add irssi scripts

This commit is contained in:
xfnw 2022-01-12 17:51:28 -05:00
parent 2fef6bb84c
commit 8a61f16543
12 changed files with 2746 additions and 6 deletions

View File

@ -157,6 +157,9 @@ aliases = {
rainbow = "exec -o toilet --irc --gay -f term -- $";
nn = "window number";
move = "window move";
kline = "quote kline";
gline = "quote gline";
challenge = "quote challenge";
};
settings = {
@ -214,16 +217,14 @@ hilights = (
text = "xfnw";
color = "%G";
act_color = "%Y";
nick = "no";
word = "no";
regexp = "yes";
word = "yes";
full = "yes";
},
{
text = "vulpine";
color = "%G";
act_color = "%Y";
nick = "no";
word = "no";
regexp = "yes";
word = "yes";
full = "yes";
}
);

View File

@ -0,0 +1,39 @@
use strict;
use vars qw($VERSION %IRSSI);
$VERSION = '0.02';
%IRSSI = (
authors => 'Juerd',
contact => '#####@juerd.nl',
name => 'autostuff',
description => 'Save current servers, channels and windows for autoconnect and autojoin',
license => 'Public Domain',
url => 'http://juerd.nl/site.plp/irssi',
changed => '2010-03-24 14:35',
);
use Irssi qw(command_bind servers channels windows command);
command_bind autostuff => sub {
my ($data, $server, $window) = @_;
for (servers) {
my $chatnet = $_->{chatnet} || $_->{tag};
command "/network add $chatnet";
command "/server add -auto -network $chatnet $_->{address} $_->{port} $_->{password}";
}
for (channels) {
my $chatnet = $_->{server}->{chatnet} || $_->{server}->{tag};
command "/channel add -auto $_->{name} $chatnet $_->{key}";
}
command "/layout save";
command "/save";
};
command_bind "window clean" => sub {
for (sort { $b->{refnum} <=> $a->{refnum} } windows) {
next if $_->{active};
next if $_->{immortal};
next if $_->{name};
command "/window close $_->{refnum}";
}
};

View File

@ -0,0 +1,54 @@
use strict;
use warnings;
use Irssi;
our $VERSION = '0.0.1';
our %IRSSI = (
authors => 'launchd',
contact => 'me@zpld.me',
name => 'chghost',
description => 'implement support for https://ircv3.net/specs/extensions/chghost.html',
license => 'MIT',
changed => '5/20/2021'
);
Irssi::theme_register([
chghost => '{channick_hilight $0} {nickhost $1} has changed hostname to {hilight $2}',
]);
Irssi::signal_add('event chghost', sub {
my ($server, $data, $nick, $oldhost) = @_;
my @parts = split m/ /, $data;
my $newhost = "$parts[0]\@$parts[1]";
# Print the notification to all shared channels, and the nick's query if any
for my $c ($server->channels) {
$c->printformat(MSGLEVEL_NICKS, 'chghost', $nick, $oldhost, $newhost) if $c->nick_find($nick);
}
my $q = $server->query_find($nick);
$q->printformat(MSGLEVEL_NICKS, 'chghost', $nick, $oldhost, $newhost) if defined $q;
Irssi::signal_stop();
});
Irssi::signal_add('event connected', sub {
my ($server) = @_;
if ($server->{chat_type} eq 'IRC')
{
$server->irc_server_cap_toggle('chghost', 1);
}
});
if (!Irssi::Irc::Server->can('irc_server_cap_toggle')) {
die 'this version of irssi is not supported';
}
for my $server (Irssi::servers()) {
if ($server->{chat_type} eq 'IRC')
{
$server->irc_server_cap_toggle('chghost', 1);
}
}

View File

@ -0,0 +1,85 @@
#
# Print hilighted messages & private messages to window named "hilight" for
# irssi 0.7.99 by Timo Sirainen
#
# Modded a tiny bit by znx to stop private messages entering the hilighted
# window (can be toggled) and to put up a timestamp.
#
# Changed a little by rummik to optionally show network name. Enable with
# `/set hilightwin_show_network on`
#
use strict;
use Irssi;
use POSIX;
use vars qw($VERSION %IRSSI);
$VERSION = "1.00";
%IRSSI = (
authors => "Timo \'cras\' Sirainen, Mark \'znx\' Sangster, Kimberly \'rummik\' Zick",
contact => "tss\@iki.fi, znxster\@gmail.com, git\@zick.kim",
name => "hilightwin",
description => "Print hilighted messages to window named \"hilight\"",
license => "Public Domain",
url => "http://irssi.org/",
changed => "Thu Apr 6 15:30:25 EDT 2017"
);
sub is_ignored {
my ($dest) = @_;
my @ignore = split(' ', Irssi::settings_get_str('hilightwin_ignore_targets'));
return 0 if (!@ignore);
my %targets = map { $_ => 1 } @ignore;
return 1 if exists($targets{"*"});
return 1 if exists($targets{$dest->{target}});
if ($dest->{server}) {
my $tag = $dest->{server}->{tag};
return 1 if exists($targets{$tag . "/*"});
return 1 if exists($targets{$tag . "/" . $dest->{target}});
}
return 0;
}
sub sig_printtext {
my ($dest, $text, $stripped) = @_;
my $opt = MSGLEVEL_HILIGHT;
my $shownetwork = Irssi::settings_get_bool('hilightwin_show_network');
if(Irssi::settings_get_bool('hilightwin_showprivmsg')) {
$opt = MSGLEVEL_HILIGHT|MSGLEVEL_MSGS;
}
if(
($dest->{level} & ($opt)) &&
($dest->{level} & MSGLEVEL_NOHILIGHT) == 0 &&
(!is_ignored($dest))
) {
my $window = Irssi::window_find_name('hilight');
if ($dest->{level} & MSGLEVEL_PUBLIC) {
$text = $dest->{target}.": ".$text;
$text = $dest->{server}->{tag} . "/" . $text if ($shownetwork);
} elsif ($shownetwork) {
$text = $dest->{server}->{tag} . ": " . $text;
}
$text =~ s/%/%%/g;
$window->print($text, MSGLEVEL_CLIENTCRAP) if ($window);
}
}
my $window = Irssi::window_find_name('hilight');
Irssi::print("Create a window named 'hilight'") if (!$window);
Irssi::settings_add_bool('hilightwin','hilightwin_showprivmsg',1);
Irssi::settings_add_str('hilightwin', 'hilightwin_ignore_targets', '');
Irssi::settings_add_bool('hilightwin','hilightwin_show_network', 0);
Irssi::signal_add('print text', 'sig_printtext');
# vim:set ts=4 sw=4 et:

