aboutsummaryrefslogtreecommitdiffstats
path: root/weechat
diff options
context:
space:
mode:
Diffstat (limited to 'weechat')
-rw-r--r--weechat/alias.conf45
-rw-r--r--weechat/aspell.conf21
-rw-r--r--weechat/buffers.conf60
-rw-r--r--weechat/charset.conf11
-rw-r--r--weechat/irc.conf242
-rw-r--r--weechat/iset.conf27
-rw-r--r--weechat/logger.conf26
l---------weechat/perl/autoload/buffers.pl1
l---------weechat/perl/autoload/highmon.pl1
l---------weechat/perl/autoload/iset.pl1
l---------weechat/perl/autoload/stalker.pl1
l---------weechat/perl/autoload/yaurls.pl1
-rw-r--r--weechat/perl/buffers.pl1200
-rw-r--r--weechat/perl/highmon.pl1064
-rw-r--r--weechat/perl/iset.pl1394
-rw-r--r--weechat/perl/stalker.pl1408
-rw-r--r--weechat/perl/yaurls.pl301
-rw-r--r--weechat/python/announce_url_title.py318
-rw-r--r--weechat/python/anotify.py470
l---------weechat/python/autoload/announce_url_title.py1
l---------weechat/python/autoload/anotify.py1
l---------weechat/python/autoload/colorize_nicks.py1
l---------weechat/python/autoload/listbuffer.py1
-rw-r--r--weechat/python/colorize_nicks.py316
-rw-r--r--weechat/python/listbuffer.py467
-rw-r--r--weechat/relay.conf37
-rw-r--r--weechat/rmodifier.conf14
-rw-r--r--weechat/script.conf48
-rw-r--r--weechat/sec.conf11
-rw-r--r--weechat/theos.crt23
-rw-r--r--weechat/xfer.conf38
-rw-r--r--weechat/yaurls.conf28
32 files changed, 7578 insertions, 0 deletions
diff --git a/weechat/alias.conf b/weechat/alias.conf
new file mode 100644
index 0000000..f0673be
--- /dev/null
+++ b/weechat/alias.conf
@@ -0,0 +1,45 @@
+#
+# alias.conf -- weechat v0.4.3-dev
+#
+
+[cmd]
+AAWAY = "allserv /away"
+alot = "/input insert http://hyperboleandahalf.blogspot.com/2010/04/alot-is-better-than-you-at-everything.html"
+AME = "allchan /me"
+AMSG = "allchan /msg *"
+ANICK = "allserv /nick"
+bro = "/input insert ლ(°◡°ლ)"
+BYE = "quit"
+C = "buffer clear"
+CHAT = "dcc chat"
+CL = "buffer clear"
+CLOSE = "buffer close"
+EXIT = "quit"
+ig = "filter add ignore_$1 *.$server.* nick_$1 *"
+irc-analogy = "/input insert an IRC server is like a shopping mall. It provides space for various shops. While the mall owner (read: the server's staff) might control some of the shops (read: channels), most of them are 'owned' (registered) by individual parties (channel founders). Each of the shops (channels) usually have their own subject/topic of conversation and their own rules and guidelines. All of the shops (channels) can be reached via the main entrance (any IRC client connected to the server's address), but some of them might have their own entrance (an IRC applet/client on their own website). So, the fact that you have connected through website X about subject Y, doesn't mean all other channels belong to the same website / share the same topic of conversation."
+J = "join"
+K = "kick"
+KB = "kickban"
+konamicode = "/input insert ↑ ↑ ↓ ↓ ← → ← → B A"
+LEAVE = "part"
+lookaround = "/input insert /me looks around ('-' ) (._. ) (o_o) ( ._.) ( '-')"
+M = "msg"
+MUB = "unban *"
+N = "names"
+Q = "query"
+qt = "disconnect -all ;quit"
+REDRAW = "window refresh"
+SAY = "msg *"
+SIGNOFF = "quit"
+T = "topic"
+UB = "unban"
+UMODE = "mode $nick"
+unig = "filter del ignore_$1"
+V = "command core version"
+W = "who"
+WC = "window merge"
+WI = "whois"
+WII = "whois $1 $1"
+WW = "whowas"
+
+[completion]
diff --git a/weechat/aspell.conf b/weechat/aspell.conf
new file mode 100644
index 0000000..a07a4bc
--- /dev/null
+++ b/weechat/aspell.conf
@@ -0,0 +1,21 @@
+#
+# aspell.conf -- weechat v0.4.3-dev
+#
+
+[color]
+misspelled = lightred
+suggestions = default
+
+[check]
+commands = "ame,amsg,away,command,cycle,kick,kickban,me,msg,notice,part,query,quit,topic"
+default_dict = "en"
+during_search = off
+enabled = on
+real_time = on
+suggestions = 0
+word_min_length = 2
+
+[dict]
+core.weechat = "en"
+
+[option]
diff --git a/weechat/buffers.conf b/weechat/buffers.conf
new file mode 100644
index 0000000..0aa864d
--- /dev/null
+++ b/weechat/buffers.conf
@@ -0,0 +1,60 @@
+#
+# buffers.conf -- weechat v0.4.3-dev
+#
+
+[color]
+current_bg = blue
+current_fg = yellow
+default_bg = default
+default_fg = default
+hotlist_highlight_bg = red
+hotlist_highlight_fg = magenta
+hotlist_low_bg = default
+hotlist_low_fg = blue
+hotlist_message_bg = default
+hotlist_message_fg = lightblue
+hotlist_private_bg = red
+hotlist_private_fg = magenta
+none_channel_bg = default
+none_channel_fg = default
+number = lightgreen
+number_char = lightgreen
+queries_default_bg = default
+queries_default_fg = default
+queries_highlight_bg = red
+queries_highlight_fg = magenta
+queries_message_bg = red
+queries_message_fg = magenta
+whitelist_default_bg = default
+whitelist_default_fg = default
+whitelist_highlight_bg = red
+whitelist_highlight_fg = magenta
+whitelist_low_bg = default
+whitelist_low_fg = blue
+whitelist_message_bg = red
+whitelist_message_fg = magenta
+whitelist_private_bg = red
+whitelist_private_fg = magenta
+
+[look]
+core_to_front = on
+detach = 0
+detach_free_content = off
+detach_query = off
+hide_merged_buffers = server
+hotlist_counter = off
+immune_detach_buffers = ""
+indenting = on
+indenting_number = on
+jump_prev_next_visited_buffer = off
+mark_inactive = on
+name_crop_suffix = "×"
+name_size_max = 0
+number_char = "."
+prefix = off
+prefix_empty = on
+short_names = on
+show_lag = off
+show_number = on
+sort = number
+whitelist_buffers = ""
diff --git a/weechat/charset.conf b/weechat/charset.conf
new file mode 100644
index 0000000..bf46f99
--- /dev/null
+++ b/weechat/charset.conf
@@ -0,0 +1,11 @@
+#
+# charset.conf -- weechat v0.4.3-dev
+#
+
+[default]
+decode = "iso-8859-1"
+encode = "UTF-8"
+
+[decode]
+
+[encode]
diff --git a/weechat/irc.conf b/weechat/irc.conf
new file mode 100644
index 0000000..25f2807
--- /dev/null
+++ b/weechat/irc.conf
@@ -0,0 +1,242 @@
+#
+# irc.conf -- weechat v0.4.3-dev
+#
+
+[look]
+buffer_switch_autojoin = off
+buffer_switch_join = on
+color_nicks_in_names = on
+color_nicks_in_nicklist = on
+color_nicks_in_server_messages = on
+color_pv_nick_like_channel = on
+ctcp_time_format = "%a, %d %b %Y %T %z"
+display_away = local
+display_ctcp_blocked = on
+display_ctcp_reply = on
+display_ctcp_unknown = on
+display_host_join = on
+display_host_join_local = on
+display_host_quit = on
+display_join_message = "329,332,333"
+display_old_topic = on
+display_pv_away_once = on
+display_pv_back = on
+highlight_channel = "$nick"
+highlight_pv = "$nick"
+highlight_server = "$nick"
+highlight_tags_restrict = "irc_privmsg,irc_notice"
+item_away_message = on
+item_channel_modes_hide_key = off
+item_display_server = buffer_plugin
+item_nick_modes = on
+item_nick_prefix = on
+msgbuffer_fallback = current
+new_channel_position = none
+new_pv_position = none
+nick_color_force = ""
+nick_color_hash = djb2
+nick_color_stop_chars = "_|["
+nick_completion_smart = speakers
+nick_mode = prefix
+nick_mode_empty = off
+nicks_hide_password = "nickserv"
+notice_as_pv = auto
+notice_welcome_redirect = on
+notice_welcome_tags = ""
+notify_tags_ison = "notify_message"
+notify_tags_whois = "notify_message"
+part_closes_buffer = off
+pv_buffer = independent
+pv_tags = "notify_private"
+raw_messages = 256
+server_buffer = merge_with_core
+smart_filter = on
+smart_filter_delay = 5
+smart_filter_join = on
+smart_filter_join_unmask = 30
+smart_filter_mode = "ovh"
+smart_filter_nick = on
+smart_filter_quit = on
+topic_strip_colors = off
+
+[color]
+input_nick = lightcyan
+item_away = yellow
+item_channel_modes = default
+item_lag_counting = default
+item_lag_finished = yellow
+message_join = green
+message_quit = lightred
+mirc_remap = "1,-1:darkgray"
+nick_prefixes = "q:lightred;a:lightcyan;o:lightgreen;h:lightmagenta;v:yellow;*:lightblue"
+notice = blue
+reason_quit = default
+topic_new = white
+topic_old = darkgray
+
+[network]
+alternate_nick = on
+autoreconnect_delay_growing = 2
+autoreconnect_delay_max = 1800
+ban_mask_default = "*!$user@$host"
+colors_receive = on
+colors_send = on
+lag_check = 15
+lag_max = 1800
+lag_min_show = 0
+lag_reconnect = 0
+lag_refresh_interval = 1
+notify_check_ison = 1
+notify_check_whois = 5
+send_unknown_commands = off
+whois_double_nick = on
+
+[msgbuffer]
+
+[ctcp]
+
+[ignore]
+
+[server_default]
+addresses = "theos.kyriasis.com/6697"
+anti_flood_prio_high = 2
+anti_flood_prio_low = 2
+autoconnect = off
+autojoin = ""
+autoreconnect = on
+autoreconnect_delay = 10
+autorejoin = off
+autorejoin_delay = 30
+away_check = 0
+away_check_max_nicks = 25
+capabilities = "znc.in/server-time-iso"
+command = ""
+command_delay = 0
+connection_timeout = 60
+default_msg_kick = ""
+default_msg_part = ""
+default_msg_quit = ""
+ipv6 = on
+local_hostname = ""
+nicks = "demize,remize,dem,kyrias"
+notify = ""
+password = ""
+proxy = ""
+realname = "Johannes Löthberg"
+sasl_mechanism = plain
+sasl_password = ""
+sasl_timeout = 15
+sasl_username = ""
+ssl = on
+ssl_cert = "%h/keys/demize.pem"
+ssl_dhkey_size = 2048
+ssl_priorities = "NORMAL"
+ssl_verify = on
+username = "dem"
+
+[server]
+Freenode.addresses
+Freenode.proxy
+Freenode.ipv6
+Freenode.ssl
+Freenode.ssl_cert
+Freenode.ssl_priorities
+Freenode.ssl_dhkey_size
+Freenode.ssl_verify
+Freenode.password = "kyrias/freenode:"
+Freenode.capabilities
+Freenode.sasl_mechanism
+Freenode.sasl_username
+Freenode.sasl_password
+Freenode.sasl_timeout
+Freenode.autoconnect = on
+Freenode.autoreconnect
+Freenode.autoreconnect_delay
+Freenode.nicks
+Freenode.username
+Freenode.realname
+Freenode.local_hostname
+Freenode.command
+Freenode.command_delay
+Freenode.autojoin
+Freenode.autorejoin
+Freenode.autorejoin_delay
+Freenode.connection_timeout
+Freenode.anti_flood_prio_high
+Freenode.anti_flood_prio_low
+Freenode.away_check
+Freenode.away_check_max_nicks
+Freenode.default_msg_kick
+Freenode.default_msg_part
+Freenode.default_msg_quit
+Freenode.notify
+Furnet.addresses
+Furnet.proxy
+Furnet.ipv6
+Furnet.ssl
+Furnet.ssl_cert
+Furnet.ssl_priorities
+Furnet.ssl_dhkey_size
+Furnet.ssl_verify
+Furnet.password = "kyrias/furnet:"
+Furnet.capabilities
+Furnet.sasl_mechanism
+Furnet.sasl_username
+Furnet.sasl_password
+Furnet.sasl_timeout
+Furnet.autoconnect = on
+Furnet.autoreconnect
+Furnet.autoreconnect_delay
+Furnet.nicks
+Furnet.username
+Furnet.realname
+Furnet.local_hostname
+Furnet.command
+Furnet.command_delay
+Furnet.autojoin
+Furnet.autorejoin
+Furnet.autorejoin_delay
+Furnet.connection_timeout
+Furnet.anti_flood_prio_high
+Furnet.anti_flood_prio_low
+Furnet.away_check
+Furnet.away_check_max_nicks
+Furnet.default_msg_kick
+Furnet.default_msg_part
+Furnet.default_msg_quit
+Furnet.notify
+Foonetic.addresses
+Foonetic.proxy
+Foonetic.ipv6
+Foonetic.ssl
+Foonetic.ssl_cert
+Foonetic.ssl_priorities
+Foonetic.ssl_dhkey_size
+Foonetic.ssl_verify
+Foonetic.password = "kyrias/foonetic:"
+Foonetic.capabilities
+Foonetic.sasl_mechanism
+Foonetic.sasl_username
+Foonetic.sasl_password
+Foonetic.sasl_timeout
+Foonetic.autoconnect = on
+Foonetic.autoreconnect
+Foonetic.autoreconnect_delay
+Foonetic.nicks
+Foonetic.username
+Foonetic.realname
+Foonetic.local_hostname
+Foonetic.command
+Foonetic.command_delay
+Foonetic.autojoin
+Foonetic.autorejoin
+Foonetic.autorejoin_delay
+Foonetic.connection_timeout
+Foonetic.anti_flood_prio_high
+Foonetic.anti_flood_prio_low
+Foonetic.away_check
+Foonetic.away_check_max_nicks
+Foonetic.default_msg_kick
+Foonetic.default_msg_part
+Foonetic.default_msg_quit
+Foonetic.notify
diff --git a/weechat/iset.conf b/weechat/iset.conf
new file mode 100644
index 0000000..cf43d55
--- /dev/null
+++ b/weechat/iset.conf
@@ -0,0 +1,27 @@
+#
+# iset.conf -- weechat v0.4.3-dev
+#
+
+[color]
+bg_selected = red
+help_default_value = green
+help_option_name = white
+help_text = default
+option = default
+option_selected = white
+type = brown
+type_selected = yellow
+value = cyan
+value_selected = lightcyan
+value_undef = green
+value_undef_selected = lightgreen
+
+[help]
+show_help_bar = on
+show_help_extra_info = on
+show_plugin_description = on
+
+[look]
+scroll_horiz = 10
+show_current_line = on
+value_search_char = "="
diff --git a/weechat/logger.conf b/weechat/logger.conf
new file mode 100644
index 0000000..02a4a92
--- /dev/null
+++ b/weechat/logger.conf
@@ -0,0 +1,26 @@
+#
+# logger.conf -- weechat v0.4.3-dev
+#
+
+[look]
+backlog = 20
+
+[color]
+backlog_end = darkgray
+backlog_line = green
+
+[file]
+auto_log = on
+flush_delay = 120
+info_lines = off
+mask = "$server/$channel/%F"
+name_lower_case = on
+nick_prefix = ""
+nick_suffix = ""
+path = "%h/logs/"
+replacement_char = "_"
+time_format = "%Y-%m-%d %H:%M:%S"
+
+[level]
+
+[mask]
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 <flashcode@flashtux.org>
+# Copyright (C) 2011-2012 Nils G <weechatter@arcor.de>
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+#
+# 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 <anti.teamidiot.de>:
+# v3.7: call menu on right mouse if menu script is loaded.
+# 2012-10-06, nils_2 <weechatter@arcor.de>:
+# v3.6: add new option "hotlist_counter" (idea by torque).
+# 2012-06-02, nils_2 <weechatter@arcor.de>:
+# v3.5: add values "server|channel|private|all|keepserver|none" to option "hide_merged_buffers" (suggested by dominikh).
+# 2012-05-25, nils_2 <weechatter@arcor.de>:
+# v3.4: add new option "show_lag".
+# 2012-04-07, Sebastien Helleu <flashcode@flashtux.org>:
+# v3.3: fix truncation of wide chars in buffer name (option name_size_max) (bug #36034)
+# 2012-03-15, nils_2 <weechatter@arcor.de>:
+# 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 <flashcode@flashtux.org>:
+# v3.1: fix reload of config file
+# 2012-01-29, nils_2 <weechatter@arcor.de>:
+# v3.0: fix: buffers did not update directly during window_switch (reported by FiXato)
+# 2012-01-29, nils_2 <weechatter@arcor.de>:
+# v2.9: add options "name_size_max" and "name_crop_suffix"
+# 2012-01-08, nils_2 <weechatter@arcor.de>:
+# 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 <flashcode@flashtux.org>:
+# v2.7: fix regex lookup in whitelist buffers list
+# 2011-12-04, nils_2 <weechatter@arcor.de>:
+# 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 <weechatter@arcor.de>:
+# v2.5: add new options "show_number_char" and "color_number_char",
+# add help-description for options
+# 2011-08-24, Sebastien Helleu <flashcode@flashtux.org>:
+# v2.4: add mouse support
+# 2011-06-06, nils_2 <weechatter@arcor.de>:
+# v2.3: added: missed option "color_whitelist_default"
+# 2011-03-23, Sebastien Helleu <flashcode@flashtux.org>:
+# v2.2: fix color of nick prefix with WeeChat >= 0.3.5
+# 2011-02-13, nils_2 <weechatter@arcor.de>:
+# v2.1: add options "color_whitelist_*"
+# 2010-10-05, Sebastien Helleu <flashcode@flashtux.org>:
+# v2.0: add options "sort" and "show_number"
+# 2010-04-12, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.9: replace call to log() by length() to align buffer numbers
+# 2010-04-02, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.8: fix bug with background color and option indenting_number
+# 2010-04-02, Helios <helios@efemes.de>:
+# v1.7: add indenting_number option
+# 2010-02-25, m4v <lambdae2@gmail.com>:
+# v1.6: add option to hide empty prefixes
+# 2010-02-12, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.5: add optional nick prefix for buffers like IRC channels
+# 2009-09-30, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.4: remove spaces for indenting when bar position is top/bottom
+# 2009-06-14, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.3: add option "hide_merged_buffers"
+# 2009-06-14, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.2: improve display with merged buffers
+# 2009-05-02, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.1: sync with last API changes
+# 2009-02-21, Sebastien Helleu <flashcode@flashtux.org>:
+# v1.0: remove timer used to update bar item first time (not needed any more)
+# 2009-02-17, Sebastien Helleu <flashcode@flashtux.org>:
+# v0.9: fix bug with indenting of private buffers
+# 2009-01-04, Sebastien Helleu <flashcode@flashtux.org>:
+# v0.8: update syntax for command /set (comments)
+# 2008-10-20, Jiri Golembiovsky <golemj@gmail.com>:
+# v0.7: add indenting option
+# 2008-10-01, Sebastien Helleu <flashcode@flashtux.org>:
+# v0.6: add default color for buffers, and color for current active buffer
+# 2008-09-18, Sebastien Helleu <flashcode@flashtux.org>:
+# v0.5: fix color for "low" level entry in hotlist
+# 2008-09-18, Sebastien Helleu <flashcode@flashtux.org>:
+# v0.4: rename option "show_category" to "short_names",
+# remove option "color_slash"
+# 2008-09-15, Sebastien Helleu <flashcode@flashtux.org>:
+# v0.3: fix bug with priority in hotlist (var not defined)
+# 2008-09-02, Sebastien Helleu <flashcode@flashtux.org>:
+# 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 <flashcode@flashtux.org>:
+# 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 <flashcode\@flashtux.org>", $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 <longbow@longbowslair.co.uk>:
+# v2.3.2: -fix: Let bar output use the string set in weechat's config option
+# -add: github info
+# 2012-04-15, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.3.1: -fix: Colour tags in bar timestamp string
+# 2012-02-28, KenjiE20 <longbow@longbowslair.co.uk>:
+# 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 <romainchossart_at_gmail.com>:
+# 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 <longbow@longbowslair.co.uk>:
+# 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 <longbow@longbowslair.co.uk>:
+# v2.1.3: -fix: perl errors caused by bar line counter
+# -fix: Add command list to inbuilt help
+# 2010-09-30, KenjiE20 <longbow@longbowslair.co.uk>:
+# 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 <longbow@longbowslair.co.uk>:
+# v2.1: -feature: Add 'nchannel' option to alignment to display buffer and name
+# 2010-04-25, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.0: Release as version 2.0
+# 2010-04-24, KenjiE20 <longbow@longbowslair.co.uk>:
+# 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 <longbow@longbowslair.co.uk>:
+# 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 <longbow@longbowslair.co.uk>:
+# v1.6: -feature: colored buffer names
+# -change: version sync with chanmon
+# 2009-09-05, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.2: -fix: disable buffer highlight
+# 2009-09-02, KenjiE20 <longbow@longbowslair.co.uk>:
+# v.1.1.1 -change: Stop unsightly text block on '/help'
+# 2009-08-10, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.1: In-client help added
+# 2009-08-02, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.0: Initial Public Release
+
+# Copyright (c) 2009 by KenjiE20 <longbow@longbowslair.co.uk>
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+@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 <flashcode@flashtux.org>
+# Copyright (C) 2010-2012 Nils Görs <weechatter@arcor.de>
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+# Set WeeChat and plugins options interactively.
+#
+# History:
+#
+# 2013-04-30, arza <arza@arza.us>:
+# version 3.0: simpler title, fix refresh on unset
+# 2012-12-16, nils_2 <weechatter@arcor.de>:
+# version 2.9: fix focus window with iset buffer on mouse click
+# 2012-08-25, nils_2 <weechatter@arcor.de>:
+# version 2.8: most important key and mouse bindings for iset buffer added to title-bar (idea The-Compiler)
+# 2012-07-31, nils_2 <weechatter@arcor.de>:
+# 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 <weechatter@arcor.de>:
+# version 2.6: switch to iset buffer (if existing) when command /iset is called with arguments
+# 2012-03-17, Sebastien Helleu <flashcode@flashtux.org>:
+# version 2.5: fix check of sections when creating config file
+# 2012-03-09, Sebastien Helleu <flashcode@flashtux.org>:
+# version 2.4: fix reload of config file
+# 2012-02-02, nils_2 <weechatter@arcor.de>:
+# 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 <weechatter@arcor.de>:
+# version 2.1: use own config file (iset.conf), fix own help color (used immediately)
+# 2011-10-16, nils_2 <weechatter@arcor.de>:
+# 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 <flashcode@flashtux.org>:
+# version 1.9: add mouse support, fix iset buffer, fix errors on first load under FreeBSD
+# 2011-07-21, nils_2 <weechatter@arcor.de>:
+# 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 <weechatter@arcor.de>:
+# 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 <weechatter@arcor.de>:
+# 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 <flashcode@flashtux.org>:
+# version 1.5: use new help format for command arguments
+# 2011-02-03, nils_2 <weechatter@arcor.de>:
+# version 1.4: fixed: restore value filter after /upgrade using buffer local variable.
+# 2011-01-14, nils_2 <weechatter@arcor.de>:
+# version 1.3: added function to search for values (option value_search_char).
+# code optimization.
+# 2010-12-26, Sebastien Helleu <flashcode@flashtux.org>:
+# 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 <drubin+weechat@smartcube.co.za>:
+# version 1.1.1: fix bugs with cursor position
+# 2010-11-20, nils_2 <weechatter@arcor.de>:
+# version 1.1: cursor position set to value
+# 2010-08-03, Sebastien Helleu <flashcode@flashtux.org>:
+# version 1.0: move misplaced call to infolist_free()
+# 2010-02-02, rettub <rettub@gmx.net>:
+# version 0.9: turn all the help stuff off if option 'show_help_bar' is 'off',
+# new key binding <alt>-<v> to toggle help_bar and help stuff on/off
+# 2010-01-30, nils_2 <weechatter@arcor.de>:
+# version 0.8: fix error when option does not exist
+# 2010-01-24, Sebastien Helleu <flashcode@flashtux.org>:
+# version 0.7: display iset bar only on iset buffer
+# 2010-01-22, nils_2 <weechatter@arcor.de> 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 <flashcode@flashtux.org>:
+# version 0.5: fix bug with iset buffer after /upgrade
+# 2009-05-02, Sebastien Helleu <flashcode@flashtux.org>:
+# version 0.4: sync with last API changes
+# 2009-01-04, Sebastien Helleu <flashcode@flashtux.org>:
+# version 0.3: open iset buffer when /iset command is executed
+# 2009-01-04, Sebastien Helleu <flashcode@flashtux.org>:
+# 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 <flashcode@flashtux.org>:
+# version 0.1: first official version
+# 2008-04-19, Sebastien Helleu <flashcode@flashtux.org>:
+# script creation
+
+use strict;
+
+my $PRGNAME = "iset";
+my $VERSION = "3.0";
+my $DESCR = "Interactive Set for configuration options";
+my $AUTHOR = "Sebastien Helleu <flashcode\@flashtux.org>";
+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 <file> || s <section> || [=][=]<text>",
+ "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 <weechatter@arcor.de>
+# Copyright (c) 2013 by Stefan Wold <ratler@stderr.eu>
+# based on irssi script stalker.pl from Kaitlyn Parkhurst (SymKat) <symkat@symkat.com>
+# 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 <http://www.gnu.org/licenses/>.
+#
+# 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 <weechatter\@arcor.de>";
+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 <host> [server] [-regex] || nick <nick> [server] [-regex] || scan [<server.channel>] || 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 <http://www.gnu.org/licenses/>.
+#
+#
+# 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 <flashcode@flashtux.org>
+# 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\>(.+)\<\/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;
+}
diff --git a/weechat/python/announce_url_title.py b/weechat/python/announce_url_title.py
new file mode 100644
index 0000000..95bd796
--- /dev/null
+++ b/weechat/python/announce_url_title.py
@@ -0,0 +1,318 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2009 by xt <xt@bash.no>
+# Borrowed parts from pagetitle.py by xororand
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+#
+#
+# If someone posts an URL in a configured channel
+# this script will post back title
+
+# Explanation about ignores:
+# * plugins.var.python.announce_url_title.ignore_buffers:
+# Comma separated list of patterns for define ignores.
+# URLs from channels where its name matches any of these patterns will be ignored.
+# Wildcards '*', '?' and char groups [..] can be used.
+# An ignore exception can be added by prefixing '!' in the pattern.
+#
+# Example:
+# *ubuntu*,!#ubuntu-offtopic
+# any urls from a 'ubuntu' channel will be ignored,
+# except from #ubuntu-offtopic
+#
+# * plugins.var.python.announce_url_title.url_ignore
+# simply does partial match, so specifying 'google' will ignore every url with the word google in it
+#
+#
+# History:
+# 2012-11-15, xt
+# version 16: improve escaping
+# 2011-09-04, Deltafire
+# version 15: fix remote execution exploit due to unescaped ' character in urls;
+# small bug fix for version 14 changes
+# 2011-08-23, Deltafire
+# version 14: ignore filtered lines
+# 2011-03-11, Sebastien Helleu <flashcode@flashtux.org>
+# version 13: get python 2.x binary for hook_process (fix problem when python 3.x is default python version)
+# 2010-12-10, xt
+# version 12: add better ignores (code based on m4v inotify.py)
+# 2010-11-02, xt
+# version 11: add prefix
+# 2010-11-01, xt
+# version 10: add ignored buffers feature
+# 2010-10-29, add ignore buffers feature
+# version 0.9: WeeChat user-agent option
+# 2010-10-11, xt
+# version 0.8: support multiple concurrent url lookups
+# 2010-10-11, xt
+# version 0.7: do not trigger on notices
+# 2010-08-25, xt
+# version 0.6: notice some buffers instead of msg
+# 2009-12-08, Chaz6
+# version 0.5: only announce for specified channels
+# 2009-12-08, Chaz6 <chaz@chaz6.com>
+# version 0.4: add global option
+# 2009-12-08, xt
+# version 0.3: option for public announcing or not
+# 2009-12-07, xt <xt@bash.no>
+# version 0.2: don't renannounce same urls for a time
+# add optional prefix and suffix
+# 2009-12-02, xt
+# version 0.1: initial
+
+import weechat
+w = weechat
+import re
+import htmllib
+from time import time as now
+from fnmatch import fnmatch
+from urllib import quote
+
+SCRIPT_NAME = "announce_url_title"
+SCRIPT_AUTHOR = "xt <xt@bash.no>"
+SCRIPT_VERSION = "16"
+SCRIPT_LICENSE = "GPL3"
+SCRIPT_DESC = "Announce URL titles to channel or locally"
+
+settings = {
+ "buffers" : 'freenode.#testing,', # comma separated list of buffers
+ "buffers_notice" : 'freenode.#testing,', # comma separated list of buffers
+ 'ignore_buffers' : 'grep,', # comma separated list of buffers to be ignored by this module
+ 'title_max_length': '80',
+ 'url_ignore' : '', # comma separated list of strings in url to ignore
+ 'reannounce_wait': '5', # 5 minutes delay
+ 'prefix': '',
+ 'suffix': '',
+ 'announce_public': 'off', # print it or msg the buffer
+ 'global': 'off', # whether to enable for all buffers
+ 'user_agent': 'WeeChat/%(version)s (http://www.weechat.org)', # user-agent format string
+ 'global_prefix':'url', # Prefix for when not public announcement
+}
+
+
+octet = r'(?:2(?:[0-4]\d|5[0-5])|1\d\d|\d{1,2})'
+ipAddr = r'%s(?:\,.%s){3}' % (octet, octet)
+# Base domain regex off RFC 1034 and 1738
+label = r'[0-9a-z][-0-9a-z]*[0-9a-z]?'
+domain = r'%s(?:\.%s)*\.[a-z][-0-9a-z]*[a-z]?' % (label, label)
+urlRe = re.compile(r'(\w+://(?:%s|%s)(?::\d+)?(?:/[^\])>\s]*)?)' % (domain, ipAddr), re.I)
+
+buffer_name = ''
+
+urls = {}
+script_nick = 'url'
+def say(s, buffer=''):
+ """normal msg"""
+ weechat.prnt(buffer, '%s\t%s' %(script_nick, s))
+
+def unescape(s):
+ """Unescape HTML entities"""
+ p = htmllib.HTMLParser(None)
+ p.save_bgn()
+ p.feed(s)
+ return p.save_end()
+
+def url_print_cb(data, buffer, time, tags, displayed, highlight, prefix, message):
+ global buffer_name, urls, ignore_buffers
+
+ # Do not trigger on filtered lines and notices
+ if displayed == '0' or prefix == '--':
+ return w.WEECHAT_RC_OK
+
+ msg_buffer_name = w.buffer_get_string(buffer, "name")
+ # Skip ignored buffers
+
+ #if msg_buffer_name in w.config_get_plugin('ignore_buffers').split(','):
+ # return w.WEECHAT_RC_OK
+ if msg_buffer_name in ignore_buffers:
+ return w.WEECHAT_RC_OK
+
+ found = False
+ notice = False
+ if w.config_get_plugin('global') == 'on':
+ found = True
+ buffer_name = msg_buffer_name
+ else:
+ for active_buffer in w.config_get_plugin('buffers').split(','):
+ if active_buffer.lower() == msg_buffer_name.lower():
+ found = True
+ buffer_name = msg_buffer_name
+ break
+ for active_buffer in w.config_get_plugin('buffers_notice').split(','):
+ if active_buffer.lower() == msg_buffer_name.lower():
+ found = True
+ buffer_name = msg_buffer_name
+ break
+
+ if not found:
+ return w.WEECHAT_RC_OK
+
+ ignorelist = w.config_get_plugin('url_ignore').split(',')
+ for url in urlRe.findall(message):
+
+ url = quote(url, ":/") # Escape URL
+ ignore = False
+ for ignore_part in ignorelist:
+ if ignore_part.strip():
+ if ignore_part in url:
+ ignore = True
+ w.prnt('', '%s: Found %s in URL: %s, ignoring.' %(SCRIPT_NAME, ignore_part, url))
+ break
+
+ if ignore:
+ continue
+
+ if url in urls:
+ continue
+ else:
+ urls[url] = {}
+ url_process_launcher()
+
+ return w.WEECHAT_RC_OK
+
+def url_process_launcher():
+ ''' Iterate found urls, fetch title if hasn't been launched '''
+ global urls
+
+ user_agent = w.config_get_plugin('user_agent') % {'version': w.info_get("version", "")}
+ for url, url_d in urls.items():
+ if not url_d: # empty dict means not launched
+ url_d['launched'] = now()
+
+ # Read 8192
+ python2_bin = w.info_get("python2_bin", "") or "python"
+ cmd = python2_bin + " -c \"import urllib2; opener = urllib2.build_opener();"
+ cmd += "opener.addheaders = [('User-agent','%s')];" % user_agent
+ cmd += "print opener.open('%s').read(8192)\"" % url
+
+ url_d['stdout'] = ''
+ url_d['url_hook_process'] = w.hook_process(cmd, 30 * 1000, "url_process_cb", "")
+
+ return w.WEECHAT_RC_OK
+
+def url_process_cb(data, command, rc, stdout, stderr):
+ """ Callback parsing html for title """
+
+ global buffer_name, urls
+
+ url = command.split("'")[-2]
+ if stdout != "":
+ urls[url]['stdout'] += stdout
+ if int(rc) >= 0:
+
+ head = re.sub("[\r\n\t ]"," ", urls[url]['stdout'])
+ title = re.search('(?i)\<title\>(.*?)\</title\>', head)
+ if title:
+ title = unescape(title.group(1))
+
+ max_len = int(w.config_get_plugin('title_max_length'))
+ if len(title) > max_len:
+ title = "%s [...]" % title[0:max_len]
+
+ splits = buffer_name.split('.') #FIXME bad code
+ server = splits[0]
+ buffer = '.'.join(splits[1:])
+ output = w.config_get_plugin('prefix') + title + w.config_get_plugin('suffix')
+ announce_public = w.config_get_plugin('announce_public')
+ if announce_public == 'on':
+ found = False
+ for active_buffer in w.config_get_plugin('buffers').split(','):
+ if active_buffer.lower() == buffer_name.lower():
+ w.command('', '/msg -server %s %s %s' %(server, buffer, output))
+ found = True
+ for active_buffer in w.config_get_plugin('buffers_notice').split(','):
+ if active_buffer.lower() == buffer_name.lower():
+ w.command('', '/notice -server %s %s %s' %(server, buffer, output))
+ found = True
+ if found == False:
+ say(output,w.buffer_search('', buffer_name))
+ else:
+ say(output,w.buffer_search('', buffer_name))
+ urls[url]['stdout'] = ''
+
+ return w.WEECHAT_RC_OK
+
+def purge_cb(*args):
+ ''' Purge the url list on configured intervals '''
+
+ global urls
+
+ t_now = now()
+ for url, url_d in urls.items():
+ if (t_now - url_d['launched']) > \
+ int(w.config_get_plugin('reannounce_wait'))*60:
+ del urls[url]
+
+ return w.WEECHAT_RC_OK
+
+class Ignores(object):
+ def __init__(self, ignore_type):
+ self.ignore_type = ignore_type
+ self.ignores = []
+ self.exceptions = []
+ self._get_ignores()
+
+ def _get_ignores(self):
+ assert self.ignore_type is not None
+ ignores = weechat.config_get_plugin(self.ignore_type).split(',')
+ ignores = [ s.lower() for s in ignores if s ]
+ self.ignores = [ s for s in ignores if s[0] != '!' ]
+ self.exceptions = [ s[1:] for s in ignores if s[0] == '!' ]
+
+ def __contains__(self, s):
+ s = s.lower()
+ for p in self.ignores:
+ if fnmatch(s, p):
+ for e in self.exceptions:
+ if fnmatch(s, e):
+ return False
+ return True
+ return False
+
+def ignore_update(*args):
+ ignore_buffers._get_ignores()
+ return w.WEECHAT_RC_OK
+
+
+if __name__ == "__main__":
+ if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE,
+ SCRIPT_DESC, "", ""):
+
+ # Set default settings
+ for option, default_value in settings.iteritems():
+ if not w.config_is_set_plugin(option):
+ w.config_set_plugin(option, default_value)
+ ignore_buffers = Ignores('ignore_buffers')
+
+ w.hook_print("", "", "://", 1, "url_print_cb", "")
+ w.hook_timer(\
+ int(w.config_get_plugin('reannounce_wait')) * 1000 * 60,
+ 0,
+ 0,
+ "purge_cb",
+ '')
+ weechat.hook_config('plugins.var.python.%s.ignore_buffers' %SCRIPT_NAME, 'ignore_update', '')
+ color_chat_delimiters = weechat.color('chat_delimiters')
+ color_chat_nick = weechat.color('chat_nick')
+ color_reset = weechat.color('reset')
+ color_chat_buffer = weechat.color('chat_buffer')
+ # pretty printing
+ script_nick = '%s[%s%s%s]%s' %(color_chat_delimiters,
+ color_chat_nick,
+ w.config_get_plugin('global_prefix'),
+ color_chat_delimiters,
+ color_reset)
diff --git a/weechat/python/anotify.py b/weechat/python/anotify.py
new file mode 100644
index 0000000..19e2445
--- /dev/null
+++ b/weechat/python/anotify.py
@@ -0,0 +1,470 @@
+# -*- coding: utf-8 -*-
+#
+# anotify.py
+# Copyright (c) 2012 magnific0 <jacco.geul@gmail.com>
+#
+# based on:
+# growl.py
+# Copyright (c) 2011 Sorin Ionescu <sorin.ionescu@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
+SCRIPT_NAME = 'anotify'
+SCRIPT_AUTHOR = 'magnific0'
+SCRIPT_VERSION = '1.0.0'
+SCRIPT_LICENSE = 'MIT'
+SCRIPT_DESC = 'Sends libnotify notifications upon events.'
+
+
+# Changelog
+# 2012-09-20: v1.0.0 Forked from original and adapted for libnotify.
+
+# -----------------------------------------------------------------------------
+# Settings
+# -----------------------------------------------------------------------------
+SETTINGS = {
+ 'show_public_message': 'off',
+ 'show_private_message': 'on',
+ 'show_public_action_message': 'off',
+ 'show_private_action_message': 'on',
+ 'show_notice_message': 'off',
+ 'show_invite_message': 'on',
+ 'show_highlighted_message': 'on',
+ 'show_server': 'on',
+ 'show_channel_topic': 'on',
+ 'show_dcc': 'on',
+ 'show_upgrade_ended': 'on',
+ 'sticky': 'off',
+ 'sticky_away': 'on',
+ 'icon': '/usr/share/pixmaps/weechat.xpm',
+}
+
+
+# -----------------------------------------------------------------------------
+# Imports
+# -----------------------------------------------------------------------------
+try:
+ import re
+ import os
+ import weechat
+ import pynotify
+ IMPORT_OK = True
+except ImportError as error:
+ IMPORT_OK = False
+ if str(error).find('weechat') != -1:
+ print('This script must be run under WeeChat.')
+ print('Get WeeChat at http://www.weechat.org.')
+ else:
+ weechat.prnt('', 'anotify: {0}'.format(error))
+
+# -----------------------------------------------------------------------------
+# Globals
+# -----------------------------------------------------------------------------
+TAGGED_MESSAGES = {
+ 'public message or action': set(['irc_privmsg', 'notify_message']),
+ 'private message or action': set(['irc_privmsg', 'notify_private']),
+ 'notice message': set(['irc_notice', 'notify_private']),
+ 'invite message': set(['irc_invite', 'notify_highlight']),
+ 'channel topic': set(['irc_topic', ]),
+ #'away status': set(['away_info', ]),
+}
+
+
+UNTAGGED_MESSAGES = {
+ 'away status':
+ re.compile(r'^You ((\w+).){2,3}marked as being away', re.UNICODE),
+ 'dcc chat request':
+ re.compile(r'^xfer: incoming chat request from (\w+)', re.UNICODE),
+ 'dcc chat closed':
+ re.compile(r'^xfer: chat closed with (\w+)', re.UNICODE),
+ 'dcc get request':
+ re.compile(
+ r'^xfer: incoming file from (\w+) [^:]+: ((?:,\w|[^,])+),',
+ re.UNICODE),
+ 'dcc get completed':
+ re.compile(r'^xfer: file ([^\s]+) received from \w+: OK', re.UNICODE),
+ 'dcc get failed':
+ re.compile(
+ r'^xfer: file ([^\s]+) received from \w+: FAILED',
+ re.UNICODE),
+ 'dcc send completed':
+ re.compile(r'^xfer: file ([^\s]+) sent to \w+: OK', re.UNICODE),
+ 'dcc send failed':
+ re.compile(r'^xfer: file ([^\s]+) sent to \w+: FAILED', re.UNICODE),
+}
+
+
+DISPATCH_TABLE = {
+ 'away status': 'set_away_status',
+ 'public message or action': 'notify_public_message_or_action',
+ 'private message or action': 'notify_private_message_or_action',
+ 'notice message': 'notify_notice_message',
+ 'invite message': 'notify_invite_message',
+ 'channel topic': 'notify_channel_topic',
+ 'dcc chat request': 'notify_dcc_chat_request',
+ 'dcc chat closed': 'notify_dcc_chat_closed',
+ 'dcc get request': 'notify_dcc_get_request',
+ 'dcc get completed': 'notify_dcc_get_completed',
+ 'dcc get failed': 'notify_dcc_get_failed',
+ 'dcc send completed': 'notify_dcc_send_completed',
+ 'dcc send failed': 'notify_dcc_send_failed',
+}
+
+
+STATE = {
+ 'icon': None,
+ 'is_away': False
+}
+
+
+# -----------------------------------------------------------------------------
+# Notifiers
+# -----------------------------------------------------------------------------
+def cb_irc_server_connected(data, signal, signal_data):
+ '''Notify when connected to IRC server.'''
+ if weechat.config_get_plugin('show_server') == 'on':
+ a_notify(
+ 'Server',
+ 'Server Connected',
+ 'Connected to network {0}.'.format(signal_data))
+ return weechat.WEECHAT_RC_OK
+
+
+def cb_irc_server_disconnected(data, signal, signal_data):
+ '''Notify when disconnected to IRC server.'''
+ if weechat.config_get_plugin('show_server') == 'on':
+ a_notify(
+ 'Server',
+ 'Server Disconnected',
+ 'Disconnected from network {0}.'.format(signal_data))
+ return weechat.WEECHAT_RC_OK
+
+
+def cb_notify_upgrade_ended(data, signal, signal_data):
+ '''Notify on end of WeeChat upgrade.'''
+ if weechat.config_get_plugin('show_upgrade_ended') == 'on':
+ a_notify(
+ 'WeeChat',
+ 'WeeChat Upgraded',
+ 'WeeChat has been upgraded.')
+ return weechat.WEECHAT_RC_OK
+
+
+def notify_highlighted_message(prefix, message):
+ '''Notify on highlighted message.'''
+ if weechat.config_get_plugin("show_highlighted_message") == "on":
+ a_notify(
+ 'Highlight',
+ 'Highlighted Message',
+ "{0}: {1}".format(prefix, message),
+ priority=pynotify.URGENCY_CRITICAL)
+
+
+def notify_public_message_or_action(prefix, message, highlighted):
+ '''Notify on public message or action.'''
+ if prefix == ' *':
+ regex = re.compile(r'^(\w+) (.+)$', re.UNICODE)
+ match = regex.match(message)
+ if match:
+ prefix = match.group(1)
+ message = match.group(2)
+ notify_public_action_message(prefix, message, highlighted)
+ else:
+ if highlighted:
+ notify_highlighted_message(prefix, message)
+ elif weechat.config_get_plugin("show_public_message") == "on":
+ a_notify(
+ 'Public',
+ 'Public Message',
+ '{0}: {1}'.format(prefix, message))
+
+
+def notify_private_message_or_action(prefix, message, highlighted):
+ '''Notify on private message or action.'''
+ regex = re.compile(r'^CTCP_MESSAGE.+?ACTION (.+)$', re.UNICODE)
+ match = regex.match(message)
+ if match:
+ notify_private_action_message(prefix, match.group(1), highlighted)
+ else:
+ if prefix == ' *':
+ regex = re.compile(r'^(\w+) (.+)$', re.UNICODE)
+ match = regex.match(message)
+ if match:
+ prefix = match.group(1)
+ message = match.group(2)
+ notify_private_action_message(prefix, message, highlighted)
+ else:
+ if highlighted:
+ notify_highlighted_message(prefix, message)
+ elif weechat.config_get_plugin("show_private_message") == "on":
+ a_notify(
+ 'Private',
+ 'Private Message',
+ '{0}: {1}'.format(prefix, message))
+
+
+def notify_public_action_message(prefix, message, highlighted):
+ '''Notify on public action message.'''
+ if highlighted:
+ notify_highlighted_message(prefix, message)
+ elif weechat.config_get_plugin("show_public_action_message") == "on":
+ a_notify(
+ 'Action',
+ 'Public Action Message',
+ '{0}: {1}'.format(prefix, message),
+ priority=pynotify.URGENCY_NORMAL)
+
+
+def notify_private_action_message(prefix, message, highlighted):
+ '''Notify on private action message.'''
+ if highlighted:
+ notify_highlighted_message(prefix, message)
+ elif weechat.config_get_plugin("show_private_action_message") == "on":
+ a_notify(
+ 'Action',
+ 'Private Action Message',
+ '{0}: {1}'.format(prefix, message),
+ priority=pynotify.URGENCY_NORMAL)
+
+
+def notify_notice_message(prefix, message, highlighted):
+ '''Notify on notice message.'''
+ regex = re.compile(r'^([^\s]*) [^:]*: (.+)$', re.UNICODE)
+ match = regex.match(message)
+ if match:
+ prefix = match.group(1)
+ message = match.group(2)
+ if highlighted:
+ notify_highlighted_message(prefix, message)
+ elif weechat.config_get_plugin("show_notice_message") == "on":
+ a_notify(
+ 'Notice',
+ 'Notice Message',
+ '{0}: {1}'.format(prefix, message))
+
+
+def notify_invite_message(prefix, message, highlighted):
+ '''Notify on channel invitation message.'''
+ if weechat.config_get_plugin("show_invite_message") == "on":
+ regex = re.compile(
+ r'^You have been invited to ([^\s]+) by ([^\s]+)$', re.UNICODE)
+ match = regex.match(message)
+ if match:
+ channel = match.group(1)
+ nick = match.group(2)
+ a_notify(
+ 'Invite',
+ 'Channel Invitation',
+ '{0} has invited you to join {1}.'.format(nick, channel))
+
+
+def notify_channel_topic(prefix, message, highlighted):
+ '''Notify on channel topic change.'''
+ if weechat.config_get_plugin("show_channel_topic") == "on":
+ regex = re.compile(
+ r'^\w+ has (?:changed|unset) topic for ([^\s]+)' +
+ '(?:(?: from "(?:(?:"\w|[^"])+)")? to "((?:"\w|[^"])+)")?',
+ re.UNICODE)
+ match = regex.match(message)
+ if match:
+ channel = match.group(1)
+ topic = match.group(2) or ''
+ a_notify(
+ 'Channel',
+ 'Channel Topic',
+ "{0}: {1}".format(channel, topic))
+
+
+def notify_dcc_chat_request(match):
+ '''Notify on DCC chat request.'''
+ if weechat.config_get_plugin("show_dcc") == "on":
+ nick = match.group(1)
+ a_notify(
+ 'DCC',
+ 'Direct Chat Request',
+ '{0} wants to chat directly.'.format(nick))
+
+
+def notify_dcc_chat_closed(match):
+ '''Notify on DCC chat termination.'''
+ if weechat.config_get_plugin("show_dcc") == "on":
+ nick = match.group(1)
+ a_notify(
+ 'DCC',
+ 'Direct Chat Ended',
+ 'Direct chat with {0} has ended.'.format(nick))
+
+
+def notify_dcc_get_request(match):
+ 'Notify on DCC get request.'
+ if weechat.config_get_plugin("show_dcc") == "on":
+ nick = match.group(1)
+ file_name = match.group(2)
+ a_notify(
+ 'DCC',
+ 'File Transfer Request',
+ '{0} wants to send you {1}.'.format(nick, file_name))
+
+
+def notify_dcc_get_completed(match):
+ 'Notify on DCC get completion.'
+ if weechat.config_get_plugin("show_dcc") == "on":
+ file_name = match.group(1)
+ a_notify('DCC', 'Download Complete', file_name)
+
+
+def notify_dcc_get_failed(match):
+ 'Notify on DCC get failure.'
+ if weechat.config_get_plugin("show_dcc") == "on":
+ file_name = match.group(1)
+ a_notify('DCC', 'Download Failed', file_name)
+
+
+def notify_dcc_send_completed(match):
+ 'Notify on DCC send completion.'
+ if weechat.config_get_plugin("show_dcc") == "on":
+ file_name = match.group(1)
+ a_notify('DCC', 'Upload Complete', file_name)
+
+
+def notify_dcc_send_failed(match):
+ 'Notify on DCC send failure.'
+ if weechat.config_get_plugin("show_dcc") == "on":
+ file_name = match.group(1)
+ a_notify('DCC', 'Upload Failed', file_name)
+
+
+# -----------------------------------------------------------------------------
+# Utility
+# -----------------------------------------------------------------------------
+def set_away_status(match):
+ status = match.group(1)
+ if status == 'been ':
+ STATE['is_away'] = True
+ if status == 'longer ':
+ STATE['is_away'] = False
+
+
+def cb_process_message(
+ data,
+ wbuffer,
+ date,
+ tags,
+ displayed,
+ highlight,
+ prefix,
+ message
+):
+ '''Delegates incoming messages to appropriate handlers.'''
+ tags = set(tags.split(','))
+ functions = globals()
+ is_public_message = tags.issuperset(
+ TAGGED_MESSAGES['public message or action'])
+ buffer_name = weechat.buffer_get_string(wbuffer, 'name')
+ dcc_buffer_regex = re.compile(r'^irc_dcc\.', re.UNICODE)
+ dcc_buffer_match = dcc_buffer_regex.match(buffer_name)
+ highlighted = False
+ if highlight == "1":
+ highlighted = True
+ # Private DCC message identifies itself as public.
+ if is_public_message and dcc_buffer_match:
+ notify_private_message_or_action(prefix, message, highlighted)
+ return weechat.WEECHAT_RC_OK
+ # Pass identified, untagged message to its designated function.
+ for key, value in UNTAGGED_MESSAGES.items():
+ match = value.match(message)
+ if match:
+ functions[DISPATCH_TABLE[key]](match)
+ return weechat.WEECHAT_RC_OK
+ # Pass identified, tagged message to its designated function.
+ for key, value in TAGGED_MESSAGES.items():
+ if tags.issuperset(value):
+ functions[DISPATCH_TABLE[key]](prefix, message, highlighted)
+ return weechat.WEECHAT_RC_OK
+ return weechat.WEECHAT_RC_OK
+
+
+def a_notify(notification, title, description, priority=pynotify.URGENCY_LOW):
+ '''Returns whether notifications should be sticky.'''
+ is_away = STATE['is_away']
+ icon = STATE['icon']
+ time_out = 5000
+ if weechat.config_get_plugin('sticky') == 'on':
+ time_out = 0
+ if weechat.config_get_plugin('sticky_away') == 'on' and is_away:
+ time_out = 0
+ try:
+ pynotify.init("wee-notifier")
+ wn = pynotify.Notification(title, description, icon)
+ wn.set_urgency(priority)
+ wn.set_timeout(time_out)
+ wn.show()
+ except Exception as error:
+ weechat.prnt('', 'anotify: {0}'.format(error))
+
+
+# -----------------------------------------------------------------------------
+# Main
+# -----------------------------------------------------------------------------
+def main():
+ '''Sets up WeeChat notifications.'''
+ # Initialize options.
+ for option, value in SETTINGS.items():
+ if not weechat.config_is_set_plugin(option):
+ weechat.config_set_plugin(option, value)
+ # Initialize.
+ name = "WeeChat"
+ icon = "/usr/share/pixmaps/weechat.xpm"
+ notifications = [
+ 'Public',
+ 'Private',
+ 'Action',
+ 'Notice',
+ 'Invite',
+ 'Highlight',
+ 'Server',
+ 'Channel',
+ 'DCC',
+ 'WeeChat'
+ ]
+ STATE['icon'] = icon
+ # Register hooks.
+ weechat.hook_signal(
+ 'irc_server_connected',
+ 'cb_irc_server_connected',
+ '')
+ weechat.hook_signal(
+ 'irc_server_disconnected',
+ 'cb_irc_server_disconnected',
+ '')
+ weechat.hook_signal('upgrade_ended', 'cb_upgrade_ended', '')
+ weechat.hook_print('', '', '', 1, 'cb_process_message', '')
+
+
+if __name__ == '__main__' and IMPORT_OK and weechat.register(
+ SCRIPT_NAME,
+ SCRIPT_AUTHOR,
+ SCRIPT_VERSION,
+ SCRIPT_LICENSE,
+ SCRIPT_DESC,
+ '',
+ ''
+):
+ main()
diff --git a/weechat/python/autoload/announce_url_title.py b/weechat/python/autoload/announce_url_title.py
new file mode 120000
index 0000000..5417bfe
--- /dev/null
+++ b/weechat/python/autoload/announce_url_title.py
@@ -0,0 +1 @@
+../announce_url_title.py \ No newline at end of file
diff --git a/weechat/python/autoload/anotify.py b/weechat/python/autoload/anotify.py
new file mode 120000
index 0000000..1517fef
--- /dev/null
+++ b/weechat/python/autoload/anotify.py
@@ -0,0 +1 @@
+../anotify.py \ No newline at end of file
diff --git a/weechat/python/autoload/colorize_nicks.py b/weechat/python/autoload/colorize_nicks.py
new file mode 120000
index 0000000..3ee34e9
--- /dev/null
+++ b/weechat/python/autoload/colorize_nicks.py
@@ -0,0 +1 @@
+../colorize_nicks.py \ No newline at end of file
diff --git a/weechat/python/autoload/listbuffer.py b/weechat/python/autoload/listbuffer.py
new file mode 120000
index 0000000..e7089b2
--- /dev/null
+++ b/weechat/python/autoload/listbuffer.py
@@ -0,0 +1 @@
+../listbuffer.py \ No newline at end of file
diff --git a/weechat/python/colorize_nicks.py b/weechat/python/colorize_nicks.py
new file mode 100644
index 0000000..d3730da
--- /dev/null
+++ b/weechat/python/colorize_nicks.py
@@ -0,0 +1,316 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2010 by xt <xt@bash.no>
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+
+# This script colors nicks in IRC channels in the actual message
+# not just in the prefix section.
+#
+#
+# History:
+# 2013-01-29, nils_2
+# version 14: make script compatible with Python 3.x
+# 2012-10-19, ldvx
+# version 13: Iterate over every word to prevent incorrect colorization of
+# nicks. Added option greedy_matching.
+# 2012-04-28, ldvx
+# version 12: added ignore_tags to avoid colorizing nicks if tags are present
+# 2012-01-14, nesthib
+# version 11: input_text_display hook and modifier to colorize nicks in input bar
+# 2010-12-22, xt
+# version 10: hook config option for updating blacklist
+# 2010-12-20, xt
+# version 0.9: hook new config option for weechat 0.3.4
+# 2010-11-01, nils_2
+# version 0.8: hook_modifier() added to communicate with rainbow_text
+# 2010-10-01, xt
+# version 0.7: changes to support non-irc-plugins
+# 2010-07-29, xt
+# version 0.6: compile regexp as per patch from Chris quigybo@hotmail.com
+# 2010-07-19, xt
+# version 0.5: fix bug with incorrect coloring of own nick
+# 2010-06-02, xt
+# version 0.4: update to reflect API changes
+# 2010-03-26, xt
+# version 0.3: fix error with exception
+# 2010-03-24, xt
+# version 0.2: use ignore_channels when populating to increase performance.
+# 2010-02-03, xt
+# version 0.1: initial (based on ruby script by dominikh)
+#
+# Known issues: nicks will not get colorized if they begin with a character
+# such as ~ (which some irc networks do happen to accept)
+
+import weechat
+import re
+w = weechat
+
+SCRIPT_NAME = "colorize_nicks"
+SCRIPT_AUTHOR = "xt <xt@bash.no>"
+SCRIPT_VERSION = "14"
+SCRIPT_LICENSE = "GPL"
+SCRIPT_DESC = "Use the weechat nick colors in the chat area"
+
+settings = {
+ "blacklist_channels" : '', # comma separated list of channels (use short_name)
+ "blacklist_nicks" : 'so,root', # comma separated list of nicks
+ "min_nick_length" : '2', # length
+ "colorize_input" : 'off', # boolean
+ "ignore_tags" : '', # comma separated list of tags to ignore. I.e. irc_join,irc_part,irc_quit
+ "greedy_matching" : 'on', # if off, then let's use lazy matching instead
+}
+
+
+VALID_NICK = r'([@~&!%+])?([-a-zA-Z0-9\[\]\\`_^\{|\}]+)'
+valid_nick_re = re.compile(VALID_NICK)
+PREFIX_COLORS = {
+ '@' : 'nicklist_prefix1',
+ '~' : 'nicklist_prefix1',
+ '&' : 'nicklist_prefix1',
+ '!' : 'nicklist_prefix1',
+ '%' : 'nicklist_prefix2',
+ '+' : 'nicklist_prefix3',
+}
+ignore_channels = []
+ignore_nicks = []
+
+# Dict with every nick on every channel with its color as lookup value
+colored_nicks = {}
+
+def colorize_cb(data, modifier, modifier_data, line):
+ ''' Callback that does the colorizing, and returns new line if changed '''
+
+ global ignore_nicks, ignore_channels, colored_nicks
+
+ full_name = modifier_data.split(';')[1]
+ server = full_name.split('.')[0]
+ channel = '.'.join(full_name.split('.')[1:])
+
+ buffer = w.buffer_search('', full_name)
+ # Check if buffer has colorized nicks
+ if not buffer in colored_nicks:
+ return line
+
+ if channel in ignore_channels:
+ return line
+
+ try:
+ min_length = int(w.config_get_plugin('min_nick_length'))
+ except ValueError:
+ w.prnt('', '%sError with option min_nick_length, should be a integer' % weechat.prefix('error'))
+ w.config_set_plugin('min_nick_length', settings['min_nick_length'])
+
+ reset = w.color('reset')
+
+ # Don't colorize if the ignored tag is present in message
+ tags_line = modifier_data.rsplit(';')
+ if len(tags_line) >= 3:
+ tags_line = tags_line[2].split(',')
+ for i in w.config_get_plugin('ignore_tags').split(','):
+ if i in tags_line:
+ return line
+
+ for words in valid_nick_re.findall(line):
+ prefix, nick = words[0], words[1]
+ # Check that nick is not ignored and longer than minimum length
+ if len(nick) < min_length or nick in ignore_nicks:
+ continue
+ # Check that nick is in the dictionary colored_nicks
+ if nick in colored_nicks[buffer]:
+ nick_color = colored_nicks[buffer][nick]
+
+ # Let's use greedy matching. Will check against every word in a line.
+ if w.config_get_plugin('greedy_matching') == "on":
+ for word in line.split():
+ if nick in word:
+ # Is there a nick that contains nick and has a greater lenght?
+ # If so let's save that nick into var biggest_nick
+ biggest_nick = ""
+ for i in colored_nicks[buffer]:
+ if nick in i and nick != i and len(i) > len(nick):
+ if i in word:
+ # If a nick with greater len is found, and that word
+ # also happens to be in word, then let's save this nick
+ biggest_nick = i
+ # If there's a nick with greater len, then let's skip this
+ # As we will have the chance to colorize when biggest_nick
+ # iterates being nick.
+ if len(biggest_nick) > 0 and biggest_nick in word:
+ pass
+ elif len(word) < len(biggest_nick) or len(biggest_nick) == 0:
+ new_word = word.replace(nick, '%s%s%s' %(nick_color, nick, reset))
+ line = line.replace(word, new_word)
+ # Let's use lazy matching for nick
+ elif w.config_get_plugin('greedy_matching') == "off":
+ if nick in colored_nicks[buffer]:
+ nick_color = colored_nicks[buffer][nick]
+ # The two .? are in case somebody writes "nick:", "nick,", etc
+ # to address somebody
+ regex = r"(\A|\s).?(%s).?(\Z|\s)" % re.escape(nick)
+ match = re.search(regex, line)
+ if str(type(match)) == "<type '_sre.SRE_Match'>":
+ new_line = line[:match.start(2)] + nick_color+nick+reset + line[match.end(2):]
+ line = new_line
+ return line
+
+def colorize_input_cb(data, modifier, modifier_data, line):
+ ''' Callback that does the colorizing in input '''
+
+ global ignore_nicks, ignore_channels, colored_nicks
+
+ try:
+ min_length = int(w.config_get_plugin('min_nick_length'))
+ except ValueError:
+ w.prnt('', '%sError with option min_nick_length, should be a integer' % weechat.prefix('error'))
+ w.config_set_plugin('min_nick_length', settings['min_nick_length'])
+
+ if w.config_get_plugin('colorize_input') == 'on':
+ pass
+ elif w.config_get_plugin('colorize_input') == 'off':
+ return line
+ else:
+ w.prnt('', '%sError with option colorize_input, should be on or off' % weechat.prefix('error'))
+ w.config_set_plugin('colorize_input', settings['colorize_input'])
+ return line
+
+ buffer = w.current_buffer()
+ # Check if buffer has colorized nicks
+ if not buffer in colored_nicks:
+ return line
+
+ channel = w.buffer_get_string(buffer,'name')
+ if channel in ignore_channels:
+ return line
+
+ reset = w.color('reset')
+
+ for words in valid_nick_re.findall(line):
+ prefix, nick = words[0], words[1]
+ # Check that nick is not ignored and longer than minimum length
+ if len(nick) < min_length or nick in ignore_nicks:
+ continue
+ if nick in colored_nicks[buffer]:
+ nick_color = colored_nicks[buffer][nick]
+ line = line.replace(nick, '%s%s%s' %(nick_color, nick, reset))
+
+ return line
+
+def populate_nicks(*args):
+ ''' Fills entire dict with all nicks weechat can see and what color it has
+ assigned to it. '''
+ global colored_nicks
+
+ colored_nicks = {}
+
+ servers = w.infolist_get('irc_server', '', '')
+ while w.infolist_next(servers):
+ servername = w.infolist_string(servers, 'name')
+ colored_nicks[servername] = {}
+ my_nick = w.info_get('irc_nick', servername)
+ channels = w.infolist_get('irc_channel', '', servername)
+ while w.infolist_next(channels):
+ pointer = w.infolist_pointer(channels, 'buffer')
+ nicklist = w.infolist_get('nicklist', pointer, '')
+ channelname = w.infolist_string(channels, 'name')
+
+ if not pointer in colored_nicks:
+ colored_nicks[pointer] = {}
+
+ while w.infolist_next(nicklist):
+ nick = w.infolist_string(nicklist, 'name')
+ if nick == my_nick:
+ nick_color = w.color(\
+ w.config_string(\
+ w.config_get('weechat.color.chat_nick_self')))
+ else:
+ nick_color = w.info_get('irc_nick_color', nick)
+
+ colored_nicks[pointer][nick] = nick_color
+
+ w.infolist_free(nicklist)
+
+ w.infolist_free(channels)
+
+ w.infolist_free(servers)
+
+ return w.WEECHAT_RC_OK
+
+def add_nick(data, signal, type_data):
+ ''' Add nick to dict of colored nicks '''
+ global colored_nicks
+
+ pointer, nick = type_data.split(',')
+ if not pointer in colored_nicks:
+ colored_nicks[pointer] = {}
+
+ servername = w.buffer_get_string(pointer, 'localvar_server')
+ my_nick = w.buffer_get_string(pointer, 'localvar_nick')
+
+ if nick == my_nick:
+ nick_color = w.color(\
+ w.config_string(\
+ w.config_get('weechat.color.chat_nick_self')))
+ else:
+ nick_color = w.info_get('irc_nick_color', nick)
+
+ colored_nicks[pointer][nick] = nick_color
+
+ return w.WEECHAT_RC_OK
+
+def remove_nick(data, signal, type_data):
+ ''' Remove nick from dict with colored nicks '''
+ global colored_nicks
+
+ pointer, nick = type_data.split(',')
+
+ if pointer in colored_nicks and nick in colored_nicks[pointer]:
+ del colored_nicks[pointer][nick]
+
+ return w.WEECHAT_RC_OK
+
+def update_blacklist(*args):
+ global ignore_channels, ignore_nicks
+ if w.config_get_plugin('blacklist_channels'):
+ ignore_channels = w.config_get_plugin('blacklist_channels').split(',')
+ ignore_nicks = w.config_get_plugin('blacklist_nicks').split(',')
+ return w.WEECHAT_RC_OK
+
+if __name__ == "__main__":
+ if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE,
+ SCRIPT_DESC, "", ""):
+ # Set default settings
+# for option, default_value in settings.iteritems():
+ for option, default_value in list(settings.items()):
+ if not w.config_is_set_plugin(option):
+ w.config_set_plugin(option, default_value)
+
+ for key, value in list(PREFIX_COLORS.items()):
+# for key, value in PREFIX_COLORS.iteritems():
+ PREFIX_COLORS[key] = w.color(w.config_string(w.config_get('weechat.look.%s'%value)))
+
+ update_blacklist() # Set blacklist
+ populate_nicks() # Run it once to get data ready
+ w.hook_signal('nicklist_nick_added', 'add_nick', '')
+ w.hook_signal('nicklist_nick_removed', 'remove_nick', '')
+ w.hook_modifier('weechat_print', 'colorize_cb', '')
+ # Hook config for changing colors
+ w.hook_config('weechat.color.chat_nick_colors', 'populate_nicks', '')
+ # Hook for working togheter with other scripts (like colorize_lines)
+ w.hook_modifier('colorize_nicks', 'colorize_cb', '')
+ # Hook for modifying input
+ w.hook_modifier('250|input_text_display', 'colorize_input_cb', '')
+ # Hook for updating blacklist (this could be improved to use fnmatch)
+ weechat.hook_config('plugins.var.python.%s.blacklist*' %SCRIPT_NAME, 'update_blacklist', '')
diff --git a/weechat/python/listbuffer.py b/weechat/python/listbuffer.py
new file mode 100644
index 0000000..227a3ba
--- /dev/null
+++ b/weechat/python/listbuffer.py
@@ -0,0 +1,467 @@
+# -*- coding: utf-8 -*-
+#
+# ListBuffer, version 0.8.1 for WeeChat version 0.3
+# Latest development version: https://github.com/FiXato/listbuffer
+#
+# Show /list results in a common buffer and interact with them.
+#
+# This script allows you to easily join channels from the /list output.
+# It will open a common buffer for the /list result, through which you
+# browse with your cursor keys, and join with the meta-enter keys.
+# Adjust sorting with meta->, meta-< and meta-/ keybindings.
+#
+## History:
+### 2011-09-08: FiXato:
+#
+# * version 0.1: initial release.
+# * added a common buffer for /list results
+# * added highlighting for currently selected line
+# * added /join support via enter key
+# * added scroll_top and scroll_bottom support
+#
+# * version 0.2: /list format bugfix
+# * added support for /list results without modes
+# * some servers don't send 321 (/list start). Taken into account.
+#
+# * version 0.3: Sorting support
+# * Added some basic sorting support. Scroll through sort options
+# with meta-> and meta-< (users, channel, topic, modes)
+#
+### 2011-09-19: FiXato
+#
+# * version 0.4:
+# * Case-insensitive buffer lookup fix.
+# * Removed default enter keybind
+#
+### 2011-12-28: troydm:
+#
+# * version 0.5: It's an upside-down-world
+# * Added inverted sorting support provided by Dmitry "troydm" Geurkov
+# Use meta-/ to switch between inverted and regular sorting.
+#
+### 2012-02-10: FiXato:
+#
+# * version 0.6: Stop shoving that buffer in my face!
+# * The listbuffer should no longer pop up by itself when you load the script.
+# It should only pop up now when you actually do a /list query.
+#
+# * version 0.7: .. but please pop it up in my current window when I ask for it
+# * Added setting plugins.var.python.listbuffer.autofocus
+# This will autofocus the listbuffer in the current window if another window isn't
+# already showing it, and of course only when the user issues /list
+#
+### 2012-07-10: FiXato:
+#
+# * version 0.7.1: Forgetful bugfix
+# * Made sure lb_curline global variable is defined
+#
+### 2013-03-19: FiXato:
+#
+# * version 0.8: Sorted out the sorting
+# * Added automatically updating options for sorting:
+# * plugins.var.python.listbuffer.sort_inverted
+# * plugins.var.python.listbuffer.sort_order
+# * version 0.8.1: Pad it baby!
+# * Channel modes are equally padded even when there are no channel modes.
+# * Added padding options:
+# * plugins.var.python.listbuffer.modes_min_width
+# * plugins.var.python.listbuffer.channel_min_width
+# * plugins.var.python.listbuffer.users_min_width
+#
+## Acknowledgements:
+# * Dmitry "troydm" Geurkov, for providing the inverse-sorting patch to the project.
+# * Sebastien "Flashcode" Helleu, for developing the kick-ass IRC client WeeChat
+# and the iset.pl script which inspired me to this script.
+# * Nils "nils_2" Görs, for his contributions to iset.pl which served as
+# example code.
+# * David "drubin" Rubin, for his urlgrab.py script, which also served
+# as example code.
+# * ArZa, whose listsort.pl script helped me getting started with
+# grabbing the /list results. Parts of his code have been shamelessly
+# copied and ported to Python.
+# * Khaled Mardam-Bey, for making me yearn for similar /list support in
+# WeeChat as mIRC already offered. :P
+# * mave_, for pointing out that sort orders weren't remembered.
+#
+## TODO:
+# - Auto-scroll selected line upon window scroll.
+# - Add option to hide already joined channels.
+# - Improve sorting methods
+# - Add auto-join support
+# - Detect if channel is already in auto-join
+# - Allow automatically switching to the listbuffer
+# - Add support for ALIS (/squery alis LIST * -mix 100 (IRCNet)
+# - Make colours configurable
+# - Limit number of channels to parse
+# - Add filter support a la iset
+# - Allow selecting multiple channels
+# - Add optional command redirection.
+#
+## Copyright (c) 2011,2012,2013 Filip H.F. "FiXato" Slagter,
+# <FiXato [at] Gmail [dot] com>
+# http://profile.fixato.org
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+SCRIPT_NAME = "listbuffer"
+SCRIPT_AUTHOR = "Filip H.F. 'FiXato' Slagter <fixato [at] gmail [dot] com>"
+SCRIPT_VERSION = "0.8.1"
+SCRIPT_LICENSE = "MIT"
+SCRIPT_DESC = "A common buffer for /list output."
+SCRIPT_COMMAND = "listbuffer"
+
+import_ok = True
+
+try:
+ import weechat
+except ImportError:
+ print "This script must be run under WeeChat."
+ import_ok = False
+
+import re
+
+lb_settings = (
+ ("autofocus", "on", "Focus the listbuffer in the current window if it isn't already displayed by a window."),
+ ("sort_order", "users", "Last used sort order for the channel list."),
+ ("sort_inverted", "on", "Invert the sort order for the channel list."),
+ ("modes_min_width", "8", "The minimum width used for modes in the channel list. If a channel has less modes than this amount, the column will be padded with spaces."),
+ ("channel_min_width", "25", "The minimum width used for the channel name in the channel list. If a channelname is shorter than this amount, the column will be padded with spaces."),
+ ("users_min_width", "8", "The minimum width used for the usercount in the channel list. If the usercount has less digits than this amount, the column will be padded with spaces."),
+)
+lb_buffer = None
+lb_curline = 0
+lb_channels = []
+lb_network = None
+lb_list_started = False
+lb_current_sort = None
+lb_sort_inverted = False
+lb_sort_options = (
+ 'channel',
+ 'users',
+ 'modes',
+ 'topic',
+)
+
+# server numeric Nick Chan Users Modes Topic
+lb_channel_list_expression = '(:\S+) (\d{3}) (\S+) (\S+) (\d+) :(\[(.*?)\] )?(.*)'
+
+# Create listbuffer.
+def lb_create_buffer():
+ global lb_buffer, lb_curline
+
+ if not lb_buffer:
+ lb_buffer = weechat.buffer_new("listbuffer", "lb_input_cb", \
+ "", "lb_close_cb", "")
+ lb_set_buffer_title()
+ # Sets notify to 0 as this buffer does not need to be in hotlist.
+ weechat.buffer_set(lb_buffer, "notify", "0")
+ weechat.buffer_set(lb_buffer, "nicklist", "0")
+ weechat.buffer_set(lb_buffer, "type", "free")
+ weechat.buffer_set(lb_buffer, "key_bind_ctrl-L", "/listbuffer **refresh")
+ weechat.buffer_set(lb_buffer, "key_bind_meta2-A", "/listbuffer **up")
+ weechat.buffer_set(lb_buffer, "key_bind_meta2-B", "/listbuffer **down")
+ weechat.buffer_set(lb_buffer, "key_bind_meta2-1~", "/listbuffer **scroll_top")
+ weechat.buffer_set(lb_buffer, "key_bind_meta2-4~", "/listbuffer **scroll_bottom")
+ weechat.buffer_set(lb_buffer, "key_bind_meta-ctrl-J", "/listbuffer **enter")
+ weechat.buffer_set(lb_buffer, "key_bind_meta-ctrl-M", "/listbuffer **enter")
+ weechat.buffer_set(lb_buffer, "key_bind_meta->", "/listbuffer **sort_next")
+ weechat.buffer_set(lb_buffer, "key_bind_meta-<", "/listbuffer **sort_previous")
+ weechat.buffer_set(lb_buffer, "key_bind_meta-/", "/listbuffer **sort_invert")
+ lb_curline = 0
+ if weechat.config_get_plugin("autofocus") == "on":
+ if not weechat.window_search_with_buffer(lb_buffer):
+ weechat.command("", "/buffer " + weechat.buffer_get_string(lb_buffer,"name"))
+
+def lb_set_buffer_title():
+ global lb_buffer, lb_current_sort
+ ascdesc = '(v)' if lb_sort_inverted else '(^)'
+ weechat.buffer_set(lb_buffer, "title", lb_line_format({
+ 'channel': 'Channel name%s' % (ascdesc if lb_current_sort == 'channel' else ''),
+ 'users': 'Users%s' % (ascdesc if lb_current_sort == 'users' else ''),
+ 'modes': 'Modes%s' % (ascdesc if lb_current_sort == 'modes' else ''),
+ 'topic': 'Topic%s' % (ascdesc if lb_current_sort == 'topic' else ''),
+ 'nomodes': None,
+ }))
+
+def lb_list_start(data, signal, message):
+ lb_initialise_list
+
+ return weechat.WEECHAT_RC_OK
+
+def lb_initialise_list(signal):
+ global lb_channels, lb_network, lb_list_started
+
+ lb_create_buffer()
+ lb_channels = []
+ lb_network = signal.split(',')[0]
+ lb_list_started = True
+ return
+
+
+def lb_list_chan(data, signal, message):
+ global lb_channels, lb_buffer, lb_list_started
+
+ # Work-around for IRCds which don't send 321 Numeric (/List start)
+ if not lb_list_started:
+ lb_initialise_list(signal)
+
+ for chan_data in re.findall(lb_channel_list_expression,message):
+ lb_channels.append({
+ 'server': chan_data[0][1:-1],
+ 'numeric': chan_data[1],
+ 'nick': chan_data[2],
+ 'channel': chan_data[3],
+ 'users': chan_data[4],
+ 'nomodes': chan_data[5] == '',
+ 'modes': chan_data[6],
+ 'topic': weechat.hook_modifier_exec("irc_color_decode", "1", chan_data[7])
+ })
+ return weechat.WEECHAT_RC_OK
+
+def lb_list_end(data, signal, message):
+ global lb_list_started
+
+ # Work-around for IRCds which don't send 321 Numeric (/List start)
+ if not lb_list_started:
+ lb_initialise_list(signal)
+
+ lb_list_started = False
+ if lb_current_sort:
+ lb_sort()
+ lb_refresh()
+ return weechat.WEECHAT_RC_OK
+
+def keyEvent (data, buffer, args):
+ global lb_options
+ lb_options[args]()
+
+def lb_input_cb(data, buffer, input_data):
+ global lb_options, lb_curline
+ lb_options[input_data]()
+ return weechat.WEECHAT_RC_OK
+
+def lb_refresh():
+ global lb_channels, lb_buffer
+ weechat.buffer_clear(lb_buffer)
+
+ y = 0
+ for list_data in lb_channels:
+ lb_refresh_line(y)
+ y += 1
+ return
+
+def lb_refresh_line(y):
+ global lb_buffer, lb_curline, lb_channels
+ if y >= 0 and y < len(lb_channels):
+ formatted_line = lb_line_format(lb_channels[y], y == lb_curline)
+ weechat.prnt_y(lb_buffer, y, formatted_line)
+
+def lb_refresh_curline():
+ global lb_curline
+ lb_refresh_line(lb_curline-1)
+ lb_refresh_line(lb_curline)
+ lb_refresh_line(lb_curline+1)
+ return
+
+def lb_line_format(list_data,curr=False):
+ str = ""
+ if (curr):
+ str += weechat.color("yellow,red")
+ channel_text = list_data['channel'].ljust(int(weechat.config_get_plugin('channel_min_width')))
+ users_text = "(%s)" % list_data['users']
+ padded_users_text = users_text.rjust(int(weechat.config_get_plugin('users_min_width')) + 2)
+ str += "%s%s %s " % (weechat.color("bold"), channel_text, padded_users_text)
+ if not list_data['nomodes']:
+ modes = "[%s]" % list_data['modes']
+ else:
+ modes = "[]"
+ str += "%s: " % modes.rjust(int(weechat.config_get_plugin('modes_min_width')) + 2)
+ str += "%s" % list_data['topic']
+ return str
+
+def lb_line_up():
+ global lb_curline
+ if lb_curline <= 0:
+ return
+ lb_curline -= 1
+ lb_refresh_curline()
+ lb_check_outside_window()
+ return
+
+def lb_line_down():
+ global lb_curline, lb_channels
+ if lb_curline+1 >= len(lb_channels):
+ return
+ lb_curline += 1
+ lb_refresh_curline()
+ lb_check_outside_window()
+ return
+
+def lb_line_run():
+ global lb_channels, lb_curline, lb_network
+ buff = weechat.info_get("irc_buffer", lb_network)
+ channel = lb_channels[lb_curline]['channel']
+ command = "/join %s" % channel
+ weechat.command(buff, command)
+ return
+
+def lb_line_select():
+ return
+
+def lb_scroll_top():
+ global lb_curline
+ old_y = lb_curline
+ lb_curline = 0
+ lb_refresh_curline()
+ lb_refresh_line(old_y)
+ weechat.command(lb_buffer, "/window scroll_top")
+ return
+
+def lb_scroll_bottom():
+ global lb_curline, lb_channels
+ old_y = lb_curline
+ lb_curline = len(lb_channels)-1
+ lb_refresh_curline()
+ lb_refresh_line(old_y)
+ weechat.command(lb_buffer, "/window scroll_bottom")
+ return
+
+def lb_check_outside_window():
+ global lb_buffer, lb_curline
+ if (lb_buffer):
+ infolist = weechat.infolist_get("window", "", "current")
+ if (weechat.infolist_next(infolist)):
+ start_line_y = weechat.infolist_integer(infolist, "start_line_y")
+ chat_height = weechat.infolist_integer(infolist, "chat_height")
+ if(start_line_y > lb_curline):
+ weechat.command(lb_buffer, "/window scroll -%i" %(start_line_y - lb_curline))
+ elif(start_line_y <= lb_curline - chat_height):
+ weechat.command(lb_buffer, "/window scroll +%i"%(lb_curline - start_line_y - chat_height + 1))
+ weechat.infolist_free(infolist)
+
+def lb_sort_next():
+ global lb_current_sort, lb_sort_options
+ if lb_current_sort:
+ new_index = lb_sort_options.index(lb_current_sort) + 1
+ else:
+ new_index = 0
+
+ if len(lb_sort_options) <= new_index:
+ new_index = 0
+
+ lb_set_current_sort_order(lb_sort_options[new_index])
+ lb_sort()
+
+def lb_set_current_sort_order(value):
+ global lb_current_sort
+ lb_current_sort = value
+ weechat.config_set_plugin('sort_order', lb_current_sort)
+
+def lb_set_invert_sort_order(value):
+ global lb_sort_inverted
+ lb_sort_inverted = value
+ weechat.config_set_plugin('sort_inverted', ('on' if lb_sort_inverted else 'off'))
+
+def lb_sort_previous():
+ global lb_current_sort, lb_sort_options
+ if lb_current_sort:
+ new_index = lb_sort_options.index(lb_current_sort) - 1
+ else:
+ new_index = 0
+
+ if new_index < 0:
+ new_index = len(lb_sort_options) - 1
+
+ lb_set_current_sort_order(lb_sort_options[new_index])
+ lb_sort()
+
+def lb_sort(sort_key=None):
+ global lb_channels, lb_current_sort, lb_sort_inverted
+ if sort_key:
+ lb_set_current_sort_order(sort_key)
+ if lb_current_sort == 'users':
+ lb_channels = sorted(lb_channels, key=lambda chan_data: int(chan_data[lb_current_sort]))
+ else:
+ lb_channels = sorted(lb_channels, key=lambda chan_data: chan_data[lb_current_sort])
+ if lb_sort_inverted:
+ lb_channels.reverse()
+ lb_set_buffer_title()
+ lb_refresh()
+
+def lb_sort_invert():
+ global lb_current_sort, lb_sort_inverted
+ if lb_current_sort:
+ lb_set_invert_sort_order(not lb_sort_inverted)
+ lb_sort()
+
+def lb_close_cb(*kwargs):
+ """ A callback for buffer closing. """
+ global lb_buffer
+
+ lb_buffer = None
+ return weechat.WEECHAT_RC_OK
+
+lb_options = {
+ 'refresh' : lb_refresh,
+ 'up' : lb_line_up,
+ 'down' : lb_line_down,
+ 'enter' : lb_line_run,
+ 'space' : lb_line_select,
+ 'scroll_top' : lb_scroll_top,
+ 'scroll_bottom': lb_scroll_bottom,
+ 'sort_next' : lb_sort_next,
+ 'sort_previous': lb_sort_previous,
+ 'sort_invert': lb_sort_invert
+}
+
+def lb_command_main(data, buffer, args):
+ if args[0:2] == "**":
+ keyEvent(data, buffer, args[2:])
+ return weechat.WEECHAT_RC_OK
+
+def lb_set_default_settings():
+ global lb_settings
+ # Set default settings
+ for option, default_value, description in lb_settings:
+ if not weechat.config_is_set_plugin(option):
+ weechat.config_set_plugin(option, default_value)
+ version = weechat.info_get("version_number", "") or 0
+ if int(version) >= 0x00030500:
+ weechat.config_set_desc_plugin(option, description)
+
+def lb_reset_stored_sort_order():
+ global lb_current_sort, lb_sort_inverted
+ lb_current_sort = weechat.config_get_plugin('sort_order')
+ lb_sort_inverted = (True if weechat.config_get_plugin('sort_inverted') == 'on' else False)
+
+if __name__ == "__main__" and import_ok:
+ if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION,
+ SCRIPT_LICENSE, SCRIPT_DESC, "lb_close_cb", ""):
+ lb_set_default_settings()
+ lb_reset_stored_sort_order()
+ lb_buffer = weechat.buffer_search("python", "listbuffer")
+
+ weechat.hook_signal("*,irc_in_321", "lb_list_start", "")
+ weechat.hook_signal("*,irc_in_322", "lb_list_chan", "")
+ weechat.hook_signal("*,irc_in_323", "lb_list_end", "")
+ weechat.hook_command(SCRIPT_COMMAND,
+ "List Buffer",
+ "", "", "",
+ "lb_command_main", "")
diff --git a/weechat/relay.conf b/weechat/relay.conf
new file mode 100644
index 0000000..7c45ba4
--- /dev/null
+++ b/weechat/relay.conf
@@ -0,0 +1,37 @@
+#
+# relay.conf -- weechat v0.4.3-dev
+#
+
+[look]
+auto_open_buffer = on
+raw_messages = 256
+
+[color]
+client = cyan
+status_active = lightblue
+status_auth_failed = lightred
+status_connecting = yellow
+status_disconnected = lightred
+status_waiting_auth = brown
+text = default
+text_bg = default
+text_selected = white
+
+[network]
+allowed_ips = ""
+bind_address = ""
+compression_level = 6
+ipv6 = on
+max_clients = 5
+password = ""
+ssl_cert_key = "%h/ssl/relay.pem"
+websocket_allowed_origins = ""
+
+[irc]
+backlog_max_minutes = 1440
+backlog_max_number = 256
+backlog_since_last_disconnect = on
+backlog_tags = "irc_privmsg"
+backlog_time_format = "[%H:%M] "
+
+[port]
diff --git a/weechat/rmodifier.conf b/weechat/rmodifier.conf
new file mode 100644
index 0000000..c21d8ef
--- /dev/null
+++ b/weechat/rmodifier.conf
@@ -0,0 +1,14 @@
+#
+# rmodifier.conf -- weechat v0.4.3-dev
+#
+
+[look]
+hide_char = "*"
+
+[modifier]
+command_auth = "history_add,input_text_display,irc_command_auth;^(/(msg|quote) +nickserv +(id|identify|register|ghost \S+|release \S+) +)(.*);1,4*"
+message_auth = "irc_message_auth;^(.*(id|identify|register|ghost \S+|release \S+) +)(.*);1,3*"
+oper = "history_add,input_text_display;^(/oper +\S+ +)(.*);1,2*"
+quote_pass = "history_add,input_text_display;^(/quote pass +)(.*);1,2*"
+server = "history_add,input_text_display;^(/(server|connect) .*-(sasl_)?password=)(\S+)(.*);1,4*,5"
+set_pass = "history_add;^(/set +\S*password\S* +)(.*);1,2*"
diff --git a/weechat/script.conf b/weechat/script.conf
new file mode 100644
index 0000000..570e651
--- /dev/null
+++ b/weechat/script.conf
@@ -0,0 +1,48 @@
+#
+# script.conf -- weechat v0.4.3-dev
+#
+
+[look]
+columns = "%s %n %V %v %u | %d | %t"
+diff_color = on
+diff_command = "auto"
+display_source = on
+quiet_actions = on
+sort = "p,n"
+translate_description = on
+use_keys = on
+
+[color]
+status_autoloaded = cyan
+status_held = white
+status_installed = lightcyan
+status_obsolete = lightmagenta
+status_popular = yellow
+status_running = lightgreen
+status_unknown = lightred
+text = default
+text_bg = default
+text_bg_selected = red
+text_date = default
+text_date_selected = white
+text_delimiters = darkgray
+text_description = default
+text_description_selected = white
+text_extension = default
+text_extension_selected = white
+text_name = cyan
+text_name_selected = lightcyan
+text_selected = white
+text_tags = brown
+text_tags_selected = yellow
+text_version = magenta
+text_version_loaded = default
+text_version_loaded_selected = white
+text_version_selected = lightmagenta
+
+[scripts]
+autoload = on
+cache_expire = 60
+dir = "%h/script"
+hold = ""
+url = "http://www.weechat.org/files/plugins.xml.gz"
diff --git a/weechat/sec.conf b/weechat/sec.conf
new file mode 100644
index 0000000..a6d419a
--- /dev/null
+++ b/weechat/sec.conf
@@ -0,0 +1,11 @@
+#
+# sec.conf -- weechat v0.4.3-dev
+#
+
+[crypt]
+cipher = aes256
+hash_algo = sha256
+passphrase_file = ""
+salt = on
+
+[data]
diff --git a/weechat/theos.crt b/weechat/theos.crt
new file mode 100644
index 0000000..db9e868
--- /dev/null
+++ b/weechat/theos.crt
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID4TCCAsmgAwIBAgIJAIdcg5Fz/kmfMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD
+VQQGEwJOTDETMBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UECgwIa3lyaWFzaXMx
+DDAKBgNVBAsMA3puYzEbMBkGA1UEAwwSdGhlb3Mua3lyaWFzaXMuY29tMSQwIgYJ
+KoZIhvcNAQkBFhVqb2hhbm5lc0BreXJpYXNpcy5jb20wHhcNMTQwMTA4MTYyNjIw
+WhcNMjQwMTA2MTYyNjIwWjCBhjELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNvbWUt
+U3RhdGUxETAPBgNVBAoMCGt5cmlhc2lzMQwwCgYDVQQLDAN6bmMxGzAZBgNVBAMM
+EnRoZW9zLmt5cmlhc2lzLmNvbTEkMCIGCSqGSIb3DQEJARYVam9oYW5uZXNAa3ly
+aWFzaXMuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzX3w6HdZ
+3D9PmyVaoSKQXN1cNshL7pu0yVQekUIoG1NbUo95Dtgt4LD3U2BtjI2PG/mmmnIk
+fZEv7frNGNXc93SBE4x9SM3E8YRxFidFeJNdcnlJrTFMczqZkcullEWWT5Sby/lt
+UEZBl1WtxnmLx8ILpUOAyDUWqUykx0KSW6Z5/rh+zdN3WiHx0RKoIoUGUrF47fbS
+PjdrUKVy14qSoDEjZ1ZMV6DBd5yvbrSsPe0DiQ2HcfXbYtR/XOTVBDDRgPUdwW+b
+IiZ4UWmnMZ2VLElqAhlmL9lwcIXiG6zopqcexzq+O01/02t5jE03BVnZQOaLiPV8
+LjVNAFezEjvdHQIDAQABo1AwTjAdBgNVHQ4EFgQUzWZqmo/ZRmxsLAQpQ8TbzQJk
+J28wHwYDVR0jBBgwFoAUzWZqmo/ZRmxsLAQpQ8TbzQJkJ28wDAYDVR0TBAUwAwEB
+/zANBgkqhkiG9w0BAQUFAAOCAQEAm7HK5ytpjKVVCDNrxKdRmm/IIA7GJwuanYNK
+NVarnj4GdsLSr3x6vci+EsTfGkRiLu7wr/u+Lk2v6gDtFJnkX3AdR5vk6LTrYIGD
+mF3/uliY+tdAJ1D5lCmrgcM/qDo+tyGGB/XpHgy7Ag4uKjYg/VOsopLTqr2ZLtY4
+/TIs894eHbBLUHucG8Qjnqe0BG4Q9CGq+r6NmjX+84COclWlDt25UFU1WCmR49er
+kCCfl40h+Gwsj+JfuqzA8IlXazAFpsnFBfK61/sQ1KH8f4PYzBrFwagHslJMeMgZ
+Mn65qDposEMkYX2g3zTDC9orPpl2pK/XvRV+UGinUwbYuxjfLw==
+-----END CERTIFICATE-----
diff --git a/weechat/xfer.conf b/weechat/xfer.conf
new file mode 100644
index 0000000..c102e9d
--- /dev/null
+++ b/weechat/xfer.conf
@@ -0,0 +1,38 @@
+#
+# xfer.conf -- weechat v0.4.3-dev
+#
+
+[look]
+auto_open_buffer = on
+progress_bar_size = 20
+pv_tags = "notify_private"
+
+[color]
+status_aborted = lightred
+status_active = lightblue
+status_connecting = yellow
+status_done = lightgreen
+status_failed = lightred
+status_waiting = lightcyan
+text = default
+text_bg = default
+text_selected = white
+
+[network]
+blocksize = 65536
+fast_send = on
+own_ip = ""
+port_range = ""
+speed_limit = 0
+timeout = 300
+
+[file]
+auto_accept_chats = off
+auto_accept_files = off
+auto_accept_nicks = ""
+auto_rename = on
+auto_resume = on
+convert_spaces = on
+download_path = "%h/xfer"
+upload_path = "~"
+use_nick_in_filename = on
diff --git a/weechat/yaurls.conf b/weechat/yaurls.conf
new file mode 100644
index 0000000..ed55160
--- /dev/null
+++ b/weechat/yaurls.conf
@@ -0,0 +1,28 @@
+#
+# yaurls.conf -- weechat v0.4.3-dev
+#
+
+[blacklists]
+channel_blacklist = ""
+nick_blacklist = ""
+server_blacklist = ""
+string_blacklist = ""
+url_blacklist = "youtube.com"
+
+[colors]
+domain_color = lightblue
+header_color = green
+prefix_suffix_color = lightmagenta
+url_color = lightgreen
+
+[engine]
+convert_own = on
+maximum_length = 35
+service = durl
+timeout = 20
+
+[look]
+format = "%H %U %D"
+header = "durl"
+header_prefix = "["
+header_suffix = "]→"