#!/usr/bin/perl -w
## Bugreports and Licence disclaimer.
#
# For bugreports and other improvements contact Geert Hauwaerts
#
# 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 script; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
##
use strict;
use Irssi;
use vars qw($VERSION %IRSSI);
$VERSION = '0.02';
%IRSSI = (
authors => 'Geert Hauwaerts',
contact => '[email protected]',
name => 'invitejoin.pl',
description => 'This script will join a channel if somebody invites you to it.',
license => 'Public Domain',
url => 'https://github.com/irssi/scripts.irssi.org/blob/master/scripts/invitejoin.pl',
changed => 'Di 17. Jan 19:32:45 CET 2017',
);
my $help = < ]
[delnick ]
[listnick]
[help]
addnick: Add a new nickname on the given net as allowed autoinvite source.
delnick: Delete a nickname from the allowed list.
listnick: Display the contents of the allowed nickname list.
help: Display this useful little helptext.
Examples: (all on one line)
/INVITEJOIN addnick Freenode ChanServ
Note: This script doesn't allow wildcards
EOF
my @allowed_nicks = ();
my $allowed_nicks_file = "invitejoin.nicks";
my $irssidir = Irssi::get_irssi_dir();
Irssi::theme_register([
'invitejoin_usage', '%R>>%n %_Invitejoin:%_ Insufficient parameters: Use "%_/INVITEJOIN help%_" for further instructions.',
'invitejoin_help', '$0',
'invitejoin_loaded', '%R>>%n %_Scriptinfo:%_ Loaded $0 version $1 by $2.',
'invitejoin_invited', '%R>>%n %_Invitejoin:%_ Joined $1 (Invited by $0).',
'invitejoin_usage_add_nick', '%R>>%n %_Invitejoin:%_ Insufficient parameters: Usage "%_/INVITEJOIN addnick ircnet ChanServ%_".',
'invitejoin_no_net', '%R>>%n %_Invitejoin:%_ Unknown Irssi ircnet %_$0%_.',
'saved_nick', '%R>>%n %_Invitejoin:%_ Added allowed nick "%_$1%_" on %_$0%_.',
'nick_already_present', '%R>>%n %_Invitejoin:%_ Nick already present.',
'invitejoin_delusage', '%R>>%n %_Invitejoin:%_ Insufficient parameters: Usage "%_/INVITEJOIN delnick ircnet nick%_".',
'invitejoin_delled', '%R>>%n %_Invitejoin:%_ Deleted %_$1%_ on %_$0%_ from allowed list.',
'invitejoin_nfound', '%R>>%n %_Invitejoin:%_ The nick %_$1%_ on %_$0%_ could not be found.',
'allowed_nicks_info', '%_Ircnet Nick%_',
'allowed_nicks_empty', '%R>>%n %_Invitejoin:%_ Your allowed nick list is empty. All invites will be followed.',
'allowed_nicks_print', '$[18]0 $1',
'invite_denied', '%R>>%n %_Invitejoin:%_ Invite from nick %_$1%_ on %_$0%_ to %_$2%_ not followed because it is not in the allowed list.',
]);
sub load_allowed_nicks {
my ($file) = @_;
@allowed_nicks = load_file($file, sub {
my $new_allowed = new_allowed_nick(@_);
return undef if ($new_allowed->{net} eq '' || $new_allowed->{nick} eq '');
return $new_allowed;
});
}
sub save_allowed_nicks {
my ($file) = @_;
save_file($file, \@allowed_nicks, \&allowed_nick_to_list);
}
sub allowed_nick_to_list {
my $allowed_nick = shift;
return (
$allowed_nick->{net},
$allowed_nick->{nick}
);
}
sub new_allowed_nick {
return {
net => shift,
nick => shift
};
}
# file: filename to be read
# parse_line_fn: receives array of entries of a single line as input, should
# return parsed data object or undef in the data is incomplete
# returns: parsed data array
sub load_file {
my ($file, $parse_line_fn) = @_;
my @parsed_data = ();
if (-e $file) {
open(my $fh, "<", $file);
local $/ = "\n";
while (<$fh>) {
chomp;
my $data = $parse_line_fn->(split("\t"));
push(@parsed_data, $data) if $data;
}
close($fh);
}
return @parsed_data;
}
# file: filename to be written, is created accessable only by the user
# data_ref: array ref of data entries
# serialize_fn: receives a data reference and should return an array or tuples
# for that data that will be serialized into one line
sub save_file {
my ($file, $data_ref, $serialize_fn) = @_;
create_private_file($file) unless -e $file;
open(my $fh, ">", $file) or die "Can't create $file. Reason: $!";
for my $data (@$data_ref) {
print($fh join("\t", $serialize_fn->($data)), "\n");
}
close($fh);
}
sub create_private_file {
my ($file) = @_;
my $umask = umask 0077; # save old umask
open(my $fh, ">", $file) or die "Can't create $file. Reason: $!";
close($fh);
umask $umask;
}
sub add_allowed_nick {
my ($network, $nick) = split(" ", $_[0], 2);
my ($correct_net);
if ($network eq '' || $nick eq '') {
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_usage_add_nick');
return;
}
if ($network) {
my ($ircnet) = Irssi::chatnet_find($network);
if (!$ircnet) {
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_no_net', $network);
return;
} else {
$correct_net = 1;
}
}
if ($correct_net && $nick) {
if (is_nick_in_list($network, $nick)) {
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nick_already_present');
return;
}
push(@allowed_nicks, new_allowed_nick($network, $nick));
save_allowed_nicks("$irssidir/$allowed_nicks_file");
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'saved_nick', $network, $nick);
}
}
sub del_allowed_nick {
my ($ircnet, $nick) = split(" ", $_[0], 2);
if ($ircnet eq '' || $nick eq '') {
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_delusage');
return;
}
my $size_before = scalar(@allowed_nicks);
@allowed_nicks = grep { ! ($_->{net} eq $ircnet && $_->{nick} eq $nick) } @allowed_nicks;
my $size_after = scalar(@allowed_nicks);
if ($size_after != $size_before) {
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_delled', $ircnet, $nick);
save_allowed_nicks("$irssidir/$allowed_nicks_file");
} else {
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_nfound', $ircnet, $nick);
}
if ($size_after == 0) {
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'allowed_nicks_empty');
}
}
sub list_allowed_nicks {
if (@allowed_nicks == 0) {
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'allowed_nicks_empty');
} else {
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'allowed_nicks_info');
for my $allowed (@allowed_nicks) {
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'allowed_nicks_print', $allowed->{net}, $allowed->{nick});
}
}
}
sub invitejoin_runsub {
my ($data, $server, $item) = @_;
$data =~ s/\s+$//g;
if ($data) {
Irssi::command_runsub('invitejoin', $data, $server, $item);
} else {
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_usage');
}
}
sub is_nick_in_list {
my ($net, $nick) = @_;
return (grep {
$_->{net} eq $net &&
$_->{nick} eq $nick
} @allowed_nicks) > 0;
}
sub is_allowed_nick {
my ($net, $nick) = @_;
# If no allowed nicks are specified (initial configuration) accept
# all invite requests.
# # (This mimics previous behavior of this script
# before there was an allowed list)
return 1 if @allowed_nicks == 0;
return is_nick_in_list($net, $nick);
}
sub invitejoin {
my ($server, $channel, $nick, $address) = @_;
my $invitejoin = Irssi::settings_get_bool('invitejoin');
if ($invitejoin) {
if (is_allowed_nick($server->{tag}, $nick)) {
$server->command("join $channel");
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_invited', $nick, $channel);
Irssi::signal_stop();
}
else {
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invite_denied', $server->{tag}, $nick, $channel);
}
}
}
Irssi::signal_add('message invite', 'invitejoin');
Irssi::settings_add_bool('invitejoin', 'invitejoin' => 1);
load_allowed_nicks("$irssidir/$allowed_nicks_file");
Irssi::command_bind('invitejoin', 'invitejoin_runsub');
Irssi::command_bind('invitejoin addnick', 'add_allowed_nick');
Irssi::command_bind('invitejoin delnick', 'del_allowed_nick');
Irssi::command_bind('invitejoin listnick', 'list_allowed_nicks');
Irssi::command_bind('invitejoin help' => sub { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_help', $help) });
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'invitejoin_loaded', $IRSSI{name}, $VERSION, $IRSSI{authors});