View File

@ -0,0 +1,671 @@
use Irssi;
use strict;
use warnings;
use bignum;
use Socket;
use vars qw($VERSION %IRSSI);
%IRSSI =
(
name => "isbanned",
description => "freenode-specific script that checks whether someone is banned on some channel",
commands => "isbanned ismuted islisted isreset",
authors => "mniip",
contact => "mniip \@ freenode",
license => "Public domain",
modified => "2015-09-14"
);
$VERSION = "0.7.0";
# Commands:
# /isbanned <channel> <user>
# Check whether <user> is banned on <channel>
# /ismuted <channel> <user>
# Check whether <user> is muted on <channel>
# /islisted <channel> <mode> <user>
# Check whether <user> is listed in <channel>'s
# <mode> list (can be b, q, e, or I)
# /isreset
# If something screws up, this resets the state to inactive
#
# <user> can either be a nickname, or a hostmask in the form
# nick!ident@host#gecos$account
# where some parts can be omitted. Strictly speaking the form is
# [nick] ['!' ident] ['@' host] ['#' gecos] ['$' account]
# If any part is omitted, it is assumed to be empty string, except for
# account: if the account part is omitted the user is assumed to be
# unidentified (as opposed to identified as empty string)
#
# Supports all kinds of features, misfeatures, and quirks freenode uses.
# Supports $a, $j, $r, $x, and $z extbans, and any edge cases of those.
# Supports CIDR bans, both IPv4 and IPv6, and the misfeature by which
# an invalid IP address is not parsed and zeroes are matched instead.
# Supports the +ikmrS modes. Supports the RFC2812 casemapping in patterns,
# which are, by the way, parsed without backtracking and thus effeciently.
#
# Changelog:
# 0.6.0 (2015.01.12)
# Ported from the hexchat script version 0.6
#
# 0.6.1 (2015.01.13)
# Fixed a few porting issues: the original host is now included
# in the hosts list too. Fixed IPv6 parsing. Fixed $x and $~x.
#
# 0.6.2 (2015.01.13)
# Fixed a few warnings.
#
# 0.6.3 (2015.01.16)
# Improve command argument parsing. Display usage on incorrect use.
# Support multiple modes at once in islisted.
#
# 0.6.4 (2015.03.22)
# Fix translation from python: fix bans containing the letter Z not matching
#
# 0.7.0 (2015.09.14)
# Support trailing characters in CIDR bans.
my $active = 0;
my $user;
my $channel;
my $orig_list;
my $modes;
my @whois;
my $lists_left;
my @bans;
sub parse_ipv6_word
{
my ($w) = @_;
return hex $w if $w =~ /^0*[0-9a-fA-F]{1,4}$/;
die "Invalid IPv6 word";
}
sub parse_ip
{
my ($ip, $strict) = @_;
if($ip =~ /:/)
{
if($ip =~ /::/)
{
my $edge = ($ip =~ /::$/) || ($ip =~ /^::/);
$ip = $ip . "0" if $ip =~ /::$/;
$ip = "0" . $ip if $ip =~ /^::/;
my ($head, $tail) = split /::/, $ip, 2;
my @headwords = split /:/, $head, 8;
my @tailwords = split /:/, $tail, 8;
if(@headwords + @tailwords <= ($edge ? 8 : 7))
{
my $result;
eval
{
@headwords = map { parse_ipv6_word($_) } @headwords;
@tailwords = map { parse_ipv6_word($_) } @tailwords;
my @words = (@headwords, (0) x (8 - @headwords - @tailwords), @tailwords);
$result = 0;
for(my $i = 0; $i < 8; $i++)
{
$result |= $words[$i] << ((7 - $i) * 16);
}
};
return $result if defined $result;
}
}
else
{
my @words = split /:/, $ip, 8;
if(scalar @words == 8)
{
my $result;
eval
{
@words = map { parse_ipv6_word($_) } @words;
$result = 0;
for(my $i = 0; $i < 8; $i++)
{
$result |= $words[$i] << ((7 - $i) * 16);
}
};
return $result if defined $result;
}
}
die "Invalid IPv6" if $strict;
return 0;
}
else
{
if($ip =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)
{
my ($o1, $o2, $o3, $o4) = (0 + $1, 0 + $2, 0 + $3, 0 + $4);
return $o1 << 24 | $o2 << 16 | $o3 << 8 | $o4
if $o1 < 256 && $o2 < 256 && $o3 < 256 && $o4 < 256;
}
die "Invalid IPv4" if $strict;
return 0;
}
}
my %char_classes =
(
"[" => "[\[{]",
"{" => "[{\[]",
"|" => "[|\\]",
"\\" => "[\\|]",
"]" => "[\]}]",
"}" => "[}\]]",
"~" => "[~^]",
"?" => "."
);
$char_classes{$_} = $_ foreach split //, '-_`^0123456789';
for(my $c = 0; $c <= 25; $c++)
{
my $lc = chr($c + ord "a");
my $uc = chr($c + ord "A");
$char_classes{$lc} = "[$lc$uc]";
$char_classes{$uc} = "[$uc$lc]";
}
sub match_pattern
{
my ($string, $pattern) = @_;
$string = "" if !defined $string;
$pattern =~ s|[?*]+|"?" x ($& =~ tr/?/?/) . ($& =~ /\*/ ? "*" : "")|ge;
my $last_pos = 0;
my @pieces = split /\*/, $pattern;
push @pieces, "" if $pattern =~ /\*$/;
push @pieces, "" if $pattern eq "*";
for(my $i = 0; $i < scalar @pieces; $i++)
{
my $regex = "";
$regex .= "^" if !$i;
$regex .= defined $char_classes{$_} ? $char_classes{$_} : "\\$_" for split //, $pieces[$i];
$regex .= "\$" if $i == $#pieces;
if((substr $string, $last_pos) =~ qr/$regex/)
{
$last_pos += $+[0];
}
else
{
return 0;
}
}
return 1;
}
my @found_modes;
sub add_ban
{
push @found_modes, "\x0302$_[1] $_[0]\x0F in \x0306$_[2]\x0F set by \x0310$_[3]\x0F on \x0308" . (scalar localtime $_[4]) . "\x0F";
}
sub analyze
{
$active = 0;
my ($nick, $ident, $host, $gecos, $account, $ssl) = @whois;
@found_modes = ();
my @hostile_modes = ();
for my $c(split //, $modes)
{
push @hostile_modes, $c if $orig_list eq "b" && ($c eq "i" || ($c eq "r" && !$account) || ($c eq "S" && !$ssl));
push @hostile_modes, $c if $orig_list eq "q" && ($c eq "m" || ($c eq "r" && !$account));
}
push @found_modes, ("\x0302+" . join("", @hostile_modes) . "\x0F in \x0306$channel\x0F") if(@hostile_modes);
for my $b(@bans)
{
my ($ban) = split /(?<!^)\$/, $b->[0], 2;
if($ban =~ /^\$/)
{
add_ban(@$b) if $ban eq '$a' && $account;
if($ban =~ /^\$a:(.*)$/)
{
add_ban(@$b) if $account && nick_eq($account, $1);
}
add_ban(@$b) if $ban eq '$~a' && !$account;
if($ban =~ /^\$~a:(.*)$/)
{
add_ban(@$b) if !$account || !nick_eq($account, $1);
}
add_ban(@$b) if $ban =~ /^\$~j:/;
if($ban =~ /^\$r:(.*)$/)
{
add_ban(@$b) if match_pattern($gecos, $1);
}
if($ban =~ /^\$~r:(.*)$/)
{
add_ban(@$b) if !match_pattern($gecos, $1);
}
if($ban =~ /^\$x:(.*)$/)
{
for my $h(@$host)
{
if(match_pattern("$nick!$ident\@$h#$gecos", $1))
{
add_ban(@$b);
last;
}
}
}
if($ban =~ /^\$~x:(.*)$/)
{
my $found = 0;
for my $h(@$host)
{
if(match_pattern("$nick!$ident\@$h#$gecos", $1))
{
$found = 1;
last;
}
}
add_ban(@$b) if !$found;
}
add_ban(@$b) if $ban eq '$z' && $ssl;
add_ban(@$b) if $ban eq '$~z' && !$ssl;
}
else
{
my ($v, $bhost) = split /@/, $ban, 2;
my ($bnick, $bident) = split /!/, $v, 2;
if(match_pattern($nick, $bnick) && match_pattern($ident, $bident))
{
my $found = 0;
for my $h(@$host)
{
if(match_pattern($h, $bhost))
{
$found = 1;
add_ban(@$b);
last;
}
}
if(!$found)
{
my ($ip, $width) = split /\//, $bhost, 2;
if(defined $width)
{
$width =~ s/^([0-9]*).*/$1/g;
$width = int("0" . $width);
if($width > 0)
{
my $is_v4 = !($ip =~ /:/);
$width = ($is_v4 ? 32 : 128) - $width;
$width = 0 if $width < 0;
$ip = parse_ip($ip);
for my $h(@$host)
{
if(!($h =~ /:/) == $is_v4)
{
my $last;
eval
{
my $h = parse_ip($h, 1);
if(($ip >> $width) == ($h >> $width))
{
add_ban(@$b);
$last = 1;
}
};
last if $last;
}
}
}
}
}
} # omg so many }
}
}
if(@found_modes)
{
if($orig_list eq "b")
{
Irssi::print("The following are preventing \x0310$user\x0F from joining \x0306$channel\x0F:");
}
elsif($orig_list eq "q")
{
Irssi::print("The following are preventing \x0310$user\x0F from speaking in \x0306$channel\x0F:");
}
else
{
Irssi::print("The following \x0302+$orig_list\x0F modes affect \x0310$user\x0F in \x0306$channel\x0F:");
}
Irssi::print($_) for(@found_modes);
}
else
{
if($orig_list eq "b")
{
Irssi::print("Nothing is preventing \x0310$user\x0F from joining \x0306$channel\x0F");
}
elsif($orig_list eq "q")
{
Irssi::print("Nothing is preventing \x0310$user\x0F from speaking in \x0306$channel\x0F");
}
else
{
Irssi::print("No \x0302+$orig_list\x0F modes affect \x0310$user\x0F in \x0306$channel\x0F");
}
}
}
sub reset
{
$active = 0;
}
sub lookup_host
{
my ($host) = @_;
$host = "" if !defined $host;
Irssi::print("\x0302Resolving <$host>");
my @addresses = gethostbyname($host);
if(@addresses)
{
@addresses = map { inet_ntoa($_) } @addresses[4 .. $#addresses];
my %seen;
@addresses = grep { !$seen{$_}++ } (@addresses, $host);
Irssi::print("\x0302IPs: <@addresses>");
return @addresses;
}
else
{
Irssi::print("\x0302Found nothing, will use <$host>");
return $host;
}
}
sub query_list
{
my ($server, $channel, $mode) = @_;
$server->command("quote MODE $channel");
for my $m(split //, $mode)
{
$lists_left++;
$server->command("quote MODE $channel $m");
}
}
sub query_whois
{
my ($server, $nick) = @_;
$nick =~ s/\s+//g;
$server->command("quote WHOIS $nick");
}
sub ignored
{
Irssi::signal_stop() if $active;
}
sub nick_eq
{
my ($n1, $n2) = @_;
$n1 = lc $n1;
$n1 =~ tr/[]\\/{}|/;
$n2 = lc $n2;
$n2 =~ tr/[]\\/{}|/;
return $n1 eq $n2;
}
sub modes
{
if($active)
{
my ($server, $data, $nick, $address) = @_;
my @w = split / /, $data;
Irssi::print("\x0302Channel $w[1] is +s, report may be incomplete") if $w[2] =~ /s/;
if(nick_eq($w[1], $channel))
{
$modes = $w[2];
analyze() if !$lists_left && @whois;
}
Irssi::signal_stop();
}
}
sub list_entry_b { list_entry("+b", @_); }
sub list_entry_q { list_entry("+q", @_); }
sub list_entry_I { list_entry("+I", @_); }
sub list_entry_e { list_entry("+e", @_); }
sub list_entry
{
if($active)
{
my ($u, $server, $data, $nick, $address) = @_;
my @w = split / /, $data;
splice @w, 2, 1 if $u eq "+q";
if(nick_eq($w[1], $channel) && $w[2] =~ /^\$j:(.*)$/)
{
query_list($server, $1 =~ s/\$.*$//r, "b")
}
else
{
push @bans, [$w[2], $u, $w[1], $w[3], $w[4]];
}
Irssi::signal_stop();
}
}
sub list_end
{
if($active)
{
$lists_left--;
analyze() if !$lists_left && @whois && $modes;
Irssi::signal_stop();
}
}
sub no_modes
{
if($active)
{
Irssi::print("\x0304Attempted to get modes for a nickname, did you put the arguments in the wrong order?");
if(!$modes)
{
$modes = "+";
}
else
{
$lists_left--;
analyze() if !$lists_left && @whois;
}
Irssi::signal_stop();
}
}
sub mode_error
{
if($active)
{
Irssi::print("\x0304Something went wrong with the modes, report may be incomplete");
if(!$modes)
{
$modes = "+";
analyze() if !$lists_left && @whois;
}
else
{
$lists_left--;
analyze() if !$lists_left && @whois;
}
Irssi::signal_stop();
}
}
sub no_list
{
if($active)
{
my ($server, $data, $nick, $address) = @_;
my @w = split / /, $data;
Irssi::print("\x0304Could not obtain modes for $w[1], report may be incomplete");
if(nick_eq($w[1], $channel) && !$modes)
{
$modes = "+";
analyze() if !$lists_left && @whois;
}
else
{
$lists_left--;
analyze() if !$lists_left && @whois && $modes;
}
Irssi::signal_stop();
}
}
my @wh;
my $ac;
my $ssl;
sub whois_start
{
if($active)
{
my ($server, $data, $nick, $address) = @_;
my @w = split / /, $data;
@wh = ($w[1], $w[2], [lookup_host($w[3])], substr((join " ", @w[5 .. $#w]), 1));
undef $ac;
undef $ssl;
Irssi::signal_stop();
}
}
sub whois_ssl
{
if($active)
{
$ssl = 1;
Irssi::signal_stop();
}
}
sub whois_account
{
if($active)
{
my ($server, $data, $nick, $address) = @_;
my @w = split / /, $data;
$ac = $w[2];
Irssi::signal_stop();
}
}
sub whois_end
{
if($active)
{
my ($server, $data, $nick, $address) = @_;
if(@wh)
{
@whois = (@wh, $ac, $ssl);
@wh = ();
analyze() if !$lists_left && $modes;
}
else
{
Irssi::print("\x0304Whois failed, aborting!");
$active = 0;
}
Irssi::signal_stop();
}
}
sub start_search
{
my ($server, $ch, $u, $mode) = @_;
@whois = ();
$orig_list = $mode;
$channel = $ch;
$user = $u;
if($user =~ /[!@#\$]/)
{
my ($account, $rname, $host, $nick, $ident, $v);
($v, $account) = split /\$/, $user, 2;
($v, $rname) = split /#/, $v, 2;
($v, $host) = split /@/, $v, 2;
($nick, $ident) = split /!/, $v, 2;
@whois = ($nick, $ident, [lookup_host($host)], $rname, $account, 0);
}
undef $modes;
$lists_left = 0;
@bans = ();
$active = 1;
query_list($server, $channel, $mode);
query_whois($server, $user) if !@whois;
}
sub isbanned
{
my ($arg, $server, $witem) = @_;
if($arg =~ /^\s*(\S+)\s+(.*\S)\s*/)
{
my $chan = $1;
my $user = $2;
return start_search($server, $chan, $user, "b") if $chan ne "" && $user ne "";
}
Irssi::print("Usage: /isbanned <channel> <user>");
}
sub ismuted
{
my ($arg, $server, $witem) = @_;
my ($chan, $user) = split / /, $arg, 2;
if($arg =~ /^\s*(\S+)\s+(.*\S)\s*/)
{
my $chan = $1;
my $user = $2;
if($chan ne "" && $user ne "")
{
start_search($server, $chan, $user, "q");
query_list($server, $chan, "b");
return;
}
}
Irssi::print("Usage: /ismuted <channel> <user>");
}
sub islisted
{
my ($arg, $server, $witem) = @_;
my ($chan, $mode, $user) = split / /, $arg, 3;
if($arg =~ /^\s*(\S+)\s+(\S+)\s+(.*\S)\s*/)
{
my $chan = $1;
my $mode = $2;
my $user = $3;
$mode =~ s/\+//g;
return start_search($server, $chan, $user, $mode) if $chan ne "" && $mode ne "" && $user ne "";
}
Irssi::print("Usage: /islisted <channel> <mode> <user>");
}
Irssi::signal_add("event 329", \&ignored);
Irssi::signal_add("event 276", \&ignored);
Irssi::signal_add("event 317", \&ignored);
Irssi::signal_add("event 378", \&ignored);
Irssi::signal_add("event 319", \&ignored);
Irssi::signal_add("event 312", \&ignored);
Irssi::signal_add("event 324", \&modes);
Irssi::signal_add("event 367", \&list_entry_b);
Irssi::signal_add("event 728", \&list_entry_q);
Irssi::signal_add("event 346", \&list_entry_I);
Irssi::signal_add("event 348", \&list_entry_e);
Irssi::signal_add("event 368", \&list_end);
Irssi::signal_add("event 729", \&list_end);
Irssi::signal_add("event 347", \&list_end);
Irssi::signal_add("event 349", \&list_end);
Irssi::signal_add("event 502", \&no_modes);
Irssi::signal_add("event 221", \&no_modes);
Irssi::signal_add("event 472", \&mode_error);
Irssi::signal_add("event 501", \&mode_error);
Irssi::signal_add("event 403", \&no_list);
Irssi::signal_add("event 482", \&no_list);
Irssi::signal_add("event 311", \&whois_start);
Irssi::signal_add("event 671", \&whois_ssl);
Irssi::signal_add("event 330", \&whois_account);
Irssi::signal_add("event 318", \&whois_end);
Irssi::command_bind("isbanned", \&isbanned);
Irssi::command_bind("ismuted", \&ismuted);
Irssi::command_bind("islisted", \&islisted);
Irssi::command_bind("isreset", \&reset);

View File

@ -0,0 +1,51 @@
use strict;
use vars qw($VERSION %IRSSI);
use Irssi 20020120;
$VERSION = "0.03";
%IRSSI = (
authors => "c0ffee",
contact => "c0ffee\@penguin-breeder.org",
name => "List nicks in channel",
description => "Use /ls <regex> to show all nicks (including ident\@host) matching regex in the current channel",
license => "Public Domain",
url => "http://www.penguin-breeder.org/irssi/",
changed => "Sun Sep 17 06:31 CEST 2017",
);
sub cmd_ls {
my ($data, $server, $channel) = @_;
if ($channel->{type} ne "CHANNEL") {
Irssi::print("You are not on a channel");
return;
}
$channel->print("--- Search results:");
my @nicks = $channel->nicks();
my $re = eval { qr/$data/i };
if (not $re) {
chomp $@;
$channel->print("Invalid regex pattern:\n$@");
return;
}
my $found;
foreach my $nick (@nicks) {
my $n = $nick->{nick} . "!" . $nick->{host};
if ($n =~ $re) {
$channel->print($n);
$found = 1;
}
}
if (not $found) {
$channel->print("No matches");
}
}
Irssi::command_bind('ls','cmd_ls');

View File

@ -0,0 +1,114 @@
#
# Usage: /MKICK [options] [mode] [mask] [reason]
# Options:
# -n normal kick
# -6 '2+4' kickmethod
# Mode:
# -a all on channel
# -o chops
# -v chvoices
# -d users without op
# -l users without op and voice
# Settings.
# /SET masskick_default_reason [reason]
# /SET masskick_default_use_6method [On/Off]
#
use strict;
use Irssi;
use Irssi::Irc;
use vars qw($VERSION %IRSSI);
$VERSION = "0.9";
%IRSSI = (
authors => 'Marcin Rozycki',
contact => 'derwan@irssi.pl',
name => 'mkick',
description => 'Masskick, usage: /mkick [-aovdln6 (hostmask)] <[:]reason>',
license => 'GNU GPL v2',
url => 'http://derwan.irssi.pl',
changed => 'Wed Oct 6 20:58:38 CEST 2004'
);
Irssi::theme_register([
'mkick_not_connected', 'Mkick: Not connected to server',
'mkick_not_chanwin', 'Mkick: Not joined to any channel',
'mkick_not_chanop', 'Mkick: You\'re not channel operator on {hilight $0}',
'mkick_syntax', 'Mkick: $0, use: /MKICK [-a|-o|-v|-d|-l] [-n|-6] (mask) [reason]',
'mkick_no_users', '%_Mkick:%_ No users matching given criteria',
'mkick_kicklist', '%_Mkick:%_ Send masskick for $1 users on $0: $2-'
]);
sub cmd_mkick
{
my ($args, $server, $witem) = @_;
Irssi::printformat(MSGLEVEL_CRAP, "mkick_not_connected"), return if (!$server or !$server->{connected});
Irssi::printformat(MSGLEVEL_CRAP, "mkick_not_chanwin"), return if (!$witem or $witem->{type} !~ /^channel$/i);
Irssi::printformat(MSGLEVEL_CRAP, "mkick_not_chanop", $witem->{name}), return if (!$witem->{chanop});
my $reason = Irssi::settings_get_str("masskick_default_reason");
my $method = Irssi::settings_get_bool("masskick_default_use_6method");
my $servernick = $server->{nick};
my $channel = $witem->{name};
my $mode = undef;
my $mask = "*!*\@*";
my @kicklist = ();
my @nicklist = ();
my @args = split(/ +/, $args);
while ($_ = shift(@args))
{
/^..*!..*@..*$/ and $mask = "$&", next;
/^-(a|o|v|d|l)$/ and s/-//, $mode = $_, next;
/^-(n|6)$/ and $method = $_ =~ s/6//, next;
/^-/ and Irssi::printformat(MSGLEVEL_CRAP, "mkick_syntax", "Unknown argument: $_"), return;
/^:/ and s/^://;
$reason = ($#args >= 0) ? $_." ".join(" ", @args) : $_;
last;
};
unless ($mode) {
Irssi::printformat(MSGLEVEL_CRAP, "mkick_syntax", "Missing argument"), return if ($mask eq '*!*@*');
$mode = "a";
};
foreach my $hash ($witem->nicks())
{
my $nick = $hash->{nick};
next if ($nick eq $servernick or !$server->mask_match_address($mask, $nick, $hash->{host}));
my $isop = $hash->{op};
my $isvoice = $hash->{voice};
if ($mode eq "a" or
$mode eq "o" && $isop or
$mode eq "v" && $isvoice && !$isop or
$mode eq "d" && !$isop or
$mode eq "l" && !$isop && !$isvoice) {
push(@kicklist, $nick);
my $mod = ($isop == 1) ? "\@" : ($isvoice == 1) ? "+" : undef;
push(@nicklist, $mod.$nick);
};
};
Irssi::printformat(MSGLEVEL_CRAP, "mkick_no_users", $mask, $mode), return if ($#kicklist < 0);
Irssi::printformat(MSGLEVEL_CRAP, "mkick_kicklist", $channel, scalar(@nicklist), @nicklist);
if ($method > 0) {
$reason = substr($reason, 0, 15) if (length($reason) > 15);
while (@kicklist) {
$server->send_raw("KICK $channel ".join(",", @kicklist[0 .. $method])." :$reason");
@kicklist = @kicklist[($method + 1)..$#kicklist];
$method = ($method == 3 && $#kicklist > 3) ? 1 : 3;
};
} else {
$server->send_raw_split("KICK $channel ".join(",", @kicklist)." :$reason", 2, $server->{max_kicks_in_cmd});
};
};
Irssi::settings_add_str("misc", "masskick_default_reason", "Irssi BaBy!");
Irssi::settings_add_bool("misc", "masskick_default_use_6method", 0);
Irssi::command_bind("mkick", "cmd_mkick");

View File

@ -0,0 +1,153 @@
# modelist.pl v 0.7.2 by Marcin Rozycki (derwan@irssi.pl) changed at Sat Jun 5 22:38:59 CEST 2004
#
# Usage:
# /se
# /si
# /unexcept [index] ( ex. /unexcept 1 5 17)
# /uninvite [index] ( ex. /uninvite 3 8)
#
use strict;
use Irssi 20020600 ();
use Irssi::Irc;
use vars qw($VERSION %IRSSI);
$VERSION = "0.7.2";
%IRSSI = (
authors => 'Marcin Rozycki',
contact => 'derwan@irssi.pl',
name => 'modelist',
description => 'Cache of invites and ban exceptions in channel. Usage: /si, /se, '.
'/unexcept [indexes], /uninvite [indexes]',
license => 'GNU GPL v2',
url => 'http://derwan.irssi.pl',
changed => 'Sat Jun 5 22:38:59 CEST 2004'
);
Irssi::theme_register([
'modelist', '$0 - {hilight $1}: $2 %c$3%n $4'
]);
my %modelist = ();
sub channel_create
{
my ($server, $channel) = (@_[0], lc($_[1]));
delete $modelist{lc($server->{tag})}{$channel};
$server->redirect_event("mode I", 1, "$channel", 0, undef, {
'event 346' => 'redir modelist invite',
'' => 'event empty' });
$server->send_raw("MODE $channel I");
$server->redirect_event("mode e", 1, "$channel", 0, undef, {
'event 348' => 'redir modelist except',
'' => 'event empty' });
$server->send_raw("MODE $channel e");
}
sub sig_channel_created
{
channel_create($_[0]->{server}, $_[0]->{name}) unless ($_[0]->{no_modes});
}
sub sig_redir_modelist_invite
{
my ($nick, $chan, $mode) = split(/ +/, $_[1], 3);
message_irc_mode($_[0], $chan, undef, undef, "+I $mode");
}
sub sig_redir_modelist_except
{
my ($nick, $chan, $mode) = split(/ +/, $_[1], 3);
message_irc_mode($_[0], $chan, undef, undef, "+e $mode");
}
sub message_irc_mode
{
my ($mode, @args) = split(/ +/, $_[4]);
return unless $_[0]->ischannel($_[1]);
my ($tag, $chan, $mod) = (lc($_[0]->{tag}), lc($_[0]->channel_find($_[1])->{name}), "+");
foreach ( split //, $mode )
{
/([+-])/ and $mod = $_, next;
my $arg = ( $mod eq '+' && $_ =~ m/[beIkloRvh]/ or $mod eq '-' && $_ =~ m/[beIkoRvh]/ ) ? shift(@args) : undef;
next unless ( $_ =~ m/[eI]/ );
( $mod eq '+' ) and push(@{$modelist{$tag}{$chan}{$_}}, [$arg, $_[2], time]), next;
for (my $idx = 0; $idx <= $#{$modelist{$tag}{$chan}{$_}}; $idx++) {
splice(@{$modelist{$tag}{$chan}{$_}}, $idx, 1) if ($modelist{$tag}{$chan}{$_}[$idx][0] eq $arg);
}
}
}
sub proc_modelist_show
{
my ($arg, $server, $channel, $list, $mode) = @_;
Irssi::print("You\'re not connected to server"), return unless ($server and $server->{connected});
$arg =~ s/\s.*//;
if ($arg) {
Irssi::print("Bad channel name: $arg"), return unless ($server->ischannel($arg));
unless ($channel = $server->channel_find($arg)) {
Irssi::print("You\'re not in channel $arg --> sending request to server");
$server->send_raw("MODE $arg $list");
return;
}
}
Irssi::print("Not joined to any channel"), return unless ($channel and $channel->{type} eq "CHANNEL");
Irssi::print("Channel not fully synchronized yet, try again after a while"), return unless ($channel->{synced});
Irssi::print("Channel doesn\'t support modes"), return if ($channel->{no_modes});
my ($tag, $name) = (lc($server->{tag}), $channel->{name});
my $chan = lc($name);
my $items = $#{$modelist{$tag}{$chan}{$list}};
Irssi::print("No $mode\s in channel %_$name%_"), return if ($items < 0);
for (my $idx = 0; $idx <= $items; $idx++)
{
my ($mask, $who) = ($modelist{$tag}{$chan}{$list}[$idx]->[0], $modelist{$tag}{$chan}{$list}[$idx]->[1]);
$mask =~ tr/\240\002\003\037\026/\206\202\203\237\226/;
my $setby = ($who) ? "\00314[\003by \002$who\002, ".(time - $modelist{$tag}{$chan}{$list}[$idx]->[2])." secs ago\00314]\003" : undef;
$channel->printformat(MSGLEVEL_CRAP, 'modelist', ($idx+1), $name, $mode, $mask, $setby);
}
}
sub cmd_si { proc_modelist_show @_, "I", "invite"; }
sub cmd_se { proc_modelist_show @_, "e", "ban exception"; }
sub cmd_modelist {
my ( $type, $data, $server, $witem) = @_;
Irssi::print("You\'re not connected to server"), return unless ($server and $server->{connected});
Irssi::print("Not joined to any channel"), return unless ( $witem and $witem->{type} eq "CHANNEL" );
my ($tag, $chan, @masks) = (lc($server->{tag}), lc($server->channel_find($witem->{name})->{name}));
while ( $data =~ m/(\d+)/g ) {
my $idx = $1 - 1;
next unless ( exists $modelist{$tag}{$chan}{$type}[$idx] );
push(@masks, $modelist{$tag}{$chan}{$type}[$idx]->[0]);
}
return unless ( $#masks >= 0 );
$witem->command(sprintf("MODE %s -%s %s", $chan, $type x scalar(@masks), join(" ", @masks)));
}
Irssi::signal_add("channel created", "sig_channel_created");
Irssi::signal_add("redir modelist invite", "sig_redir_modelist_invite");
Irssi::signal_add("redir modelist except", "sig_redir_modelist_except");
Irssi::signal_add("message irc mode", "message_irc_mode");
Irssi::command_bind("si", "cmd_si");
Irssi::command_bind("se", "cmd_se");
Irssi::command_bind("uninvite" => sub { cmd_modelist("I", @_); });
Irssi::command_bind("unexcept" => sub { cmd_modelist("e", @_); });
foreach my $server (Irssi::servers)
{
foreach my $channel ($server->channels())
{
channel_create($server, $channel->{name}) unless ($channel->{no_modes});
}
}

View File

@ -0,0 +1,72 @@
use strict;
use warnings;
use Irssi 20171006;
use Irssi::UI;
our $VERSION = '1.0'; # 7775fccf37d60a5
our %IRSSI = (
authors => 'Nei',
contact => 'Nei @ anti@conference.jabber.teamidiot.de',
url => "http://anti.teamidiot.de/",
name => 'savecmdhist',
description => 'Saves the commands you typed in the input prompt to a history file, so that they persist across /upgrade and restart.',
license => 'ISC',
);
# Usage
# =====
# Put the script in autorun if you want the history to be loaded on
# start.
my $histfile = Irssi::get_irssi_dir()."/cmdhistory";
sub loadcmdhist {
my %R = ("n" => "\n", "\\" => "\\", ";" => ";");
my $fh;
unless (open $fh, '<', $histfile) {
warn "Could not open history file ($histfile) for readin: $!\n"
if -e $histfile;
return;
}
my @hist;
while (defined(my $line = <$fh>)) {
chomp $line;
if ($line =~ /^: (\d*):(\d*):(.*?) :;(.*)$/) {
push @hist, +{
time => $1,
window => length $2 ? $2 : undef,
history => length $3 ? $3 : undef,
};
$hist[-1]{text} = $4 =~ s/\\(\\|;|n)/$R{$1}/gmsr;
}
}
my $he1 = @{[Irssi::UI::Window::get_history_entries(undef)]};
Irssi::UI::Window::load_history_entries(undef, @hist) if @hist && $he1 <= 1;
}
sub savecmdhist {
my %R = ("\n" => "\\n", "\\" => "\\\\", " :;" => " :\\;");
my $old_umask =
umask 0077;
my $fh;
unless (open $fh, '>', $histfile) {
umask $old_umask;
warn "Could not open history file ($histfile) for writing: $!\n";
return;
}
umask $old_umask;
no warnings 'uninitialized';
for my $hist (Irssi::UI::Window::get_history_entries(undef)) {
my $text = $hist->{text} =~ s/(\n|\\| :;)/$R{$1}/gmsr;
print $fh ": $hist->{time}:$hist->{window}:$hist->{history} :;$text\n";
}
close $fh;
}
Irssi::signal_add 'gui exit' => sub {
savecmdhist() if Irssi::settings_get_bool('settings_autosave');
};
Irssi::signal_add 'command save' => 'savecmdhist';
loadcmdhist();

View File

@ -0,0 +1,156 @@
# sb_search.pl - search in your scrollback, scroll to a match
# Do /HELP SCROLLBACK for help
# Copyright (C) 2008 Wouter Coekaerts <wouter@coekaerts.be>, Emanuele Giaquinta <exg@irssi.org>
#
# 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 2 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, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
use strict;
use Irssi;
use Irssi::TextUI;
use vars qw($VERSION %IRSSI);
$VERSION = '1.2';
%IRSSI = (
authors => 'Wouter Coekaerts, Emanuele Giaquinta',
contact => 'wouter@coekaerts.be, exg@irssi.org',
name => 'sb_search',
description => 'search in your scrollback, scroll to a match',
license => 'GPLv2 or later',
url => 'http://wouter.coekaerts.be/irssi/',
changed => '$LastChangedDate$',
);
sub cmd_help {
my ($args, $server, $witem) = @_;
if ($args =~ /^scrollback( search)? *$/i) {
Irssi::print ( <<SCRIPTHELP_EOF
SCROLLBACK SEARCH [-level <level>] [-regexp] [-case] [-word] [-forward] [-all] [<pattern>]
SEARCH: Search for text in the scrollback buffer.
-regexp: The given text pattern is a regular expression.
-case: Performs a case-sensitive matching.
-word: The text must match full words.
-forward: Search forwards (default is backwards).
-all: Search in all windows.
Without arguments, the last search is repeated.
SCRIPTHELP_EOF
,MSGLEVEL_CLIENTCRAP);
}
}
my $regex;
my $all;
my $level;
sub cmd_sb_search {
my ($args, $server, $witem) = @_;
### handle options
my ($options, $pattern) = Irssi::command_parse_options('scrollback search', $args);
my $forward = defined(delete $options->{forward});
if (!%$options && !$pattern) {
return if !$regex && !defined $level;
} else {
$all = defined($options->{all});
$level = MSGLEVEL_ALL;
undef $regex;
}
if (defined($options->{level})) {
$level = $options->{level};
$level =~ y/,/ /;
$level = Irssi::combine_level(0, $level);
}
if ($pattern) {
my $flags = defined($options->{case}) ? '' : '(?i)';
my $b = defined($options->{word}) ? '\b' : '';
if (defined($options->{regexp})) {
local $@;
eval {
$regex = qr/$flags$b$pattern$b/;
};
if ($@) {
my ($err) = $@ =~ /^(.*)/;
$err =~ s/\sat .* line \d+\.$//;
print CLIENTERROR $err;
return;
}
} else {
$regex = qr/$flags$b\Q$pattern\E$b/;
}
}
### determine window(s) to search in
my $current_win = ref $witem ? $witem->window() : Irssi::active_win();
my @windows;
if ($all) {
# cycle backward or forwards over all windows starting from current
# for example, searching backward through 5 windows, with window 3 active: search order is 3,2,1,5,4
# if we're searching forward: 3,4,5,1,2
my $order = $forward ? 1 : -1;
@windows = sort {$order * ($a->{refnum} cmp $b->{refnum})} Irssi::windows();
my @before_windows = grep {($_->{refnum} cmp $current_win->{refnum}) == $order} @windows;
my @after_windows = grep {($_->{refnum} cmp $current_win->{refnum}) == -$order} @windows;
@windows = ($current_win, @before_windows, @after_windows);
} else {
@windows = ($current_win);
}
### do the search
foreach my $win (@windows) {
my $view = $win->view;
## determine line to start from
my $line;
if ($all && $win != $current_win) {
if ($forward) { # first line
$line = $view->get_lines;
} else { # last line
$line = $view->{buffer}{cur_line};
}
} elsif ($view->{startline}) { # line after or before first visible line
$line = $forward ? $view->{startline}->next : $view->{startline}->prev;
}
## loop over the lines
while (defined $line) {
my $line_level = $line->{info}{level};
if ($line_level & $level && $line->get_text(0) =~ $regex) {
$view->scroll_line($line);
if ($all) {
Irssi::command('window goto ' . $win->{refnum});
}
return;
}
$line = $forward ? $line->next : $line->prev;
}
}
}
Irssi::command_bind('scrollback search', \&cmd_sb_search);
Irssi::command_bind_last('help', \&cmd_help);
Irssi::command_set_options('scrollback search', '-level regexp case word forward all');

View File

@ -0,0 +1,86 @@
use strict;
use Irssi 20020101.0250 ();
use vars qw($VERSION %IRSSI);
$VERSION = "2";
%IRSSI = (
authors => 'David Leadbeater',
contact => 'dgl@dgl.cx',
name => 'servercomplete',
description => 'Tab complete servers and userhosts (irc. -> irc server, user@ -> user@host). Useful for lazy ircops for /squit and so on :)',
license => 'GNU GPLv2 or later',
url => 'http://irssi.dgl.cx/',
);
my %servers;
sub sig_complete {
my ($complist, $window, $word, $linestart, $want_space) = @_;
my $tag = $window->{active_server}->{tag};
if($word =~ /[!*@]/) {
my $wi = Irssi::active_win()->{active};
return unless ref $wi and $wi->{type} eq 'CHANNEL';
my $server = $wi->{server};
return unless ref $server;
my($nick,$ident,$host) = ('','','');
$nick = $1 if $word =~ /([^!]+)!/ && $1;
$ident = $1 if $word !~ /!$/ && $word =~ /!?([^@]+)(@|$)/ && $1;
$host = $1 if $word =~ /@(.*)$/ && $1;
for my $n ($wi->nicks()) {
next if not_wild($nick) and $n->{nick} !~ /^\Q$nick\E/i;
my($user,$addr) = split(/@/, $n->{host});
next if not_wild($ident) and $user !~ /^\Q$ident\E/i;
next if not_wild($host) and $addr !~ /^\Q$host\E/i;
if($word =~ /!/) {
push @$complist, get_match($n->{nick}, $nick) . '!' . get_match($user, $ident) . '@' . get_match($addr,$host);
}else{
push @$complist, get_match($user, $ident) . '@' . get_match($addr,$host);
}
}
}
return unless $servers{$tag};
for (keys %{$servers{$tag}}) {
push @$complist, $_ if /^\Q$word\E/;
}
}
sub get_match {
my($match, $thing) = @_;
return $thing eq '*' ? '*' : $match;
}
sub not_wild {
return 0 if($_[0] eq '*' || $_[0] eq '');
1;
}
sub add_server {
my($tag,$data,$offset) = @_;
$servers{$tag}{(split(/ /,$data))[$offset]} = 1;
}
Irssi::signal_add_last('complete word', 'sig_complete');
Irssi::signal_add('event 352', sub {
my($server,$data) = @_;
add_server($server->{tag}, $data, 4);
} );
Irssi::signal_add('event 312', sub {
my($server,$data) = @_;
add_server($server->{tag}, $data, 2);
} );
Irssi::signal_add('event 364', sub {
my($server,$data) = @_;
add_server($server->{tag}, $data, 1);
add_server($server->{tag}, $data, 2);
} );

File diff suppressed because it is too large Load Diff