aboutsummaryrefslogtreecommitdiffstats
path: root/auto-server/auto_server.pl
blob: 82382f7711dee06709852ae5d05d009e8d4390a2 (plain) (blame)
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
# 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.


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',
              contact     => 'shabble+irssi@metavore.org',
              name        => 'auto-join',
              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 $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();
}

sub parse_channel_map {
    my $data = Irssi::settings_get_str('joinplus_server_maps');
    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);
}

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();