From: bd Date: Tue, 31 Mar 2009 13:24:57 +0000 (+0000) Subject: imported scripts X-Git-Url: https://git.madduck.net/code/irssi/scripts-bc-bd.git/commitdiff_plain/refs/heads/master imported scripts --- c814dbc804d0a1969b945364deaefdfe10bf4753 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31884f8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* ident diff --git a/ai.pl b/ai.pl new file mode 100644 index 0000000..69829e8 --- /dev/null +++ b/ai.pl @@ -0,0 +1,265 @@ +use Irssi; +use Irssi::Irc; +use strict; + +use vars qw($VERSION %IRSSI); + +$VERSION="0.3"; +%IRSSI = ( + authors=> 'BC-bd', + contact=> 'bd@bc-bd.org', + name=> 'ai', + description=> 'Puts people on ignore if they do a public away. See source for options.', + license=> 'GPL v2', + url=> 'https://bc-bd.org/svn/repos/irssi/ai', +); + +# $Id$ +# for irssi 0.8.4 by bd@bc-bd.org +# +######### +# USAGE +### +# +# Examples: +# +# Ignore people saying "away" +# /set ai_words away +# +# Ignore people saying "gone for good" or "back" +# /set ai_words gone for good,back +# +# Ignore people for 500 seconds +# /set ai_time 500 +# +# Ignore people forever +# /set ai_time 0 +# +# Ignore people only on channels #foo,#bar +# /set ai_ignore_only_in ON +# /set ai_channels #foo,#bar +# +# Ignore people on all channels BUT #foo,#bar +# /set ai_ignore_only_in OFF +# /set ai_channels #foo,#bar +# +# Ignore people on all channels +# /set ai_ignore_only_in OFF +# /set -clear ai_channels +# +# Perform a command on ignore (e.g send them a message) +# /set ai_command ^msg -$C $N no "$W" in $T please +# +# would become on #foo on chatnet bar from nick dude with "dude is away" +# /msg -cbar dude no "away" in #foo please +# +# look further down for details +# +# Per channel command on #irssi: +# /ai #irssi ^say foobar +# +# delete channel command in #irssi: +# /ai #irssi +# +######### +# OPTIONS +######### +# +# /set ai_words [expr[,]+]+ +# * expr : comma seperated list of expressions that should trigger an ignore +# e.g. : away,foo,bar baz bat,bam +# +# /set ai_command [command] +# * command : to be executed on a triggered ignore. +# /set -clear ai_command to disable. The following $'s are expanded +# ( see the default command for an example ): +# $C : Chatnet (e.g. IRCnet, DALNet, ...) +# $N : Nick (some dude) +# $W : Word (the word(s) that triggered the ignore +# $T : Target (e.g. the channel) +# +# /set ai_channels [#channel[ ]]+ +# * #channel : space seperated list of channels, see ai_ignore_only_in +# +# /set ai_time +# * seconds : number of seconds to wait before removing the ignore +# +# /set ai_ignore_only_in +# * ON : only trigger ignores in ai_channels +# * OFF : trigger ignores in all channels EXCEPT ai_channels +# +# /set ai_display +# * ON : log whole sentence +# * OFF : only log word that matched regex +# +### +################ +### +# +# Changelog +# +# Version 0.4 +# - added optional sentence output +# +# Version 0.3 +# - added per channel command support +# - the command is now executed in the channel the event occured +# - changed the expand char from % to $ +# +# Version 0.2 +# - changed MSGLVL_ALL to MSGLVL_ACTIONS to avoid problems +# with channels with ignored Levels +# +# Version 0.1 +# - initial release +# +### +################ + +sub expand { + my ($string, %format) = @_; + my ($exp, $repl); + $string =~ s/\$$exp/$repl/g while (($exp, $repl) = each(%format)); + return $string; +} + +sub combineSettings { + my ($setting,$string,$match) = @_; + + $match = quotemeta($match); + + if ($setting) { + if ($string !~ /$match\b/i) { + return 1; + } + } else { + if ($string =~ /$match\b/i) { + return 1; + } + } + + return 0; +} + +sub sig_action() { + my ($server,$msg,$nick,$address,$target) = @_; + + my $command; + + if ($server->ignore_check($nick, $address, $target, $msg, MSGLEVEL_ACTIONS)) { + return; + } + + if (combineSettings(Irssi::settings_get_bool('ai_ignore_only_in'), + Irssi::settings_get_str('ai_channels'),$target)) { + return ; + } + + my @words = split(',',Irssi::settings_get_str('ai_words')); + + foreach (@words) { + if ($msg =~ /$_/i) { + my $word = $_; + + my $sentence = $word; + + my $channel = $server->channel_find($target); + my $n = $channel->nick_find($nick); + + my $type = Irssi::Irc::MASK_USER | Irssi::Irc::MASK_DOMAIN; + my $mask = Irssi::Irc::get_mask($n->{nick}, $n->{host}, $type); + + my $time = Irssi::settings_get_int('ai_time'); + if ($time == 0) { + $time = ""; + } else { + $time = "-time ".$time; + } + Irssi::command("^ignore ".$time." $mask"); + + if (Irssi::settings_get_bool('ai_display')) { + $sentence = $msg + } + Irssi::print("Ignoring $nick$target\@$server->{chatnet} because of '$sentence'"); + + my %commands = stringToHash('`',Irssi::settings_get_str('ai_commands')); + if (defined $commands{$target}) { + $command = $commands{$target}; + } else { + $command = Irssi::settings_get_str('ai_command'); + } + + if ($command ne "") { + $command = expand($command,"C",$server->{tag},"N",$nick,"T",$target,"W",$word); + $server->window_item_find($target)->command($command); + $server->window_item_find($target)->print($command); + } + + return; + } + } +} + +sub stringToHash { + my ($delim,$str) = @_; + + return split($delim,$str); +} + +sub hashToString { + my ($delim,%hash) = @_; + + return join($delim,%hash); +} + +sub colorCommand { + my ($com) = @_; + + $com =~ s/\$(.)/%_\$$1%_/g; + + return $com; +} + +sub cmd_ai { + my ($data, $server, $channel) = @_; + + my $chan = $data; + $chan =~ s/ .*//; + $data =~ s/^\Q$chan\E *//; + + my %command = stringToHash('`',Irssi::settings_get_str('ai_commands')); + + if ($chan eq "") { + foreach my $key (keys(%command)) { + Irssi::print("AI: %_$key%_ = ".colorCommand($command{$key})); + } + + Irssi::print("AI: placeholders: %_\$C%_)hatnet %_\$N%_)ick %_\$W%_)ord %_\$T%_)arget"); + Irssi::print("AI: not enough parameters: ai [command]"); + + return; + } + + if ($data eq "") { + delete($command{$chan}); + } else { + $command{$chan} = $data; + } + + Irssi::settings_set_str('ai_commands',hashToString('`',%command)); + + Irssi::print("AI: command on %_$chan%_ now: '".colorCommand($data)."'"); +} + +Irssi::command_bind('ai', 'cmd_ai'); + +# "message irc action", SERVER_REC, char *msg, char *nick, char *address, char *target +Irssi::signal_add_first('message irc action', 'sig_action'); + +Irssi::settings_add_str('misc', 'ai_commands', ''); +Irssi::settings_add_str('misc', 'ai_words', 'away,gone,ist auf'); +Irssi::settings_add_str('misc', 'ai_command', '^msg -$C $N no "$W" in $T please'); +Irssi::settings_add_str('misc', 'ai_channels', ''); +Irssi::settings_add_int('misc', 'ai_time', 500); +Irssi::settings_add_bool('misc', 'ai_ignore_only_in', 0); +Irssi::settings_add_bool('misc', 'ai_display', 0); diff --git a/chanact.pl b/chanact.pl new file mode 100644 index 0000000..d4e36b1 --- /dev/null +++ b/chanact.pl @@ -0,0 +1,571 @@ +use Irssi 20020101.0001 (); +use strict; +use Irssi::TextUI; + +use vars qw($VERSION %IRSSI); + +$VERSION = "0.5.10"; +%IRSSI = ( + authors => 'BC-bd, Veli', + contact => 'bd@bc-bd.org, veli@piipiip.net', + name => 'chanact', + description => 'Adds new powerful and customizable [Act: ...] item (chanelnames,modes,alias). Lets you give alias characters to windows so that you can select those with meta-', + license => 'GNU GPLv2 or later', + url => 'https://bc-bd.org/svn/repos/irssi/chanact' +); + +# Adds new powerful and customizable [Act: ...] item (chanelnames,modes,alias). +# Lets you give alias characters to windows so that you can select those with +# meta-. +# +# for irssi 0.8.2 by bd@bc-bd.org +# +# inspired by chanlist.pl by 'cumol@hammerhart.de' +# +######### +# Contributors +######### +# +# veli@piipiip.net /window_alias code +# qrczak@knm.org.pl chanact_abbreviate_names +# qerub@home.se Extra chanact_show_mode and chanact_chop_status +# madduck@madduck.net Better channel aliasing (case-sensitive, cross-network) +# Jan 'jast' Krueger , 2004-06-22 +# Ivo Timmermans win->{hilight} patch +# +######### +# USAGE +### +# +# copy the script to ~/.irssi/scripts/ +# +# In irssi: +# +# /script load chanact +# /statusbar window add -after act chanact +# +# If you want the item to appear on another position read the help +# for /statusbar. +# To remove the [Act: 1,2,3] item type: +# +# /statusbar window remove act +# +# To see all chanact options type: +# +# / set chanact_ +# +# After these steps you have your new statusbar item and you can start giving +# aliases to your windows. Go to the window you want to give the alias to +# and say: +# +# /window_alias +# +# You can also remove the aliases with: +# +# /window_unalias +# +# or in aliased window: +# +# /window_unalias +# +# To see a list of your windows use: +# +# /window list +# +######### +# OPTIONS +######### +# +# /set chanact_chop_status +# * ON : shorten (Status) to S +# * OFF : don't do it +# +# /set chanact_show_mode +# * ON : show channel modes +# * OFF : don't show channel modes +# +# /set chanact_sort_by_activity +# * ON : sorts the list by last activity +# * OFF : sorts the list by window number +# +# /set chanact_display +# * string : Format String for one Channel. The following $'s are expanded: +# $C : Channel +# $N : Number of the Window +# $M : Mode in that channel +# $H : Start highlightning +# $S : Stop highlightning +# * example: +# +# /set chanact_display $H$N:$M.$S$C +# +# will give you on #irssi.de if you have voice +# +# [3:+.#irssi.de] +# +# with '3:+.' highlighted and the channel name printed in regular color +# +# /set chanact_display_alias +# as 'chanact_display' but is used if the window has an alias and +# 'chanact_show_alias' is set to on. +# +# /set chanact_show_names +# * ON : show the channelnames after the number/alias +# * OFF : don't show the names +# +# /set chanact_abbreviate_names +# * 0 : don't abbreviate +# * : strip channel name prefix character and leave only +# that many characters of the proper name +# +# /set chanact_show_alias +# * ON : show the aliase instead of the refnum +# * OFF : shot the refnum +# +# /set chanact_header +# * : Characters to be displayed at the start of the item. +# Defaults to: "Act: " +# +# /set chanact_separator +# * : Charater to use between the channel entries +# +# /set chanact_autorenumber +# * ON : Move the window automatically to first available slot +# starting from "chanact_renumber_start" when assigning +# an alias to window. Also moves the window back to a +# first available slot from refnum 1 when the window +# loses it's alias. +# * OFF : Don't move the windows automatically +# +# /set chanact_renumber_start +# * : Move the window to first available slot after this +# num when "chanact_autorenumber" is ON. +# +# /set chanact_remove_hash +# * ON : Remove &#+!= from channel names +# * OFF : Don't touch channel names +# +# /set chanact_remove_prefix +# * : Regular expression used to remove from the +# beginning of the channel name. +# * example : +# To shorten a lot of debian channels: +# +# /set chanact_remove_prefix deb(ian.(devel-)?)? +# +# /set chanact_filter +# * 0 : show all channels +# * 1 : hide channels without activity +# * 2 : hide channels with only join/part/etc messages +# * 3 : hide channels with text messages +# * 4 : hide all channels (now why would you want to do that) +# +######### +# HINTS +######### +# +# If you have trouble with wrong colored entries your 'default.theme' might +# be too old. Try on a shell: +# +# $ mv ~/.irssi/default.theme /tmp/ +# +# And in irssi: +# /reload +# /save +# +### +################# + +my %show = ( + 0 => "{%n ", # NOTHING + 1 => "{sb_act_text ", # TEXT + 2 => "{sb_act_msg ", # MSG + 3 => "{sb_act_hilight ", # HILIGHT +); + +my ($actString,$needRemake); + +sub expand { + my ($string, %format) = @_; + my ($exp, $repl); + $string =~ s/\$$exp/$repl/g while (($exp, $repl) = each(%format)); + return $string; +} + +# method will get called every time the statusbar item will be displayed +# but we dont need to recreate the item every time so we first +# check if something has changed and only then we recreate the string +# this might just save some cycles +# FIXME implement $get_size_only check, and user $item->{min|max-size} +sub chanact { + my ($item, $get_size_only) = @_; + + if ($needRemake) { + remake(); + } + + $item->default_handler($get_size_only, $actString, undef, 1); +} + +# this is the real creation method +sub remake() { + my ($afternumber,$finish,$hilight,$mode,$number,$display,@windows); + my $separator = Irssi::settings_get_str('chanact_separator'); + my $abbrev = Irssi::settings_get_int('chanact_abbreviate_names'); + my $remove_prefix = Irssi::settings_get_str('chanact_remove_prefix'); + my $remove_hash = Irssi::settings_get_bool('chanact_remove_hash'); + + if (Irssi::settings_get_bool('chanact_sort_by_activity')) { + @windows = sort { ($b->{last_line} <=> $a->{last_line}) } + Irssi::windows; + } else { + @windows = sort { ($a->{refnum}) <=> ($b->{refnum}) } + Irssi::windows; + } + + $actString = ""; + foreach my $win (@windows) { + + # since irssi is single threaded this shouldn't happen + !ref($win) && next; + + my $active = $win->{active}; + !ref($active) && next; + + my $name = $win->get_active_name; + + # (status) is an awfull long name, so make it short to 'S' + # some people don't like it, so make it configurable + if (Irssi::settings_get_bool('chanact_chop_status') + && $name eq "(status)") { + $name = "S"; + } + + # check if we should show the mode + $mode = ""; + if ($active->{type} eq "CHANNEL") { + my $server = $win->{active_server}; + !ref($server) && next; + + my $channel = $server->channel_find($name); + !ref($channel) && next; + + my $nick = $channel->nick_find($server->{nick}); + !ref($nick) && next; + + if ($nick->{op}) { + $mode = "@"; + } elsif ($nick->{voice}) { + $mode = "+"; + } elsif ($nick->{halfop}) { + $mode = "%"; + } + } + + next if (Irssi::settings_get_int('chanact_filter') > $win->{data_level}); + + # in case we have a specific hilightcolor use it + if ($win->{hilight_color}) { + $hilight = "{sb_act_hilight_color $win->{hilight_color} "; + } else { + $hilight = $show{$win->{data_level}}; + } + + if ($remove_prefix) { + $name =~ s/^([&#+!=]?)$remove_prefix/$1/; + } + if ($abbrev) { + if ($name =~ /^[&#+!=]/) { + $name = substr($name, 1, $abbrev + 1); + } else { + $name = substr($name, 0, $abbrev); + } + } + if ($remove_hash) { + $name =~ s/^[&#+!=]//; + } + + if (Irssi::settings_get_bool('chanact_show_alias') == 1 && + $win->{name} =~ /^([a-zA-Z+]):(.+)$/) { + $number = "$1"; + $display = Irssi::settings_get_str('chanact_display_alias'); + } else { + $number = $win->{refnum}; + $display = Irssi::settings_get_str('chanact_display'); + } + + $actString .= expand($display,"C",$name,"N",$number,"M",$mode,"H",$hilight,"S","}{sb_background}").$separator; + } + + # assemble the final string + if ($actString ne "") { + # Remove the last separator + $actString =~ s/$separator$//; + + if (Irssi::settings_get_int('chanact_filter')) { + $actString = "{sb ".Irssi::settings_get_str('chanact_header').$actString."}"; + } else { + $actString = "{sb ".$actString."}"; + } + } + + # no remake needed any longer + $needRemake = 0; +} + +# method called because of some events. here we dont remake the item but just +# remember that we have to remake it the next time we are called +sub chanactHasChanged() +{ + # if needRemake is already set, no need to trigger a redraw as we will + # be redrawing the item anyway. + return if $needRemake; + + $needRemake = 1; + + Irssi::statusbar_items_redraw('chanact'); +} + +# function by veli@piipiip.net +# Remove alias +sub cmd_window_unalias { + my ($data, $server, $witem) = @_; + my $rn_start = Irssi::settings_get_int('chanact_renumber_start'); + + unless ($data =~ /^[a-zA-Z]$/ || + Irssi::active_win()->{name} =~ /^[a-zA-Z]$/) { + Irssi::print("Usage: /window_unalias "); + Irssi::print("or /window_alias in window that has an alias."); + return; + } + + if ($data eq '') { $data = Irssi::active_win()->{name}; } + + if (my $oldwin = Irssi::window_find_name($data)) { + $oldwin->set_name(undef); + Irssi::print("Removed alias with the key '$data'."); + + if (Irssi::settings_get_bool('chanact_autorenumber') == 1 && + $oldwin->{refnum} >= $rn_start) { + my $old_refnum = $oldwin->{refnum}; + + # Find the first available slot and move the window + my $newnum = 1; + while (Irssi::window_find_refnum($newnum) ne "") { $newnum++; } + $oldwin->set_refnum($newnum); + + Irssi::print("and moved it to from $old_refnum to $newnum"); + } + } +} + +# function by veli@piipiip.net +# Make an alias +sub cmd_window_alias { + my ($data, $server, $witem) = @_; + my $rn_start = Irssi::settings_get_int('chanact_renumber_start'); + + unless ($data =~ /^[a-zA-Z+]$/) { + Irssi::print("Usage: /window_alias "); + return; + } + + cmd_window_unalias($data, $server, $witem); + + my $window = $witem->window(); + my $winnum = $window->{refnum}; + + if (Irssi::settings_get_bool('chanact_autorenumber') == 1 && + $window->{refnum} < $rn_start) { + my $old_refnum = $window->{refnum}; + + $winnum = $rn_start; + + # Find the first available slot and move the window + while (Irssi::window_find_refnum($winnum) ne "") { $winnum++; } + $window->set_refnum($winnum); + + Irssi::print("Moved the window from $old_refnum to $winnum"); + } + + my $winname = $witem->{name}; + my $winserver = $window->{active_server}->{tag}; + my $winhandle = "$winserver/$winname"; + $window->set_name("$data:$winhandle"); + $server->command("/bind meta-$data change_window $data:$winhandle"); + Irssi::print("Window $winhandle is now accessible with meta-$data"); +} + +# function by veli@piipiip.net +# Makes the aliases if names have already been set +sub cmd_rebuild_aliases { + foreach (sort { $a->{refnum} <=> $b->{refnum} } Irssi::windows) { + if ($_->{name} =~ /^[a-zA-Z]$/) { + cmd_window_alias($_->{name}, $_->{active_server}, $_->{active}); + } + } +} + +# function by veli@piipiip.net +# Change the binding if the window refnum changes. +sub refnum_changed { + my ($window, $oldref) = @_; + my $server = Irssi::active_server(); + + if ($window->{name} =~ /^[a-zA-Z]$/) { + $server->command("/bind meta-".$window->{name}." change_window ".$window->{refnum}); + } +} + +$needRemake = 1; + +# Window alias command +Irssi::command_bind('window_alias','cmd_window_alias'); +Irssi::command_bind('window_unalias','cmd_window_unalias'); +# Irssi::command_bind('window_alias_rebuild','cmd_rebuild_aliases'); + +# our config item +Irssi::settings_add_str('chanact', 'chanact_display', '$H$N:$M$C$S'); +Irssi::settings_add_str('chanact', 'chanact_display_alias', '$H$N$M$S'); +Irssi::settings_add_int('chanact', 'chanact_abbreviate_names', 0); +Irssi::settings_add_bool('chanact', 'chanact_show_alias', 1); +Irssi::settings_add_str('chanact', 'chanact_separator', " "); +Irssi::settings_add_bool('chanact', 'chanact_autorenumber', 0); +Irssi::settings_add_bool('chanact', 'chanact_remove_hash', 0); +Irssi::settings_add_str('chanact', 'chanact_remove_prefix', ""); +Irssi::settings_add_int('chanact', 'chanact_renumber_start', 50); +Irssi::settings_add_str('chanact', 'chanact_header', "Act: "); +Irssi::settings_add_bool('chanact', 'chanact_chop_status', 1); +Irssi::settings_add_bool('chanact', 'chanact_sort_by_activity', 1); +Irssi::settings_add_int('chanact', 'chanact_filter', 0); + +# register the statusbar item +Irssi::statusbar_item_register('chanact', '$0', 'chanact'); +# according to cras we shall not call this +# Irssi::statusbars_recreate_items(); + +# register all that nifty callbacks on special events +Irssi::signal_add_last('setup changed', 'chanactHasChanged'); +Irssi::signal_add_last('window changed', 'chanactHasChanged'); +Irssi::signal_add_last('window item changed', 'chanactHasChanged'); +Irssi::signal_add_last('window hilight', 'chanactHasChanged'); +Irssi::signal_add_last('window item hilight', 'chanactHasChanged'); +Irssi::signal_add("window created", "chanactHasChanged"); +Irssi::signal_add("window destroyed", "chanactHasChanged"); +Irssi::signal_add("window name changed", "chanactHasChanged"); +Irssi::signal_add("window activity", "chanactHasChanged"); +Irssi::signal_add("print text", "chanactHasChanged"); +Irssi::signal_add('nick mode changed', 'chanactHasChanged'); + +Irssi::signal_add_last('window refnum changed', 'refnum_changed'); + +############### +### +# +# Changelog +# +# 0.5.10 +# - fixed irssi crash when using Irssi::print from within remake() +# - added option to filter out some data levels, based on a patch by +# Juergen Jung , see +# https://bc-bd.org/trac/irssi/ticket/15 +# + retired chanact_show_all in favour of chanact_filter +# +# 0.5.9 +# - changes by stefan voelkel +# + sort channels by activity, see +# https://bc-bd.org/trac/irssi/ticket/5, based on a patch by jan +# krueger +# + fixed chrash on /exec -interactive, see +# https://bc-bd.org/trac/irssi/ticket/7 +# +# - changes by Jan 'jast' Krueger , 2004-06-22 +# + updated documentation in script's comments +# +# - changes by Ivo Timmermans +# + honor actcolor /hilight setting if present +# +# 0.5.8 +# - made aliases case-sensitive and include network in channel names by madduck +# +# 0.5.7 +# - integrated remove patch by Christoph Berg +# +# 0.5.6 +# - fixed a bug (#1) reported by Wouter Coekaert +# +# 0.5.5 +# - some speedups from David Leadbeater +# +# +# 0.5.4 +# - added help for chanact_display_alias +# +# 0.5.3 +# - added '+' to the available chars of aliase's +# - added chanact_display_alias to allow different display modes if the window +# has an alias +# +# 0.5.2 +# - removed unused chanact_show_name settings (thx to Qerub) +# - fixed $mode display +# - guarded reference operations to (hopefully) fix errors on server disconnect +# +# 0.5.1 +# - small typo fixed +# +# 0.5.0 +# - changed chanact_show_mode to chanact_display. reversed changes from +# Qerub through that, but kept funcionality. +# - removed chanact_color_all since it is no longer needed +# +# 0.4.3 +# - changes by Qerub +# + added chanact_show_mode to show the mode just before the channel name +# + added chanact_chop_status to be able to control the (status) chopping +# [bd] minor implementation changes +# - moved Changelog to the end of the file since it is getting pretty big +# +# 0.4.2 +# - changed back to old version numbering sheme +# - added '=' to Qrczak's chanact_abbreviate_names stuff :) +# - added chanact_header +# +# 0.41q +# - changes by Qrczak +# + added setting 'chanact_abbreviate_names' +# + windows are sorted by refnum; I didn't understand the old +# logic and it broke sorting for numbers above 9 +# +# 0.41 +# - minor updates +# + fixed channel sort [veli] +# + removed few typos and added some documentation [veli] +# +# 0.4 +# - merge with window_alias.pl +# + added /window_alias from window_alias.pl by veli@piipiip.net +# + added setting 'chanact_show_alias' +# + added setting 'chanact_show_names' +# + changed setting 'chanact_show_mode' to int +# + added setting 'chanact_separator' [veli] +# + added setting 'chanact_autorenumber' [veli] +# + added setting 'chanact_renumber_start' [veli] +# + added /window_unalias [veli] +# + moved setting to their own group 'chanact' [veli] +# +# 0.3 +# - merge with chanlist.pl +# + added setting 'chanact_show_mode' +# + added setting 'chanact_show_all' +# +# 0.2 +# - added 'Act' to the item +# - added setting 'chanact_color_all' +# - finally found format for statusbar hilight +# +# 0.1 +# - Initial Release +# +### +################ diff --git a/ircops.pl b/ircops.pl new file mode 100644 index 0000000..1048691 --- /dev/null +++ b/ircops.pl @@ -0,0 +1,44 @@ +use Irssi; +use strict; + +use vars qw($VERSION %IRSSI); + +$VERSION = "0.1"; +%IRSSI = ( + authors => 'BC-bd', + contact => 'bd@bc-bd.org', + name => 'ircops', + description => '/IRCOPS - Display IrcOps in current channel', + license => 'GPL v2', + url => 'https://bc-bd.org/svn/repos/irssi/ircpops', +); + +sub cmd_ircops { + my ($data, $server, $channel) = @_; + + my (@list,$text,$num); + + if (!$channel || $channel->{type} ne 'CHANNEL') { + Irssi::print('No active channel in window'); + return; + } + + foreach my $nick ($channel->nicks()) { + if ($nick->{serverop}) { + push(@list,$nick->{nick}); + } + } + + $num = scalar @list; + + if ($num == 0) { + $text = "no IrcOps on this channel"; + } else { + $text = "IrcOps (".$num."): ".join(" ",@list); + } + + $channel->print($text); +} + +Irssi::command_bind('ircops', 'cmd_ircops'); + diff --git a/nact.pl b/nact.pl new file mode 100644 index 0000000..8f4345e --- /dev/null +++ b/nact.pl @@ -0,0 +1,334 @@ +use Irssi; +use Irssi::TextUI; +use strict; + +use vars qw($VERSION %IRSSI); + +$VERSION="0.2.6"; +%IRSSI = ( + authors=> 'BC-bd', + contact=> 'bd@bc-bd.org', + name=> 'nact', + description=> 'Adds an item which displays the current network activity. Needs /proc/net/dev.', + license=> 'GPL v2 or later', + url=> 'https://bc-bd.org/svn/repos/irssi/nact', +); + +######### +# INFO +### +# +# Currently running on Linux, OpenBsd and FreeBsd. +# +# Type this to add the item: +# +# /statusbar window add nact +# +# See +# +# /help statusbar +# +# for more help on how to custimize your statusbar. +# Add something like this to your theme file to customize to look of the item +# +# nact_display = "$0%R>%n%_$1%_%G>%n$2"; +# +# where $0 is the input, $1 the device and $2 the output. To customize the +# outout of the /bw command add something like +# +# nact_command = "$0)in:$1:out($2"; +# +# to your theme file. +# +########## +# THEME +#### +# +# This is the complete list of parameters passed to the format: +# +# $0: incomming rate +# $1: name of the device, eg. eth0 +# $2: outgoing rate +# $3: total bytes received +# $4: total bytes sent +# $5: sum of $4 and $5 +# +######### +# TODO +### +# +# Make this script work on other unices, For that i need some infos on where +# to find the total amount of sent bytes on other systems. You may be so kind +# as to send me the name of such a file and a sample output of it. +# +# or +# +# you can be so kind as to send me a patch. Fort that _please_ check that you +# do have the latest nact.pl and use these diff switches: +# +# diff -uN nact.pl.new nact.pl.old +# +############ +# OPTIONS +###### +# +# /set nact_command +# command: command to execute on /bw. example: +# +# /set nact_command /say +# +# /set nact_devices +# devices: space seperated list of devices to display +# +# /set nact_interval +# n: number of mili-seconds to wait before an update of the item +# +# /set nact_format +# format: a format string like the one with sprintf. examples: +# +# /set nact_format %d no digits after the point at all +# /set nact_format %.3f 3 digits after the point +# /set nact_format %.5f 5 digits after the point +# +# /set nact_unit +# n: set the unit to KiB, MiB, or GiB. examples: +# +# /set nact_unit 0 calculate dynamically +# /set nact_unit 1 set to KiB/s +# /set nact_unit 2 set to MiB/s +# /set nact_unit 3 set to GiB/s +# +### +################ + +my $outString = "nact..."; +my $outCmd = "nact..."; +my (%in,%out,$timeout,$getBytes); + +sub getBytesLinux() { + my @list; + my $ignore = 2; + + open(FID, "/proc/net/dev"); + + while () { + if ($ignore > 0) { + $ignore--; + next; + } + + my $line = $_; + $line =~ s/[\s:]/ /g; + @list = split(" ", $line); + $in{$list[0]} = $list[1]; + $out{$list[0]} = $list[9]; + } + + close (FID); +} + +sub getBytesOBSD() { + my @list; + + open(FID, "/usr/bin/netstat -nib|"); + + while () { + my $line = $_; + @list = split(" ", $line); + $in{$list[0]} = $list[4]; + $out{$list[0]} = $list[5]; + } + + close (FID); +} + +sub getBytesFBSD() { + my @list; + my $olddev=""; + + open(FID, "/usr/bin/netstat -nib|"); + while () { + my $line = $_; + @list = split(" ", $line); + next if $list[0] eq $olddev; + $in{$list[0]} = $list[6]; + $out{$list[0]} = $list[9]; + $olddev=$list[0]; + } + + close (FID); +} + +sub make_kilo($$$) { + my ($what,$format,$unit) = @_; + my ($effective); + + # determine the effective unit, either from forcing, or from dynamically + # checking the size of the value + if ($unit == 0) { + if ($what >= 1024*1024*1024) { + $effective = 3 + } elsif ($what >= 1024*1024) { + $effective = 2 + } elsif ($what >= 1024) { + $effective = 1 + } else { + $effective = 0; + } + } else { + $effective = $unit; + } + + if ($effective >= 3) { + return sprintf($format."%s", $what/(1024*1024*1024), "G"); + } elsif ($effective == 2) { + return sprintf($format."%s", $what/(1024*1024), "M"); + } elsif ($effective == 1) { + return sprintf($format."%s", $what/(1024), "K"); + } else { + return sprintf($format, $what); + } +} + +sub sb_nact() { + my ($item, $get_size_only) = @_; + + $item->default_handler($get_size_only, "{sb $outString}", undef, 1); +} + +sub timeout_nact() { + my ($out,$char); + my $slice = Irssi::settings_get_int('nact_interval'); + my $format = Irssi::settings_get_str('nact_format'); + my $unit = Irssi::settings_get_int('nact_unit'); + my $theme = Irssi::current_theme(); + my %oldIn = %in; + my %oldOut = %out; + + &$getBytes(); + + $out = ""; + $outCmd = ""; + + foreach (split(" ", Irssi::settings_get_str('nact_devices'))) { + my $b_in = $in{$_}; + my $b_out = $out{$_}; + my $deltaIn = make_kilo(($b_in -$oldIn{$_})*1000/$slice,$format,$unit); + my $deltaOut = make_kilo(($b_out -$oldOut{$_})*1000/$slice,$format,$unit); + my $i = make_kilo($b_in,$format,$unit); + my $o = make_kilo($b_out,$format,$unit); + my $s = make_kilo($b_in +$b_out,$format,$unit); + + $out .= Irssi::current_theme->format_expand( + "{nact_display $deltaIn $_ $deltaOut $i $o $s}",Irssi::EXPAND_FLAG_IGNORE_REPLACES); + + $outCmd .= Irssi::current_theme->format_expand( + "{nact_command $deltaIn $_ $deltaOut $i $o $s}",Irssi::EXPAND_FLAG_IGNORE_REPLACES); + } + + # perhaps this usage of $out as temp variable does fix those nasty + # display errors + $outString = $out; + Irssi::statusbar_items_redraw('nact'); +} + +sub nact_setup() { + my $slice = Irssi::settings_get_int('nact_interval'); + + Irssi::timeout_remove($timeout); + + if ($slice < 10) { + Irssi::print("nact.pl, ERROR nact_interval must be greater than 10"); + return; + } + + $timeout = Irssi::timeout_add($slice, 'timeout_nact' , undef); +} + +sub cmd_bw { + my ($data, $server, $witem) = @_; + + if ($witem && ($witem->{type} eq "CHANNEL" || $witem->{type} eq "QUERY")) { + $witem->command(Irssi::settings_get_str('nact_command')." ".$outCmd); + } else { + Irssi::print("nact: command needs window of type channel or query."); + } +} + +Irssi::command_bind('bw','cmd_bw'); + +Irssi::signal_add('setup changed','nact_setup'); + +# register our item +Irssi::statusbar_item_register('nact', undef, 'sb_nact'); + +# register our os independant settings +Irssi::settings_add_int('misc', 'nact_interval', 10000); +Irssi::settings_add_str('misc', 'nact_format', '%.0f'); +Irssi::settings_add_int('misc', 'nact_unit', 0); +Irssi::settings_add_str('misc', 'nact_command', 'me looks at the gauges:'); + +# os detection +my $os = `uname`; +if ($os =~ /Linux/) { + Irssi::print("nact.pl, running on Linux, using /proc/net/dev"); + $getBytes = \&getBytesLinux; + Irssi::settings_add_str('misc', 'nact_devices', "eth0 lo"); +} elsif ($os =~ /OpenBSD/) { + Irssi::print("nact.pl, running on OpenBSD, using netstat -nbi"); + $getBytes = \&getBytesOBSD; + Irssi::settings_add_str('misc', 'nact_devices', "tun0"); +} elsif ($os =~ /FreeBSD/) { + Irssi::print("nact.pl, running on FreeBSD, using netstat -nbi"); + $getBytes = \&getBytesFBSD; + Irssi::settings_add_str('misc', 'nact_devices', "rl0"); +} else { + Irssi::print("nact.pl, sorry no support for OS:$os"); + Irssi::print("nact.pl, If you know how to collect the needed data on your OS, mail me :)"); + $os = ""; +} + +if ($os ne "") { + &$getBytes(); + nact_setup(); +} + +################ +### +# Changelog +# +# Version 0.2.5 +# - added nact_command +# - added /bw +# +# Version 0.2.4 +# - added FreeBSD support (by senneth) +# +# Version 0.2.3 +# - stray ' ' in the item (reported by darix). Add a " " at the end of your +# nact_display if you have more than one interface listed. +# +# Version 0.2.2 +# - added missing use Irssi::TextUI (reported by darix) +# - small parameter switch bug (reported by darix) +# +# Version 0.2.1 +# - added total number of bytes sent/received +# +# Version 0.2.0 +# - runs now from autorun/ on openbsd +# - changed nact_interval to mili-seconds +# - added nact_format, nact_unit +# +# Version 0.1.2 +# - small typo in the docs +# +# Version 0.1.1 +# - introduced multiple os support +# - added a theme thingie to make sascha happy ;) +# +# Version 0.1.0 +# - initial release +# +### +################ diff --git a/niq.pl b/niq.pl new file mode 100644 index 0000000..c601247 --- /dev/null +++ b/niq.pl @@ -0,0 +1,325 @@ +# BitchX TAB complete style +# for irssi 0.7.99 by bd@bc-bd.org +# +# signal handling learned from dictcomplete by Timo Sirainen +# +# thx go out to fuchs, darix, dg, peder and all on #irssi who helped +# +######### +# USAGE +### +# +# In a channel window type "ab" to see a list of nicks starting +# with "ab". +# If you now press again, irssi will default to its own nick +# completion method. +# If you enter more characters you can use again to see a list +# of the matching nicks, or to complete the nick if there is only +# one matching. +# +# The last completion is saved so if you press "" with an empty +# input line, you get the last completed nick. +# +# Now there is a statusbar item where you can see the completing +# nicks instead of in the channel window. There are two ways to +# use it: +# +# 1) Inside another statusbar +# +# /set niq_show_in_statusbar ON +# /statusbar window add -before more niq +# +# 2) In an own statusbar +# +# /set niq_show_in_statusbar ON +# /set niq_own_statusbar ON +# +# WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +# +# THIS IS CURRENTLY BROKEN IN IRSSI 0.8.4 AND ONLY WORKS WITH +# THE ACTUAL CVS VERSION. USEING THIS ON AN VERSION 0.8.4 OR +# OLDER WILL ERASE YOUR INPUT LINE +# +# With 2) you can also set +# +# /set niq_hide_on_inactive ON +# +# which will only show the bar if you complete nicks. +# +# WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +# +######### +# OPTIONS +######### +# +# /set niq_show_in_statusbar +# * ON : show the completing nicks in a statusbar item +# * OFF : show the nicks in the channel window +# +# /set niq_own_statusbar +# * ON : use an own statusbar for the nicks +# * OFF : just use an item +# +# /set niq_hide_on_inactive +# * ON : hide the own statusbar on inactivity +# * OFF : dont hide it +# +# /set niq_color_char +# * ON : colors the next unlikely character +# * OFF : boring no colors +# +### +################ +### +# Changelog +# +# Version 0.5.6 +# - work around an use problem +# +# Version 0.5.5 +# - fixed completion for nicks starting with special chars +# +# Version 0.5.4 +# - removed unneeded sort() of colored nicks +# - moved colored nick generation to where it is needed +# - the statusbar only worked with colorized nicks (duh!) +# +# Version 0.5.3 +# - stop nickcompleting if last char is the completion_char +# which is in most cases ':' +# +# Version 0.5.2 +# - fixed vanishing statusbar. it wrongly was reset on any +# privmsg. +# +# Version 0.5.1 +# - changed statusbar to be off by default since most people +# dont use the latest fixed version. +# +# Version 0.5 +# - added own statusbar option +# - added color char option +# +# Version 0.4 +# - added an niq statusbar +# +# Version 0.3 +# - added default to irssi method on +# +# Version 0.2 +# - added lastcomp support +# +# Version 0.1 +# - initial release +### +################ + +use Irssi; +use Irssi::TextUI; +use strict; + +use vars qw($VERSION %IRSSI); + +$VERSION="0.5.6"; +%IRSSI = ( + authors=> 'BC-bd', + contact=> 'bd@bc-bd.org', + name=> 'niq', + description=> 'BitchX like Nickcompletion at line start plus statusbar', + license=> 'GPL v2', + url=> 'https://bc-bd.org/svn/repos/irssi/niq', +); + +my($lastword,$lastcomp,$niqString); + +$lastcomp = ""; +$lastword = ""; + +# build our nick with completion_char, add to complist and stop the signal +sub buildNickAndStop { + my ($complist,$nick) = @_; + my $push = $nick.Irssi::settings_get_str('completion_char'); + + $lastcomp = $nick; + $lastword = ""; + push (@{$complist}, $push); + + if (Irssi::settings_get_bool('niq_show_in_statusbar') == 1) { + drawStatusbar(""); + } + + Irssi::signal_stop(); +} + +# the signal handler +sub sig_complete { + my ($complist, $window, $word, $linestart, $want_space) = @_; + + # still allow channel- #, /set n, etc completion. + if ($linestart ne "") { + return; + } + + # also back out if nothing has been entered and lastcomp is "" + if ($word eq "") { + if ($lastcomp ne "") { + buildNickAndStop($complist,$lastcomp); + return; + } else { + return; + } + } + if (rindex($word,Irssi::settings_get_str('completion_char')) == length($word) -1) { + chop($word); + buildNickAndStop($complist,$word,0); + return; + } + + my $channel = $window->{active}; + + # the completion is ok if this is a channel + if ($channel->{type} ne "CHANNEL") + { + return; + } + + my (@nicks); + + # get the matching nicks but quote this l33t special chars like ^ + my $shortestNick = 999; + my $quoted = quotemeta $word; + foreach my $n ($channel->nicks()) { + if ($n->{nick} =~ /^$quoted/i && $window->{active_server}->{nick} ne $n->{nick}) { + push(@nicks,$n->{nick}); + if (length($n->{nick}) < $shortestNick) { + $shortestNick = length($n->{nick}); + } + } + } + + @nicks = sort(@nicks); + + # if theres only one nick return it. + if (scalar @nicks eq 1) + { + buildNickAndStop($complist,$nicks[0]); + } elsif (scalar @nicks gt 1) { + # check if this is or + if ($lastword eq $word) { + # so default to the irssi method + sort(@nicks); + for (@nicks) { $_ .= ':'; } + push (@{$complist}, @nicks); + + # but delete lastword to be ready for the next + $lastword = ""; + + if (Irssi::settings_get_bool('niq_show_in_statusbar') == 1) { + drawStatusbar(""); + } + + return; + } else { + # only so just print + + # TODO + # TODO way too slow, need some ideas first! + # TODO + # find the longest matching subword +# Irssi::print(join(" ",@nicks)); +# Irssi::print($shortestNick); +# my ($i,$n); +# my $exit = 0; +# for ($i = length($word); $exit == 0 && $i <$shortestNick; $i++) { +# my $char = substr($nicks[0],$i,1); +# Irssi::print($i." ".$char); +# foreach $n (@nicks) { +# Irssi::print($n); +# if (substr($n,$i,1) ne $char) { +# $i--; +# $exit = 1; +# Irssi::print("exit: ".$i); +# } +# } +# } +# Irssi::print($i); +# $word = substr($nicks[0],0,$i); +# Irssi::print($word); +# +# @$complist = (); +# $$complist[0] = $word; +# $$want_space = 0; + + # build string w/o colored nicks + if (Irssi::settings_get_bool('niq_color_char') == 1) { + $niqString = ""; + foreach my $n (@nicks) { + my $coloredNick = $n; + $coloredNick =~ s/($quoted)(.)(.*)/$1%_$2%_$3/i; + $niqString .= "$coloredNick "; + } + } else { + $niqString = join(" ",@nicks); + } + + if (Irssi::settings_get_bool('niq_show_in_statusbar') == 1) { + drawStatusbar($niqString); + } else { + $window->print($niqString); + } + + Irssi::signal_stop(); + + # remember last word + $lastword = $word; + + return; + } + } + + # we have not found a nick, so someone used within another conttext + # and thus $lastword is no longer of interest +# $lastword = "" +} + +sub emptyBar() { + $lastword = ""; + + drawStatusbar(""); +} + +sub drawStatusbar() { + my ($word) = @_; + + if (Irssi::settings_get_bool('niq_own_statusbar') == 1) { + if (Irssi::settings_get_bool('niq_hide_on_inactive') == 1) { + if ($word eq "") { + Irssi::command("statusbar niq disable"); + } else { + Irssi::command("statusbar niq enable"); + } + } + } + + $niqString = "{sb $word}"; + Irssi::statusbar_items_redraw('niq'); +} + +sub niqStatusbar() { + my ($item, $get_size_only) = @_; + + $item->default_handler($get_size_only, $niqString, undef, 1); +} + +Irssi::signal_add_first('complete word', 'sig_complete'); +Irssi::signal_add_last('window changed', 'emptyBar'); +#Irssi::signal_add('event privmsg', 'emptyBar'); +Irssi::signal_add('message own_public', 'emptyBar'); + +Irssi::statusbar_item_register('niq', '$0', 'niqStatusbar'); +Irssi::statusbars_recreate_items(); + +Irssi::settings_add_bool('misc', 'niq_show_in_statusbar', 0); +Irssi::settings_add_bool('misc', 'niq_own_statusbar', 0); +Irssi::settings_add_bool('misc', 'niq_hide_on_inactive', 1); +Irssi::settings_add_bool('misc', 'niq_color_char', 1); diff --git a/nm.pl b/nm.pl new file mode 100644 index 0000000..41eb39a --- /dev/null +++ b/nm.pl @@ -0,0 +1,616 @@ +use Irssi; +use strict; + +use vars qw($VERSION %IRSSI); + +$VERSION="0.3.6"; +%IRSSI = ( + authors=> 'BC-bd', + contact=> 'bd@bc-bd.org', + name=> 'nm', + description=> 'right aligned nicks depending on longest nick', + license=> 'GPL v2', + url=> 'https://bc-bd.org/svn/repos/irssi/nm', +); + +# $Id$ +# nm.pl +# for irssi 0.8.4 by bd@bc-bd.org +# +# right aligned nicks depending on longest nick +# +# inspired by neatmsg.pl from kodgehopper for some hints +# thanks to Eric Wald for the left alignment patch +# inspired by nickcolor.pl by Timo Sirainen and Ian Peters +# thanks to And1 for a small patch +# thanks to berber@tzi.de for the save/load patch +# +######### +# USAGE +### +# +# use +# +# /neatcolor help +# +# for help on available commands +# +######### +# OPTIONS +######### + +my $help = " +/set neat_colorize + * ON : colorize nicks + * OFF : do not colorize nicks + +/set neat_colors + Use these colors when colorizing nicks, eg: + + /set neat_colors yYrR + + See the file formats.txt on an explanation of what colors are + available. + +/set neat_left_actions + * ON : print nicks left-aligned on actions + * OFF : print nicks right-aligned on actions + +/set neat_left_messages + * ON : print nicks left-aligned on messages + * OFF : print nicks right-aligned on messages + +/set neat_right_mode + * ON : print the mode of the nick e.g @%+ after the nick + * OFF : print it left of the nick + +/set neat_maxlength + * number : Maximum length of Nicks to display. Longer nicks are truncated. + * 0 : Do not truncate nicks. + +/set neat_melength + * number : number of spaces to substract from /me padding + +/set neat_ignorechars + * str : regular expression used to filter out unwanted characters in + nicks. this can be used to assign the same color for similar + nicks, e.g. foo and foo_: + + /set neat_ignorechars [_] + +/set neat_allow_shrinking + * ON : shrink padding when longest nick disappears + * OFF : do not shrink, only allow growing + +"; + +# +### +################ +### +# +# Changelog +# +# Version 0.3.6 +# - added option to ignore certain characters from color hash building, see +# https://bc-bd.org/trac/irssi/ticket/22 +# - added option to save and specify colors for nicks, see +# https://bc-bd.org/trac/irssi/ticket/23 +# - added option to disallow shrinking, see +# https://bc-bd.org/trac/irssi/ticket/12 +# +# Version 0.3.5 +# - now also aligning own messages in queries +# +# Version 0.3.4 +# - fxed off by one error in nick_to_color, patch by jrib, see +# https://bc-bd.org/trac/irssi/ticket/24 +# +# Version 0.3.3 +# - added support for alignment in queries, see +# https://bc-bd.org/trac/irssi/ticket/21 +# +# Version 0.3.2 +# - integrated left alignment patch from Eric Wald , see +# https://bc-bd.org/trac/irssi/ticket/18 +# +# Version 0.3.1 +# - /me padding, see https://bc-bd.org/trac/irssi/ticket/17 +# +# Version 0.3.0 +# - integrate nick coloring support +# +# Version 0.2.1 +# - moved neat_maxlength check to reformat() (thx to Jerome De Greef ) +# +# Version 0.2.0 +# - by adrianel +# * reformat after setup reload +# * maximum length of nicks +# +# Version 0.1.0 +# - got lost somewhere +# +# Version 0.0.2 +# - ugly typo fixed +# +# Version 0.0.1 +# - initial release +# +### +################ +### +# +# BUGS +# +# Empty nicks, eg "<> message" +# This seems to be triggered by some themes. As of now there is no known +# fix other than changing themes, see +# https://bc-bd.org/trac/irssi/ticket/19 +# +# Well, it's a feature: due to the lacking support of extendable themes +# from irssi it is not possible to just change some formats per window. +# This means that right now all windows are aligned with the same nick +# length, which can be somewhat annoying. +# If irssi supports extendable themes, I will include per-server indenting +# and a setting where you can specify servers you don't want to be indented +# +### +################ + +my ($longestNick, %saved_colors, @colors, $alignment, $sign, %commands); + +my $colorize = -1; + +sub reformat() { + my $max = Irssi::settings_get_int('neat_maxlength'); + my $actsign = Irssi::settings_get_bool('neat_left_actions')? '': '-'; + $sign = Irssi::settings_get_bool('neat_left_messages')? '': '-'; + + if ($max && $max < $longestNick) { + $longestNick = $max; + } + + my $me = $longestNick - Irssi::settings_get_int('neat_melength'); + $me = 0 if ($me < 0); + + Irssi::command('^format own_action {ownaction $['.$actsign.$me.']0} $1'); + Irssi::command('^format action_public {pubaction $['.$actsign.$me.']0}$1'); + Irssi::command('^format action_private {pvtaction $['.$actsign.$me.']0}$1'); + Irssi::command('^format action_private_query {pvtaction_query $['.$actsign.$me.']0} $2'); + + my $length = $sign . $longestNick; + if (Irssi::settings_get_bool('neat_right_mode') == 0) { + Irssi::command('^format own_msg {ownmsgnick $2 {ownnick $['.$length.']0}}$1'); + Irssi::command('^format own_msg_channel {ownmsgnick $3 {ownnick $['.$length.']0}{msgchannel $1}}$2'); + Irssi::command('^format pubmsg_me {pubmsgmenick $2 {menick $['.$length.']0}}$1'); + Irssi::command('^format pubmsg_me_channel {pubmsgmenick $3 {menick $['.$length.']0}{msgchannel $1}}$2'); + Irssi::command('^format pubmsg_hilight {pubmsghinick $0 $3 $['.$length.']1%n}$2'); + Irssi::command('^format pubmsg_hilight_channel {pubmsghinick $0 $4 $['.$length.']1{msgchannel $2}}$3'); + Irssi::command('^format pubmsg {pubmsgnick $2 {pubnick $['.$length.']0}}$1'); + Irssi::command('^format pubmsg_channel {pubmsgnick $2 {pubnick $['.$length.']0}}$1'); + } else { + Irssi::command('^format own_msg {ownmsgnick {ownnick $['.$length.']0$2}}$1'); + Irssi::command('^format own_msg_channel {ownmsgnick {ownnick $['.$length.']0$3}{msgchannel $1}}$2'); + Irssi::command('^format pubmsg_me {pubmsgmenick {menick $['.$length.']0}$2}$1'); + Irssi::command('^format pubmsg_me_channel {pubmsgmenick {menick $['.$length.']0$3}{msgchannel $1}}$2'); + Irssi::command('^format pubmsg_hilight {pubmsghinick $0 $0 $['.$length.']1$3%n}$2'); + Irssi::command('^format pubmsg_hilight_channel {pubmsghinick $0 $['.$length.']1$4{msgchannel $2}}$3'); + Irssi::command('^format pubmsg {pubmsgnick {pubnick $['.$length.']0$2}}$1'); + Irssi::command('^format pubmsg_channel {pubmsgnick {pubnick $['.$length.']0$2}}$1'); + } + + # format queries + Irssi::command('^format own_msg_private_query {ownprivmsgnick {ownprivnick $['.$length.']2}}$1'); + Irssi::command('^format msg_private_query {privmsgnick $['.$length.']0}$2'); +}; + +sub findLongestNick { + $longestNick = 0; + + # get own nick length + map { + my $len = length($_->{nick}); + + $longestNick = $len if ($len > $longestNick); + } Irssi::servers(); + + # find longest other nick + foreach (Irssi::channels()) { + foreach ($_->nicks()) { + my $len = length($_->{nick}); + + $longestNick = $len if ($len > $longestNick); + } + } + + reformat(); +} + +# a new nick was created +sub sig_newNick +{ + my ($channel, $nick) = @_; + + my $len = length($nick->{nick}); + + if ($len > $longestNick) { + $longestNick = $len; + reformat(); + } + + return if (exists($saved_colors{$nick->{nick}})); + + $saved_colors{$nick->{nick}} = "%".nick_to_color($nick->{nick}); +} + +# something changed +sub sig_changeNick +{ + my ($channel, $nick, $old_nick) = @_; + + # we only need to recalculate if this was the longest nick + if (length($old_nick) == $longestNick) { + my $len = length($nick->{nick}); + + # if the new nick is shorter we need to find the longest nick + # again, if it is longer, it is the new longest nick + if ($len < $longestNick) { + # only look for a new longest nick if we are allowed to + # shrink + findLongestNick() if Irssi::settings_get_bool('neat_allow_shrinking'); + } else { + $longestNick = $len; + } + + reformat(); + } + + $saved_colors{$nick->{nick}} = $saved_colors{$nick->{old_nick}}; + delete $saved_colors{$nick->{old_nick}} +} + +sub sig_removeNick +{ + my ($channel, $nick) = @_; + + my $thisLen = length($nick->{nick}); + + # we only need to recalculate if this was the longest nick and we are + # allowed to shrink + if ($thisLen == $longestNick && Irssi::settings_get_bool('neat_allow_shrinking')) { + findLongestNick(); + reformat(); + } + + # we do not remove a known color for a gone nick, as they may return +} + +# based on simple_hash from nickcolor.pl +sub nick_to_color($) { + my ($string) = @_; + chomp $string; + + my $ignore = Irssi::settings_get_str("neat_ignorechars"); + $string =~ s/$ignore//g; + + my $counter; + foreach my $char (split(//, $string)) { + $counter += ord $char; + } + + return $colors[$counter % ($#colors + 1)]; +} + +sub color_left($) { + Irssi::command('^format pubmsg {pubmsgnick $2 {pubnick '.$_[0].'$['.$sign.$longestNick.']0}}$1'); + Irssi::command('^format pubmsg_channel {pubmsgnick $2 {pubnick '.$_[0].'$['.$sign.$longestNick.']0}}$1'); +} + +sub color_right($) { + Irssi::command('^format pubmsg {pubmsgnick {pubnick '.$_[0].'$['.$sign.$longestNick.']0}$2}$1'); + Irssi::command('^format pubmsg_channel {pubmsgnick {pubnick '.$_[0].'$['.$sign.$longestNick.']0}$2}$1'); +} + +sub sig_public { + my ($server, $msg, $nick, $address, $target) = @_; + + &$alignment($saved_colors{$nick}); +} + +sub sig_setup { + @colors = split(//, Irssi::settings_get_str('neat_colors')); + + # check left or right alignment + if (Irssi::settings_get_bool('neat_right_mode') == 0) { + $alignment = \&color_left; + } else { + $alignment = \&color_right; + } + + # check if we switched coloring on or off + my $new = Irssi::settings_get_bool('neat_colorize'); + if ($new != $colorize) { + if ($new) { + Irssi::signal_add('message public', 'sig_public'); + } else { + if ($colorize >= 0) { + Irssi::signal_remove('message public', 'sig_public'); + } + } + } + $colorize = $new; + + reformat(); + &$alignment('%w'); +} + +# make sure that every nick has an assigned color +sub assert_colors() { + foreach (Irssi::channels()) { + foreach ($_->nicks()) { + next if (exists($saved_colors{$_->{nick}})); + + $saved_colors{$_->{nick}} = "%".nick_to_color($_->{nick}); + } + } +} + +# load colors from file +sub load_colors() { + open(FID, "<".$ENV{HOME}."/.irssi/saved_colors") || return; + + while () { + chomp; + my ($k, $v) = split(/:/); + $saved_colors{$k} = $v; + } + + close(FID); +} + +# save colors to file +sub save_colors() { + open(FID, ">".$ENV{HOME}."/.irssi/saved_colors"); + + print FID $_.":".$saved_colors{$_}."\n" foreach (keys(%saved_colors)); + + close(FID); +} + +# log a line to a window item +sub neat_log($@) { + my ($witem, @text) = @_; + + $witem->print("nm.pl: ".$_) foreach(@text); +} + +# show available colors +sub cmd_neatcolor_colors($) { + my ($witem, undef, undef) = @_; + + neat_log($witem, "Available colors: ".join("", map { "%".$_.$_ } @colors)); +} + +# display the configured color for a nick +sub cmd_neatcolor_get() { + my ($witem, $nick, undef) = @_; + + if (!exists($saved_colors{$nick})) { + neat_log($witem, "Error: no such nick '$nick'"); + return; + } + + neat_log($witem, "Color for ".$saved_colors{$nick}.$nick); +} + +# display help +sub cmd_neatcolor_help() { + my ($witem, $cmd, undef) = @_; + + if ($cmd) { + if (!exists($commands{$cmd})) { + neat_log($witem, "Error: no such command '$cmd'"); + return; + } + + if (!exists($commands{$cmd}{verbose})) { + neat_log($witem, "No additional help for '$cmd' available"); + return; + } + + neat_log($witem, ( "", "Help for ".uc($cmd), "" ) ); + neat_log($witem, @{$commands{$cmd}{verbose}}); + return; + } + + neat_log($witem, split(/\n/, $help)); + neat_log($witem, "Available options for /neatcolor"); + neat_log($witem, " ".$_.": ".$commands{$_}{text}) foreach(sort(keys(%commands))); + + my @verbose; + foreach (sort(keys(%commands))) { + push(@verbose, $_) if exists($commands{$_}{verbose}); + } + + neat_log($witem, "Verbose help available for: '".join(", ", @verbose)."'"); +} + +# list configured nicks +sub cmd_neatcolor_list() { + my ($witem, undef, undef) = @_; + + neat_log($witem, "Configured nicks: ".join(", ", map { $saved_colors{$_}.$_ } sort(keys(%saved_colors)))); +} + +# reset a nick to its default color +sub cmd_neatcolor_reset() { + my ($witem, $nick, undef) = @_; + + if (!exists($saved_colors{$nick})) { + neat_log($witem, "Error: no such nick '$nick'"); + return; + } + + $saved_colors{$nick} = "%".nick_to_color($nick); + neat_log($witem, "Reset color for ".$saved_colors{$nick}.$nick); +} + +# save configured colors to disk +sub cmd_neatcolor_save() { + my ($witem, undef, undef) = @_; + + save_colors(); + + neat_log($witem, "color information saved"); +} + +# set a color for a nick +sub cmd_neatcolor_set() { + my ($witem, $nick, $color) = @_; + + my @found = grep(/$color/, @colors); + if ($#found) { + neat_log($witem, "Error: trying to set unknown color '%$color$color%n'"); + cmd_neatcolor_colors($witem); + return; + } + + if ($witem->{type} ne "CHANNEL" && $witem->{type} ne "QUERY") { + neat_log($witem, "Warning: not a Channel/Query, can not check nick"); + } else { + my @nicks = grep(/^$nick$/i, map { $_->{nick} } ($witem->nicks())); + + if ($#nicks < 0) { + neat_log($witem, "Warning: could not find nick '$nick' here"); + } else { + if ($nicks[0] ne $nick) { + neat_log($witem, "Warning: using '$nicks[0]' instead of '$nick'"); + $nick = $nicks[0]; + } + } + } + + $saved_colors{$nick} = "%".$color; + neat_log($witem, "Set color for $saved_colors{$nick}$nick"); +} + +%commands = ( + colors => { + text => "show available colors", + verbose => [ + "COLORS", + "", + "displays all available colors", + "", + "You can restrict/define the list of available colors ". + "with the help of the neat_colors setting" + ], + func => \&cmd_neatcolor_colors, + }, + get => { + text => "retrieve color for a nick", + verbose => [ + "GET ", + "", + "displays color used for " + ], + func => \&cmd_neatcolor_get, + }, + help => { + text => "print this help message", + func => \&cmd_neatcolor_help, + }, + list => { + text => "list configured nick/color pairs", + func => \&cmd_neatcolor_list, + }, + reset => { + text => "reset color to default", + verbose => [ + "RESET ", + "", + "resets the color used for to its internal default" + ], + func => \&cmd_neatcolor_reset, + }, + save => { + text => "save color information to disk", + verbose => [ + "SAVE", + "", + "saves color information to disk, so that it survives ". + "an irssi restart.", + "", + "Color information will be automatically saved on /quit", + ], + func => \&cmd_neatcolor_save, + }, + set => { + text => "set a specific color for a nick", + verbose => [ + "SET ", + "", + "use for ", + "", + "This command will perform a couple of sanity checks, ". + "when called from a CHANNEL/QUERY window", + "", + "EXAMPLE:", + " /neatcolor set bc-bd r", + "", + "use /neatcolor COLORS to see available colors" + ], + func => \&cmd_neatcolor_set, + }, +); + +# the main command callback that gets called for all neatcolor commands +sub cmd_neatcolor() { + my ($data, $server, $witem) = @_; + my ($cmd, $nick, $color) = split (/ /, $data); + + $cmd = lc($cmd); + + # make sure we have a valid witem to print text to + $witem = Irssi::active_win() unless ($witem); + + if (!exists($commands{$cmd})) { + neat_log($witem, "Error: unknown command '$cmd'"); + &{$commands{"help"}{"func"}} if (exists($commands{"help"})); + return; + } + + &{$commands{$cmd}{"func"}}($witem, $nick, $color); +} + +Irssi::settings_add_bool('misc', 'neat_left_messages', 0); +Irssi::settings_add_bool('misc', 'neat_left_actions', 0); +Irssi::settings_add_bool('misc', 'neat_right_mode', 1); +Irssi::settings_add_int('misc', 'neat_maxlength', 0); +Irssi::settings_add_int('misc', 'neat_melength', 2); +Irssi::settings_add_bool('misc', 'neat_colorize', 1); +Irssi::settings_add_str('misc', 'neat_colors', 'rRgGyYbBmMcC'); +Irssi::settings_add_str('misc', 'neat_ignorechars', ''); +Irssi::settings_add_bool('misc', 'neat_allow_shrinking', 1); + +Irssi::command_bind('neatcolor', 'cmd_neatcolor'); + +Irssi::signal_add('nicklist new', 'sig_newNick'); +Irssi::signal_add('nicklist changed', 'sig_changeNick'); +Irssi::signal_add('nicklist remove', 'sig_removeNick'); + +Irssi::signal_add('setup changed', 'sig_setup'); +Irssi::signal_add_last('setup reread', 'sig_setup'); + +findLongestNick(); +sig_setup; + +load_colors(); +assert_colors(); + +# we need to add this signal _after_ the colors have been loaded, to make sure +# no race condition exists wrt color saving +Irssi::signal_add('gui exit', 'save_colors'); diff --git a/repeat.pl b/repeat.pl new file mode 100644 index 0000000..0eb3fc3 --- /dev/null +++ b/repeat.pl @@ -0,0 +1,138 @@ +use Irssi; +use strict; + +use vars qw($VERSION %IRSSI); + +$VERSION="0.1.3"; +%IRSSI = ( + authors=> 'BC-bd', + contact=> 'bd@bc-bd.org', + name=> 'repeat', + description=> 'Hide duplicate lines', + license=> 'GPL v2', + url=> 'https://bc-bd.org/svn/repos/irssi/repeat', +); + +# repeal.pl: ignore repeated messages +# +# for irssi 0.8.5 by bd@bc-bd.org +# +######### +# USAGE +### +# +# This script hides repeated lines from: +# +# dude> Plz Help me!!! +# dude> Plz Help me!!! +# dude> Plz Help me!!! +# guy> foo +# +# Becomes: +# +# dude> Plz Help me!!! +# guy> foo +# +# Or with 'repeat_show' set to ON: +# +# dude> Plz Help me!!! +# Irssi: Message repeated 3 times +# guy> foo +# +######### +# OPTIONS +######### +# +# /set repeat_show +# * ON : show info line: 'Message repeated N times' +# * OFF : don't show it. +# +# /set repeat_count +# N : Display a message N times, then ignore it. +# +### +################ +### +# Changelog +# +# Version 0.1.3 +# - fix: also check before own message (by Wouter Coekaerts) +# +# Version 0.1.2 +# - removed stray debug message (duh!) +# +# Version 0.1.1 +# - off by one fixed +# - fixed missing '$' +# +# Version 0.1.0 +# - initial release +# +my %said; +my %count; + +sub sig_public { + my ($server, $msg, $nick, $address, $target) = @_; + + my $maxcount = Irssi::settings_get_int('repeat_count'); + + my $window = $server->window_find_item($target); + my $refnum = $window->{refnum}; + + my $this = $refnum.$nick.$msg; + + my $last = $said{$refnum}; + my $i = $count{$refnum}; + +# $window->print("'$this' '$last' $i"); + if ($last eq $this and not $nick eq $server->{nick}) { + $count{$refnum} = $i +1; + + if ($i >= $maxcount) { + Irssi::signal_stop(); + } + } else { + if ($i > $maxcount && Irssi::settings_get_bool('repeat_show')) { + $window->print("Message repeated ".($i-1)." times"); + } + + $count{$refnum} = 1; + $said{$refnum} = $this; + } +} + +sub sig_own_public { + my ($server, $msg, $target) = @_; + sig_public ($server, $msg, $server->{nick}, "", $target); +} + +sub remove_window { + my ($num) = @_; + + delete($count{$num}); + delete($said{$num}); +} + +sub sig_refnum { + my ($window,$old) = @_; + my $refnum = $window->{refnum}; + + $count{$refnum} = $count{old}; + $said{$refnum} = $count{old}; + + remove_window($old); +} + +sub sig_destroyed { + my ($window) = @_; + remove_window($window->{refnum}); +} + +Irssi::signal_add('message public', 'sig_public'); +Irssi::signal_add('message own_public', 'sig_own_public'); +Irssi::signal_add_last('window refnum changed', 'sig_refnum'); +Irssi::signal_add_last('window destroyed', 'sig_destroyed'); + +Irssi::settings_add_int('misc', 'repeat_count', 1); +Irssi::settings_add_bool('misc', 'repeat_show', 1); + diff --git a/reslap.pl b/reslap.pl new file mode 100644 index 0000000..49bea13 --- /dev/null +++ b/reslap.pl @@ -0,0 +1,66 @@ +use Irssi; +use Irssi::Irc; +use strict; + +use vars qw($VERSION %IRSSI); + +$VERSION="0.1.0"; +%IRSSI = ( + authors=> 'BC-bd', + contact=> 'bd@bc-bd.org', + name=> 'reslap', + description=> 'Autoreslaps people', + license=> 'GPL v2', + url=> 'https://bc-bd.org/svn/repos/irssi/reslap', +); + +# $Id$ +# for irssi 0.8.5 by bd@bc-bd.org +# +######### +# USAGE +### +# +######### +# OPTIONS +######### +# +### +################ +### +# +# Changelog +# +# Version 0.1.0 +# - initial release +# +### +################ + +sub sig_action() { + my ($server,$msg,$nick,$address,$target) = @_; + + my $window = $server->window_find_item($target); + my $match = "slaps $server->{nick} around a bit with a "; + my $fish = $msg; + + $fish =~ s/\Q$match\E//e; + + if ($fish ne $msg) { + $window->command("/me slaps $nick around a bit with a ".$fish." (autoreslap successfull)"); + return 0; + } + + $match = "drives over $server->{nick}"; + my $jump = $msg; + + $jump =~ s/\Q$match\E//e; + + if ($jump ne $msg) { + $window->command("/me jumps away (autoavoidance successfull)"); + return 0; + } +} + +# "message irc action", SERVER_REC, char *msg, char *nick, char *address, char *target +Irssi::signal_add_last('message irc action', 'sig_action'); diff --git a/rotator.pl b/rotator.pl new file mode 100644 index 0000000..70158f8 --- /dev/null +++ b/rotator.pl @@ -0,0 +1,137 @@ +use Irssi; +use Irssi::TextUI; +use strict; + +use vars qw($VERSION %IRSSI); + +$VERSION="0.2.1"; +%IRSSI = ( + authors=> 'BC-bd', + contact=> 'bd@bc-bd.org', + name=> 'rotator', + description=> 'Displaye a small, changeing statusbar item to show irssi is still running', + license=> 'GPL v2', + url=> 'https://bc-bd.org/svn/repos/irssi/rotator', +); + +# rotator Displaye a small, changeing statusbar item to show irssi is still running +# for irssi 0.8.4 by bd@bc-bd.org +# +######### +# USAGE +### +# +# To use this script type f.e.: +# +# /statusbar window add -after more -alignment right rotator +# +# For more info on statusbars read the docs for /statusbar +# +######### +# OPTIONS +######### +# +# /set rotator_seperator +# The character that is used to split the string in elements. +# +# /set rotator_chars +# The string to display. Examples are: +# +# /set rotator_chars . o 0 O +# /set rotator_chars _ ­ ¯ +# /set rotator_chars %r­ %Y- %g- +# +# /set rotator_speed +# The number of milliseconds to display every char. +# 1 second = 1000 milliseconds. +# +# /set rotator_bounce +# * ON : reverse direction at the end of rotator_chars +# * OFF : start from the beginning +# +### +################ +### +# Changelog +# +# Version 0.2.1 +# - checking rotator_speed to be > 10 +# +# Version 0.2 +# - added rotator_bounce +# - added rotator_seperator +# - added support for elements longer than one char +# - fixed displaying of special chars (thx to peder for pointing this one out) +# +# Version 0.1 +# - initial release +# +### +################ + +my ($pos,$char,$timeout,$boundary,$direction); + +$char = ''; + +sub rotatorTimeout { + my @rot = split(Irssi::settings_get_str('rotator_seperator'), Irssi::settings_get_str('rotator_chars')); + my $len = scalar @rot; + + $char = quotemeta($rot[$pos]); + + if ($pos == $boundary) { + if (Irssi::settings_get_bool('rotator_bounce')) { + if ($direction < 0) { + $boundary = $len -1; + } else { + $boundary = 0; + } + $direction *= -1; + } else { + $pos = -1; + } + } + + $pos += $direction; + + Irssi::statusbar_items_redraw('rotator'); +} + +sub rotatorStatusbar() { + my ($item, $get_size_only) = @_; + + $item->default_handler($get_size_only, "{sb ".$char."}", undef, 1); +} + +sub rotatorSetup() { + my $time = Irssi::settings_get_int('rotator_speed'); + + Irssi::timeout_remove($timeout); + + $boundary = scalar split(Irssi::settings_get_str('rotator_seperator'), Irssi::settings_get_str('rotator_chars')) -1; + $direction = +1; + $pos = 0; + + if ($time < 10) { + Irssi::print("rotator: rotator_speed must be > 10"); + } else { + $timeout = Irssi::timeout_add($time, 'rotatorTimeout' , undef); + } +} + +Irssi::signal_add('setup changed', 'rotatorSetup'); + +Irssi::statusbar_item_register('rotator', '$0', 'rotatorStatusbar'); + +Irssi::settings_add_str('misc', 'rotator_chars', '. o 0 O 0 o'); +Irssi::settings_add_str('misc', 'rotator_seperator', ' '); +Irssi::settings_add_int('misc', 'rotator_speed', 2000); +Irssi::settings_add_bool('misc', 'rotator_bounce', 1); + +if (Irssi::settings_get_int('rotator_speed') < 10) { + Irssi::print("rotator: rotator_speed must be > 10"); +} else { + $timeout = Irssi::timeout_add(Irssi::settings_get_int('rotator_speed'), 'rotatorTimeout' , undef); +} + +rotatorSetup(); diff --git a/thankop.pl b/thankop.pl new file mode 100644 index 0000000..bb87c3d --- /dev/null +++ b/thankop.pl @@ -0,0 +1,134 @@ +use Irssi 0.8.10 (); +use strict; + +use vars qw($VERSION %IRSSI); + +$VERSION="0.1.7"; +%IRSSI = ( + authors=> 'BC-bd', + contact=> 'bd@bc-bd.org', + name=> 'thankop', + description=> 'Remembers the last person oping you on a channel', + license=> 'GPL v2', + url=> 'https://bc-bd.org/svn/repos/irssi/thankop', +); + +# $Id$ # +# +######### +# USAGE +### +# +# Type '/thankop' in a channel window to thank the person opping you +# +########## +# OPTIONS +#### +# +# /set thankop_command [command] +# * command : to be executed. The following $'s are expanded +# $N : Nick (some dude) +# +# eg: +# +# /set thankop_command say $N: w00t! +# +# Would say +# +# : w00t! +# +# To the channel you got op in, with beeing the nick who +# opped you +# +################ +### +# Changelog +# +# Version 0.1.7 +# - fix crash if used in a window != CHANNEL +# - do not thank someone who has already left +# +# Version 0.1.6 +# - added support for multiple networks, thanks to senneth +# - adapted to signal changes in 0.8.10 +# +# Version 0.1.5 +# - change back to setting instead of theme item +# +# Version 0.1.4 +# - added theme item to customize the message (idea from mordeth) +# +# Version 0.1.3 +# - removed '/' from the ->command (thx to mordeth) +# - removed debug messages (where commented out) +# +# Version 0.1.2 +# - added version dependency, since some 0.8.4 users complained about a not +# working script +# +# Version 0.1.1 +# - unsetting of hash values is done with delete not unset. +# +# Version 0.1.0 +# - initial release +# +### +################ + +my %op; + +sub cmd_thankop { + my ($data, $server, $witem) = @_; + + if (!$witem || ($witem->{type} =! "CHANNEL")) { + Irssi::print("thankop: Window not of type CHANNEL"); + return; + } + + my $tag = $witem->{server}->{tag}.'/'.$witem->{name}; + + # did we record who opped us here + if (!exists($op{$tag})) { + $witem->print("thankop: I don't know who op'ed you in here"); + return; + } + + my $by = $op{$tag}; + + # still here? + if (!$witem->nick_find($by)) { + $witem->print("thankop: $by already left"); + return; + } + + my $cmd = Irssi::settings_get_str('thankop_command'); + + $cmd =~ s/\$N/$by/; + $witem->command($cmd); +} + +sub mode_changed { + my ($channel, $nick, $by, undef, undef) = @_; + + return if ($channel->{server}->{nick} ne $nick->{nick}); + + # since 0.8.10 this is set after signals have been processed + return if ($channel->{chanop}); + + my $tag = $channel->{server}->{tag}.'/'.$channel->{name}; + + $op{$tag} = $by; +} + +sub channel_destroyed { + my ($channel) = @_; + + my $tag = $channel->{server}->{tag}.'/'.$channel->{name}; + + delete($op{$tag}); +} + +Irssi::command_bind('thankop','cmd_thankop'); +Irssi::signal_add_last('nick mode changed', 'mode_changed'); + +Irssi::settings_add_str('thankop', 'thankop_command', 'say $N: opthx');