aboutsummaryrefslogtreecommitdiff
path: root/.irssi/scripts/recentdepart.pl
blob: efb8b95b0a2146134e0cd08cd04af7b3a5ab4071 (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
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
#!/usr/bin/perl -w
#
# recentdepart.pl
#
# irssi script
# 
# This script, when loaded into irssi, will filter quit and parted messages
# for channels listed in recdep_channels for any nick whos last message was
# more then a specified time ago.
#
# It also filters join messages showing only join messages for nicks who recently
# parted.
#
# [settings]
# recdep_channels
#     - Should contain a list of chatnet and channel  names that recentdepart
#        should monitor.  Its format is a spcae delimited list of chatnet/#channel
#        pairs.  Either chatnet or channel are optional but adding a / makes it
#        explicitly recognized as a chatnet or a channel name.  A special case is just a
#        "*" which turns it on globally.
#
#        "#irrsi #perl"                 - enables filtering on the #irssi and #perl
#                                          channels on all chatnets.
#
#        "freenode IRCNet/#irssi"       - enables filtering for all channels on frenode
#                                          and only the #irssi channel on IRCNet.
#
#        "freenode/"                    - force "freenode" to be interpreted as the chatnet
#                                          name by adding a / to the end.
#
#        "/freenode"                    - forces "freenode" to be interpreted as the channel
#                                          by prefixing it with the / delimiter.
#
#         "*"                           - globally enables filtering.
#
# recdep_period
#     - specifies the window of time, after a nick last spoke, for which quit/part
#        notices will be let through the filter. 
#
# recdep_rejoin
#     - specifies a time period durring which a join notice for someone rejoining will
#        be shown.  Join messages are filtered if the nicks part/quit message was filtered
#        or if the nick is gone longer then the rejoin period.
#        Set to 0 to turn off filtering of join notices.
#
# recdep_nickperiod
#     - specifies a window of time like recdep_period that is used to filter nick change
#        notices. Set to 0 to turn off filtering of nick changes.
#
# recdep_use_hideshow
#     - whether to use hideshow script instead of ignoring
#

use strict;
use warnings;
use Irssi;
use Irssi::Irc;

our $VERSION = "0.7";
our %IRSSI = (
    authors     => 'Matthew Sytsma',
    contact     => 'spiderpigy@yahoo.com',
    name        => 'Recently Departed',
    description => 'Filters quit/part/join/nick notices based on time since last message. (Similar to weechat\'s smartfilter).',
    license     => 'GNU GPLv2 or later',
    url         => '',
);

# store a hash of configure selected servers/channels
my %chanlist;
# Track recent times by server/nick/channel
# (it is more optimal to go nick/channel then channel/nick because some quit signals are by server not by channel.
#  We will only have to loop through open channels that a nick has spoken in which should be less then looping
#  through all the monitored channels looking for the nick.
my %nickhash=();
# Track recent times for parted nicks by server/channel/nick
my %joinwatch=();
my $use_hide;

sub on_setup_changed {
    my %old_chanlist = %chanlist;
    %chanlist = ();
    my @pairs = split(/ /, Irssi::settings_get_str("recdep_channels"));

    $use_hide = Irssi::settings_get_bool("recdep_use_hideshow");
    foreach (@pairs)
    {
        my ($net, $chan, $more) = split(/\//);
        if ($more)
        {
            /\/(.+)/;
            $chan = $1;
        }
#        Irssi::active_win()->print("Initial Net: $net  Chan: $chan");
        if (!$net)
        {
            $net = '*';
        }

        if ($net =~ /^[#!@&]/ && !$chan)
        {
            $chan = $net;
            $net = "*";
        }

        if (!$chan)
        {
            $chan = "*";
        }

        $chanlist{$net}{$chan} = 1;
    }

    # empty the storage in case theres a channel or server we are no longer filtering
    %nickhash=();
    %joinwatch=();
}

sub check_channel
{
    my ($server, $channel) = @_;

    # quits dont have a channel so we need to see if this server possibly contains this channel
    if (!$channel || $channel eq '*')
    {
        # see if any non chatnet channel listings are open on this server
        if (keys %{ $chanlist{'*'} })
        {
            foreach my $chan (keys %{ $chanlist{'*'} })
            {
                if ($chan eq '*' || $server->channel_find($chan))
                {
                    return 1;
                }
            }
        }

        #  see if there were any channels listed for this chatnet
        if (keys %{ $chanlist{$server->{'chatnet'}} })
        {    return 1;    }
        else
        {    return 0;    }
    }

    # check for global channel matches and pair matches
    return (($chanlist{'*'}{'*'}) ||
            ($chanlist{'*'}{$channel}) ||
            ($chanlist{$server->{'chatnet'}}{'*'}) ||
            ($chanlist{$server->{'chatnet'}}{$channel}));
}

# Hook for quitting
sub on_quit
{
	my ($server, $nick, $address, $reason) = @_;

        if ($server->{'nick'} eq $nick)
        {  return;   }

	if (check_channel($server, '*'))
        {
            my $recent = 0;
            foreach my $chan (keys %{ $nickhash{$server->{'tag'}}{lc($nick)} })
            {
                 if (time() - $nickhash{$server->{'tag'}}{lc($nick)}{$chan} < Irssi::settings_get_int("recdep_period"))
                 {
                     $recent = 1;

                     if (Irssi::settings_get_int("recdep_rejoin") > 0)
                     {
                         $joinwatch{$server->{'tag'}}{$chan}{lc($nick)} = time();
                     }
                 }
            }

            delete $nickhash{$server->{'tag'}}{lc($nick)};

            if (!$recent)
            {
                $use_hide ? $Irssi::scripts::hideshow::hide_next = 1
		    : Irssi::signal_stop();
            }
	}
}

# Hook for parting
sub on_part 
{
	my ($server, $channel, $nick, $address, $reason) = @_;

        # cleanup if its you who left a channel
        if ($server->{'nick'} eq $nick)
        {
            # slightly painfull cleanup but we shouldn't hit this as often
            foreach my $nickd (keys %{ $nickhash{$server->{'tag'}} })
            {
                delete $nickhash{$server->{'tag'}}{$nickd}{$channel};
                if (!keys(%{ $nickhash{$server->{'tag'}}{$nickd} }))
                {
                    delete $nickhash{$server->{'tag'}}{$nickd};
                }
            }
            delete $joinwatch{$server->{'tag'}}{$channel};
        }
	elsif (check_channel($server, $channel))
        {
            if (!defined $nickhash{$server->{'tag'}}{lc($nick)}{$channel} || time() - $nickhash{$server->{'tag'}}{lc($nick)}{$channel} > Irssi::settings_get_int("recdep_period"))
            {
                $use_hide ? $Irssi::scripts::hideshow::hide_next = 1
		    : Irssi::signal_stop();
            }
            elsif (Irssi::settings_get_int("recdep_rejoin") > 0)
            {
                $joinwatch{$server->{'tag'}}{$channel}{lc($nick)} = time();
            }

            delete $nickhash{$server->{'tag'}}{lc($nick)}{$channel};
            if (!keys(%{ $nickhash{$server->{'tag'}}{lc($nick)} }))
            {
                delete $nickhash{$server->{'tag'}}{lc($nick)};
            }
	}
}

# Hook for public messages.
sub on_public
{
	my ($server, $msg, $nick, $addr, $target) = @_;

        if (!$target) { return; }
        if ($nick =~ /^#/) { return; }

        if ($server->{'nick'} eq $nick) { return; }

	if (check_channel($server, $target))
        {
            $nickhash{$server->{'tag'}}{lc($nick)}{$target} = time();
	}
}

# Hook for people joining
sub on_join 
{
	my ($server, $channel, $nick, $address) = @_;

        if ($server->{'nick'} eq $nick)
        {  return;   }

        if (Irssi::settings_get_int("recdep_rejoin") == 0)
        {   return;  }

	if (check_channel($server, $channel))
        {
            if (!defined $joinwatch{$server->{'tag'}}{$channel}{lc($nick)} || time() - $joinwatch{$server->{'tag'}}{$channel}{lc($nick)} > Irssi::settings_get_int("recdep_rejoin"))
            {
                $use_hide ? $Irssi::scripts::hideshow::hide_next = 1
		    : Irssi::signal_stop();
            }
	}

        # loop through and delete all old nicks from the rejoin hash
        # this should be a small loop because it will only inlude nicks who recently left channel and who
        # passed the part message filter
        foreach my $nickd (keys %{ $joinwatch{$server->{'tag'}}{$channel} })
        {
           if (time() - $joinwatch{$server->{'tag'}}{$channel}{lc($nickd)} < Irssi::settings_get_int("recdep_rejoin"))
           {   next;   }

           delete $joinwatch{$server->{'tag'}}{$channel}{lc($nickd)};
        }
        if (!keys(%{ $joinwatch{$server->{'tag'}}{$channel} }))
        {
            delete $joinwatch{$server->{'tag'}}{$channel};
        }
}

# Hook for nick changes
sub on_nick 
{
        my ($server, $new, $old, $address) = @_;

        if ($server->{'nick'} eq $old || $server->{'nick'} eq $new)
        {  return;   }
   
        if (check_channel($server, '*'))
        {
            my $recent = 0;
            foreach my $chan (keys %{ $nickhash{$server->{'tag'}}{lc($old)} })
            {
                 if (time() - $nickhash{$server->{'tag'}}{lc($old)}{$chan} < Irssi::settings_get_int("recdep_nickperiod"))
                 {
                     $recent = 1;
                 }
            }

            if (!$recent && Irssi::settings_get_int("recdep_nickperiod") > 0)
            {
                $use_hide ? $Irssi::scripts::hideshow::hide_next = 1
		    : Irssi::signal_stop();
            }

           delete $nickhash{$server->{'tag'}}{lc($old)}; 
        }
}


# Hook for cleanup on server quit
sub on_serverquit
{
        my ($server, $msg) = @_;

        delete $nickhash{$server->{'tag'}};
        delete $joinwatch{$server->{'tag'}};
}

# Setup hooks on events
Irssi::signal_add_last("message public", "on_public");
Irssi::signal_add_last("message part", "on_part");
Irssi::signal_add_last("message quit", "on_quit");
Irssi::signal_add_last("message nick", "on_nick");
Irssi::signal_add_last("message join", "on_join");
Irssi::signal_add_last("server disconnected", "on_serverquit");
Irssi::signal_add_last("server quit", "on_serverquit");
Irssi::signal_add('setup changed', "on_setup_changed");

# Add settings
Irssi::settings_add_str("recdentpepart", "recdep_channels", '*');
Irssi::settings_add_int("recdentpepart", "recdep_period", 600);
Irssi::settings_add_int("recdentpepart", "recdep_rejoin", 120);
Irssi::settings_add_int("recdentpepart", "recdep_nickperiod", 600);
Irssi::settings_add_bool("recdentpepart", "recdep_use_hideshow", 0);
on_setup_changed();