/var/www/www.irssi.org-old/scripts/html/autorealname.pl
1 # Print realname of everyone who join to channels
2 # for irssi 0.7.99 by Timo Sirainen
3
4 use Irssi 20011207;
5 use strict;
6 use vars qw($VERSION %IRSSI);
7 $VERSION = "0.8.6";
8 %IRSSI = (
9 authors => "Timo \'cras\' Sirainen, Bastian Blank",
10 contact => "tss\@iki.fi, waldi\@debian.org",
11 name => "auto realname",
12 description => "Print realname of everyone who join to channels",
13 license => "GPLv2 or later",
14 url => "http://irssi.org/",
15 changed => "Fri, 24 Jan 2003 15:40:22 +0100"
16 );
17
18 # v0.8.6 changes - Juhamatti Niemelä
19 # - fix join msg printing when there are multiple common channels
20 # v0.8.5 changes - Bastian Blank
21 # - really use the introduced state variable
22 # v0.8.4 changes - Bastian Blank
23 # - fix queue abort
24 # v0.8.3 changes - Bastian Blank
25 # - on queue abort print any join messages
26 # v0.8.2 changes - Bastian Blank
27 # - use channelname instead of Irssi::Irc::Channel for channelname within message on join
28 # v0.8.1 changes - Bastian Blank
29 # - print any join messages on abort
30 # - also remove any timeouts
31 # v0.8 changes - Bastian Blank
32 # - join message includes realname
33 # - add timeout
34 # - don't print realname for our self
35 # - change license because german law doesn't allow to give away the copyright
36 # v0.71 changes
37 # - a bit safer now with using "redirect last"
38 # v0.7 changes
39 # - pretty much a rewrite - shouldn't break anymore
40 # v0.62 changes
41 # - upgraded redirection to work with latest CVS irssi - lot easier
42 # to handle it this time :)
43 # v0.61 changes
44 # - forgot to reset %chan_list..
45 # v0.6 changes
46 # - works now properly when a nick joins to multiple channels
47 # v0.5 changes
48 # - Use "message join" so we won't ask realname for ignored people
49
50 Irssi::theme_register([
51 'join', '{channick_hilight $0} {chanhost_hilight $1} has joined {channel $2}',
52 'join_realname', '{channick_hilight $0} ({hilight $1}) {chanhost_hilight $2} has joined {channel $3}',
53 'join_realname_only', '{channick_hilight $0} is {hilight $1}',
54 ]);
55
56 my $whois_queue_length_before_abort = 10; # max. whois queue length before we should abort the whois queries for next few seconds (people are probably joining behind a netsplit)
57 my $whois_abort_seconds = 10; # wait for 10 secs when there's been too many joins
58 my $debug = 0;
59
60 my %servers;
61
62 my %whois_waiting;
63 my %whois_queue;
64 my %aborted;
65 my %chan_list;
66
67 sub sig_connected {
68 my $server = shift;
69 $servers{$server->{tag}} = {
70 abort_time => 0, # if join event is received before this, abort
71 waiting => 0, # waiting reply for WHOIS request
72 queue => [], # whois queue
73 nicks => {} # nick => [ #chan1, #chan2, .. ]
74 };
75 }
76
77 sub sig_disconnected {
78 my $server = shift;
79 delete $servers{$server->{tag}};
80 }
81
82 sub msg_join {
83 my ($server, $channame, $nick, $host) = @_;
84 $channame =~ s/^://;
85 my $rec = $servers{$server->{tag}};
86
87 # don't display realname for our self
88 return if ($nick eq $server->{nick});
89
90 # don't whois people who netjoin back
91 return if ($server->netsplit_find($nick, $host));
92
93 return if (time < $rec->{abort_time});
94 $rec->{abort_time} = 0;
95
96 Irssi::signal_stop();
97
98 # check if the nick is already found from another channel
99 {
100 my $ret = 0;
101 foreach my $channel ($server->channels()) {
102 my $nickrec = $channel->nick_find($nick);
103 if ($nickrec && $nickrec->{realname}) {
104 # this user already has a known realname - use it.
105 $channel = $server->channel_find($channame);
106 $channel->printformat(MSGLEVEL_JOINS, 'join_realname', $nick, $nickrec->{realname}, $nickrec->{host}, $channel->{name});
107 $channel->print("autorealname: already found: $nick", MSGLEVEL_CLIENTCRAP) if $debug;
108 $ret = 1;
109 last;
110 }
111 }
112
113 return if ($ret);
114 }
115
116 # save channel to nick specific hash so we can later check which channels
117 # it needs to print the realname
118
119 if ($rec->{nicks}->{$nick}) {
120 # don't send the WHOIS again if nick is already in queue
121 push @{$rec->{nicks}->{$nick}->{chans_join}}, $channame;
122 push @{$rec->{nicks}->{$nick}->{chans_realname}}, $channame;
123 $rec->{nicks}->{$nick}->{state} = 0;
124 my $channel = $server->channel_find($channame);
125 $channel->print("autorealname: already in queue: $nick", MSGLEVEL_CLIENTCRAP) if $debug;
126 }
127 else {
128 $rec->{nicks}->{$nick} = {};
129 $rec->{nicks}->{$nick}->{chans_join} = [$channame];
130 $rec->{nicks}->{$nick}->{chans_realname} = [$channame];
131 $rec->{nicks}->{$nick}->{state} = 0;
132
133 # add the nick to queue
134 push @{$rec->{queue}}, $nick;
135
136 # timeout
137 $rec->{nicks}->{$nick}->{timeout} = Irssi::timeout_add(1000, \&timeout_whois, [$server, $nick]);
138 my $channel = $server->channel_find($channame);
139 $channel->print("autorealname: add to queue: $nick", MSGLEVEL_CLIENTCRAP) if $debug;
140 }
141
142 if (scalar @{$rec->{queue}} >= $whois_queue_length_before_abort) {
143 # too many whois requests in queue, abort
144 foreach $nick (@{$rec->{queue}}) {
145 foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) {
146 my $chanrec = $server->channel_find($channel);
147 my $nickrec = $chanrec->nick_find($nick);
148 if ($chanrec && $nickrec) {
149 $chanrec->printformat(MSGLEVEL_JOINS, 'join', $nick, $nickrec->{host}, $channel);
150 $chanrec->print("autorealname: queue abort: $nick", MSGLEVEL_CLIENTCRAP) if $debug;
151 }
152 }
153 Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout}) if (!($rec->{nicks}->{$nick}->{state} & 2));
154 delete $rec->{nicks}->{$nick};
155 }
156 $rec->{queue} = [];
157 $rec->{abort_time} = time+$whois_abort_seconds;
158 return;
159 }
160
161 # waiting for WHOIS reply..
162 return if $rec->{waiting};
163
164 request_whois($server, $rec);
165 }
166
167 sub request_whois {
168 my ($server, $rec) = @_;
169 return if (scalar @{$rec->{queue}} == 0);
170
171 my @whois_nicks = splice(@{$rec->{queue}}, 0, $server->{max_whois_in_cmd});
172 my $whois_query = join(',', @whois_nicks);
173
174 # ignore all whois replies except the first line of the WHOIS reply
175 my $redir_arg = $whois_query.' '.join(' ', @whois_nicks);
176 $server->redirect_event("whois", 1, $redir_arg, 0,
177 "redir autorealname_whois_last", {
178 "event 311" => "redir autorealname_whois",
179 "event 401" => "redir autorealname_whois_unknown",
180 "redirect last" => "redir autorealname_whois_last",
181 "" => "event empty" });
182
183 $server->send_raw("WHOIS :$whois_query");
184 $rec->{waiting} = 1;
185 }
186
187 sub event_whois {
188 my ($server, $data) = @_;
189 my ($num, $nick, $user, $host, $empty, $realname) = split(/ +/, $data, 6);
190 $realname =~ s/^://;
191 my $rec = $servers{$server->{tag}};
192
193 return if not $rec->{nicks}->{$nick};
194
195 $rec->{nicks}->{$nick}->{state} |= 1;
196
197 if (!($rec->{nicks}->{$nick}->{state} & 2)) {
198 Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout});
199 foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) {
200 my $chanrec = $server->channel_find($channel);
201 my $nickrec = $chanrec->nick_find($nick);
202 if ($chanrec && $nickrec) {
203 $chanrec->printformat(MSGLEVEL_JOINS, 'join_realname', $nick, $realname, $nickrec->{host}, $channel);
204 $chanrec->print("autorealname: got whois: $nick, state: ".$rec->{nicks}->{$nick}->{state}, MSGLEVEL_CLIENTCRAP) if $debug;
205 }
206 }
207 $rec->{nicks}->{$nick}->{chans_join} = [];
208 $rec->{nicks}->{$nick}->{chans_realname} = [];
209 $rec->{nicks}->{$nick}->{state} |= 2;
210 }
211 else {
212 foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_realname}}) {
213 my $chanrec = $server->channel_find($channel);
214 my $nickrec = $chanrec->nick_find($nick);
215 if ($chanrec && $nickrec) {
216 $chanrec->printformat(MSGLEVEL_JOINS, 'join_realname_only', $nick, $realname);
217 $chanrec->print("autorealname: got whois: $nick, state: ".$rec->{nicks}->{$nick}->{state}, MSGLEVEL_CLIENTCRAP) if $debug;
218 }
219 }
220 $rec->{nicks}->{$nick}->{chans_realname} = [];
221 }
222
223 delete $rec->{nicks}->{$nick} if ($rec->{nicks}->{$nick}->{state} == 3);
224 }
225
226 sub event_whois_unknown {
227 my ($server, $data) = @_;
228 my ($temp, $nick) = split(" ", $data);
229 my $rec = $servers{$server->{tag}};
230
231 return if not $rec->{nicks}->{$nick};
232
233 $rec->{nicks}->{$nick}->{state} |= 1;
234
235 if (!($rec->{nicks}->{$nick}->{state} & 2)) {
236 Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout});
237 foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) {
238 my $chanrec = $server->channel_find($channel);
239 my $nickrec = $chanrec->nick_find($nick);
240 if ($chanrec && $nickrec) {
241 $chanrec->printformat(MSGLEVEL_JOINS, 'join', $nick, $nickrec->{host}, $channel);
242 $chanrec->print("autorealname: got unknown whois: $nick", MSGLEVEL_CLIENTCRAP) if $debug;
243 }
244 }
245 $rec->{nicks}->{$nick}->{chans_join} = [];
246 } else {
247 foreach my $channel (@{$rec->{nicks}->{$nick}->{chans_join}}) {
248 my $chanrec = $server->channel_find($channel);
249 $chanrec->print("autorealname: got unknown whois (already considered): $nick", MSGLEVEL_CLIENTCRAP) if $debug;
250 }
251 }
252
253 delete $rec->{nicks}->{$nick} if ($rec->{nicks}->{$nick}->{state} == 3);
254 }
255
256 sub event_whois_last {
257 my $server = shift;
258 my $rec = $servers{$server->{tag}};
259
260 $rec->{waiting} = 0;
261 request_whois($server, $rec);
262 }
263
264 foreach my $server (Irssi::servers()) {
265 sig_connected($server);
266 }
267
268 sub timeout_whois {
269 my $server = shift @{$_[0]};
270 my $nick = shift @{$_[0]};
271
272 my $rec = $servers{$server->{tag}};
273
274 return if not $rec->{nicks}->{$nick};
275
276 Irssi::timeout_remove($rec->{nicks}->{$nick}->{timeout});
277 $rec->{nicks}->{$nick}->{state} |= 2;
278
279 my @channels = @{$rec->{nicks}->{$nick}->{chans_join}};
280 foreach my $channel (@channels) {
281 my $chanrec = $server->channel_find($channel);
282 my $nickrec = $chanrec->nick_find($nick);
283 if ($nickrec && $chanrec) {
284 $chanrec->printformat(MSGLEVEL_JOINS, 'join', $nick, $nickrec->{host}, $channel);
285 $chanrec->print("autorealname: timeout: $nick, state: ".$rec->{nicks}->{$nick}->{state}, MSGLEVEL_CLIENTCRAP) if $debug;
286 }
287 }
288
289 $rec->{nicks}->{$nick}->{chans_join} = [];
290 }
291
292 Irssi::signal_add( {
293 'server connected' => \&sig_connected,
294 'server disconnected' => \&sig_disconnected,
295 'message join' => \&msg_join,
296 'redir autorealname_whois' => \&event_whois,
297 'redir autorealname_whois_unknown' => \&event_whois_unknown,
298 'redir autorealname_whois_last' => \&event_whois_last });