From 0ffb46aaea4cb56c3b46a4d3fe5930bd66f4b1b0 Mon Sep 17 00:00:00 2001 From: Rich Healey Date: Fri, 7 Jan 2011 10:40:27 +1100 Subject: Merged changes from master Shabble, you can now unmerge them if you want. --- auto-server/auto_server-ng.pl | 224 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 auto-server/auto_server-ng.pl diff --git a/auto-server/auto_server-ng.pl b/auto-server/auto_server-ng.pl new file mode 100644 index 0000000..b54ca26 --- /dev/null +++ b/auto-server/auto_server-ng.pl @@ -0,0 +1,224 @@ +# This script was initially written by shabble, this fork (and molestation) is +# built upon his original work. +# +# USAGE: +# +# the primary command used is /join+ #channelname +# +# Mappings for channels to servers is accomplished with the +# joinplus_server_maps setting. +# +# Within this setting, space separated pairs denote channel, server pairs. +# Spaces also separate individual pairs, for example: +# +# /set joinplus_server_maps #foo Freenode #bar irc.somewhere.tld #meep DALNet +# +# Then use /join+ #foo, and if you are not already connected to freenode, it +# will connect you, and then join that channel. + +# TODO: +# Autocompletion for channel names +# address conflict resolution +# fix that disgusting race condition + +use strict; +use warnings; + + +use Irssi; +use Irssi::Irc; +use Irssi::TextUI; + +use Data::Dumper; + + +my $DEBUG_ENABLED = 0; +sub DEBUG () { $DEBUG_ENABLED } + +sub _debug_print { + return unless DEBUG; + return unless scalar (grep { defined && length } @_) == @_; + my $win = Irssi::active_win; + my $str = join('', @_); + $win->print($str, Irssi::MSGLEVEL_CLIENTCRAP); +} + +our $VERSION = '0.0.' . (split(/ /, '$Rev: 362 $'))[1]; + +our %IRSSI = ( + authors => 'shabble, richo', + contact => 'richo@psych0tik.net', + name => 'auto-join-ng', + description => 'connects to a specified server in order to connect' . + ' to a channel there, without having first to' . + ' connect to the server', + license => 'Public Domain', + ); + +my $channel_map = {}; +my @hack_channels; +my $pending_joins; + +sub auto_server_init { + Irssi::command_bind('join+', \&join_plus); + Irssi::settings_add_str('join_plus', 'joinplus_server_maps', ''); + Irssi::signal_add_last('setup changed', \&setup_changed); + Irssi::settings_add_bool('join_plus', 'join_plus_debug', 0); + + setup_changed(); + $pending_joins = {}; + +} + +sub setup_changed { + $DEBUG_ENABLED = Irssi::settings_get_bool('join_plus_debug'); + parse_channel_map(); +} + +# This is a tremendous kludge. +# If anyone knows a better way to get this listing, I'd like to hear it. +# This has so many race condition bugs I just don't even know where to start. +sub retrieve_channels { + @hack_channels = (); + Irssi::signal_add_first('print text', 'haxy_print_hook'); + Irssi::command("CHANNEL LIST"); + Irssi::signal_remove('print text', 'haxy_print_hook'); + return join(" ", @hack_channels); +} + + +# The idea for how to do this courtesy of http://wouter.coekaerts.be/site/irssi/aliases +sub haxy_print_hook { + Irssi::signal_remove('print text', 'haxy_print_hook'); + Irssi::signal_stop(); + my $data = $_[1]; + # Hose control characters + $data =~ s/\x04.//g; + if ($data =~ m/^#/) { + my @items = split /\s+/, $data; + push(@hack_channels, $items[0]); + push(@hack_channels, $items[1]); + } + Irssi::signal_add_first('print text', 'haxy_print_hook'); +} + +sub parse_channel_map { + #my $data = Irssi::settings_get_str('joinplus_server_maps'); + my $data = retrieve_channels(); + unbind_completion(); + my @items = split /\s+/, $data; + if (@items % 2 == 0) { + $channel_map = { @items }; # risky? + } else { + Irssi::active_win->print("Could not process channel => server mappings"); + $channel_map = {}; + } + _debug_print Dumper($channel_map); + bind_completion(); +} + +# Bind a stack of commands so that irssi knows to complete them. +sub bind_completion { + foreach(%$channel_map) { + Irssi::command_bind("join+ $_", \&join_plus); + } +} + +sub unbind_completion { + foreach(%$channel_map) { + Irssi::command_unbind("join+ $_", \&join_plus); + } +} + + +sub join_plus { + my ($args, $cmd_server, $witem) = @_; + #print Dumper($cmd, "moo", $win); + + # parse out channel name from args: + my $channel; + if ($args =~ m/^(#?[#a-zA-Z0-9]+)/) { + $channel = $1; + _debug_print ("Channel is: $channel"); + } + + unless ($channel) { + Irssi::active_win()->print("Channel $args not recognised"); + return; + } + + # lookup server + my $server_id = $channel_map->{$channel}; + _debug_print($server_id); + + unless ($server_id) { + Irssi::active_win()->print("Channel $channel does not have an" + . " appropriate server mapping"); + return; + } + # TODO: search values() and give a 'did you mean' for closest channel + + # check if we're connected to that server + my $server = Irssi::server_find_tag($server_id); + + if (not defined $server) { + $server = Irssi::server_find_chatnet($server_id); + } + + if (not defined $server) { + # still no server, walk the server list looking for address matches. + my @servers = Irssi::servers(); + foreach my $srv (@servers) { + if (($srv->{address} eq $server_id) or + ($srv->{real_address} eq $server_id)) { + $server = $srv; + last; + } + } + } + + if (defined $server) { + + _debug_print ("Already connected to server: " . $server->{tag} ); + + # check if we're already on the required channel + my $on_channel = $server->channel_find($channel); + + if (defined $channel && ref($channel) eq 'Irssi::Irc::Channel') { + Irssi::active_win()->print("You are already connected to " + . " $channel on " . $server->{tag}); + return; + } else { + _debug_print ("joining channel: $channel"); + $server->command("JOIN $channel"); + } + } else { + # not connected to server. + _debug_print ("connecting to server: $server_id"); + + Irssi::command("CONNECT $server_id"); + _debug_print ("awaiting connection for join"); + + $pending_joins->{$server_id} = $channel; + Irssi::signal_add_last("event 376", 'do_channel_join'); + } +} + +sub do_channel_join { + my ($serv) = @_; + #_debug_print("server is " . Dumper($serv)); + _debug_print(sprintf("server is %s (%s)", $serv->{address}, $serv->{tag})); + + my $channel = $pending_joins->{$serv->{address}}; + $channel = $pending_joins->{$serv->{tag}} unless $channel; + + _debug_print ("attempting to join $channel"); + + Irssi::server_find_tag($serv->{tag})->command("JOIN $channel"); + + delete $pending_joins->{$serv->{address}}; + delete $pending_joins->{$serv->{tag}}; + +} + +auto_server_init(); -- cgit v1.2.3