1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
# 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 and servers are retrieved from irssi's internal
# /channel list
#
# Then use /join+ #foo, and if you are not already connected to freenode, it
# will connect you, and then join that channel.
# TODO:
# address conflict resolution
# fix that disgusting race condition
# Fix incredibly slow shutdown time after a few days
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.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();
}
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/^([#&!]?[^ ]*)/) {
$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
# TODO: Fuzzy match for ## channels (Would be nice to hax at teh tab
# completion too)
# 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);
# FIXME
# Should this be $on_channel? Need docs..
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;
# This comes tumbling down if the server doesn't have a MOTD.
# is that RFC required?
Irssi::signal_add_last("event 376", 'do_channel_join');
}
}
sub do_channel_join {
Irssi::signal_remove("event 376", '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;
if ($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();
|