/var/www/www.irssi.org-old/scripts/html/nickserv.pl
1 #!/usr/bin/perl -w
2
3 ## Bugreports and Licence disclaimer.
4 #
5 # For bugreports and other improvements contact Geert Hauwaerts <geert@irssi.org>
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this script; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #
21 ##
22
23 use strict;
24 use Irssi;
25 use vars qw($VERSION %IRSSI);
26
27 $VERSION = "1.8";
28
29 %IRSSI = (
30 authors => 'Geert Hauwaerts',
31 contact => 'geert@irssi.org',
32 name => 'nickserv.pl',
33 description => 'This script will authorize you into NickServ.',
34 license => 'GNU General Public License',
35 url => 'http://irssi.hauwaerts.be/nickserv.pl',
36 changed => 'Fri Jun 6 12:03:04 CEST 2008',
37 );
38
39 my @nickservnet = ();
40 my $nickservnet_file = "nickserv.networks";
41
42 my @nickservauth = ();
43 my $nickservauth_file = "nickserv.auth";
44
45 my $irssidir = Irssi::get_irssi_dir();
46
47 my $help = <<EOF;
48
49 Usage: (all on one line)
50 /NICKSERV [addnet <ircnet> <services\@host>]
51 [addnick <ircnet> <nickname> <password>]
52 [delnet <ircnet>]
53 [delnick <ircnet> <nick>]
54 [help listnet listnick]
55
56 addnet: Add a new network into the NickServ list.
57 addnick: Add a new nickname into the NickServ list.
58 delnet: Delete a network from the NickServ list.
59 delnick: Delete a nickname from the NickServ list.
60 listnet: Display the contents of the NickServ network list.
61 listnick: Display the contents of the NickServ nickname list.
62 help: Display this useful little helptext.
63
64 Examples: (all on one line)
65 /NICKSERV addnet Freenode NickServ\@services.
66 /NICKSERV addnick Freenode Geert mypass
67
68 /NICKSERV delnet Freenode
69 /NICKSERV delnick Freenode Geert
70
71 Note: This script doesn't allow wildcards into the NickServ hostname. You must use the full services\@host.
72 Both /NICKSERV and /NS are valid commands.
73 EOF
74
75 Irssi::theme_register([
76 'nickserv_usage_network', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV addnet ircnet services@host%_".',
77 'nickserv_usage_nickname', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV addnick ircnet nickname password%_".',
78 'nickserv_delusage', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV delnet ircnet%_".',
79 'nickserv_delnickusage', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV delnick ircnet nickname%_".',
80 'nickserv_delled', '%R>>%n %_NickServ:%_ Deleted %_$0%_ and his nicknames from the NickServ ircnet list.',
81 'nickserv_delled_nick', '%R>>%n %_NickServ:%_ Deleted %_$1%_ from the NickServ list on $0.',
82 'nickserv_nfound', '%R>>%n %_NickServ:%_ The NickServ ircnet %_$0%_ could not be found.',
83 'nickserv_nfound_nick', '%R>>%n %_NickServ:%_ The NickServ nickname %_$0%_ could not be found on $1.',
84 'nickserv_usage', '%R>>%n %_NickServ:%_ Insufficient parameters: Use "%_/NICKSERV help%_" for further instructions.',
85 'nickserv_no_net', '%R>>%n %_NickServ:%_ Unknown Irssi ircnet %_$0%_.',
86 'nickserv_wrong_host', '%R>>%n %_NickServ:%_ Malformed services hostname %_$0%_.',
87 'already_loaded_network', '%R>>%n %_NickServ:%_ The ircnet %_$0%_ already exists in the NickServ ircnet list, please remove it first.',
88 'nickserv_loaded_nick', '%R>>%n %_NickServ:%_ The nickname %_$0%_ already exists in the NickServ authlist on %_$1%_, please remove it first.',
89 'nickserv_not_loaded_net', '%R>>%n %_NickServ:%_ The ircnet %_$0%_ doesn\'t exists in the NickServ ircnet list, please add it first.',
90 'saved_nickname', '%R>>%n %_NickServ:%_ Added nickname %_$1%_ on %_$0%_.',
91 'network_print', '$[!-2]0 $[20]1 $2',
92 'password_request', '%R>>%n %_NickServ:%_ Auth Request from NickServ on %_$0%_.',
93 'password_accepted', '%R>>%n %_NickServ:%_ Password accepted on %_$0%_.',
94 'password_wrong', '%R>>%n %_NickServ:%_ Password denied on %_$0%_. Please change the password.',
95 'network_info', '%_ # Ircnet Services hostname%_',
96 'network_empty', '%R>>%n %_NickServ:%_ Your NickServ ircnet list is empty.',
97 'nickname_print', '$[!-2]0 $[20]1 $[18]2 $3',
98 'nickname_info', '%_ # Ircnet Nickname Password%_',
99 'nickname_empty', '%R>>%n %_NickServ:%_ Your NickServ authlist is empty.',
100 'nickserv_help', '$0',
101 'saved_network', '%R>>%n %_NickServ:%_ Added services mask "%_$1%_" on %_$0%_.',
102 'nickserv_loaded', '%R>>%n %_Scriptinfo:%_ Loaded $0 version $1 by $2.'
103 ]);
104
105 sub load_nickservnet {
106
107 my ($file) = @_;
108
109 @nickservnet = ();
110
111 if (-e $file) {
112 local *F;
113 open(F, "<$file");
114 local $/ = "\n";
115
116 while (<F>) {
117 chop;
118 my $new_nsnet = new_nickserv_network(split("\t"));
119
120 if (($new_nsnet->{name} ne "") && ($new_nsnet->{host} ne "")) {
121 push(@nickservnet, $new_nsnet);
122 }
123 }
124
125 close(F);
126 }
127 }
128
129 sub save_nickservnet {
130
131 my ($file) = @_;
132
133 return unless scalar @nickservnet; # there's nothing to save
134
135 if (-e $file) {
136 local *F;
137 open(F, ">$file");
138
139 for (my $n = 0; $n < @nickservnet; ++$n) {
140 print(F join("\t", $nickservnet[$n]->{name}, $nickservnet[$n]->{host}) . "\n");
141 }
142
143 close(F);
144 } else {
145 create_network_file($file);
146 save_nickservnet($file);
147 }
148 }
149
150 sub create_network_file {
151
152 my ($file) = @_;
153
154 open(F, ">$file") or die "Can't create $file. Reason: $!";
155 }
156
157 sub new_nickserv_network {
158
159 my $nsnet = {};
160
161 $nsnet->{name} = shift;
162 $nsnet->{host} = shift;
163
164 return $nsnet;
165 }
166
167 sub load_nickservnick {
168
169 my ($file) = @_;
170
171 @nickservauth = ();
172
173 if (-e $file) {
174 local *F;
175 open(F, "<$file");
176 local $/ = "\n";
177
178 while (<F>) {
179 chop;
180 my $new_nsnick = new_nickserv_nick(split("\t"));
181
182 if (($new_nsnick->{ircnet} ne "") && ($new_nsnick->{nick} ne "") && ($new_nsnick->{pass} ne "")) {
183 push(@nickservauth, $new_nsnick);
184 }
185 }
186
187 close(F);
188 }
189 }
190
191 sub save_nickservnick {
192
193 my ($file) = @_;
194
195 return unless scalar @nickservauth; # there's nothing to save
196
197 if (-e $file) {
198 local *F;
199 open(F, ">$file");
200
201 for (my $n = 0; $n < @nickservauth; ++$n) {
202 print(F join("\t", $nickservauth[$n]->{ircnet}, $nickservauth[$n]->{nick}, $nickservauth[$n]->{pass}) . "\n");
203 }
204
205 close(F);
206 } else {
207 create_nick_file($file);
208 save_nickservnick($file);
209 }
210 }
211
212 sub create_nick_file {
213
214 my ($file) = @_;
215
216 my $umask = umask 0077; # save old umask
217 open(F, ">$file") or die "Can't create $file. Reason: $!";
218 umask $umask;
219 }
220
221 sub new_nickserv_nick {
222
223 my $nsnick = {};
224
225 $nsnick->{ircnet} = shift;
226 $nsnick->{nick} = shift;
227 $nsnick->{pass} = shift;
228
229 return $nsnick;
230 }
231
232 sub add_nickname {
233
234 my ($network, $nickname, $password) = split(" ", @_[0], 3);
235 my ($correct_network, $correct_nickname, $correct_password);
236
237 if ($network eq "" || $nickname eq "" || $password eq "") {
238 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_usage_nickname');
239 return;
240 }
241
242 if ($network) {
243 if (!already_loaded_net($network)) {
244 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_not_loaded_net', $network);
245 return;
246 } else {
247 $correct_network = 1;
248 }
249 }
250
251 if ($nickname) {
252 if (already_loaded_nick($nickname, $network)) {
253 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_loaded_nick', $nickname, $network);
254 return;
255 } else {
256 $correct_nickname = 1;
257 }
258 }
259
260 if ($correct_network && $correct_nickname) {
261 push(@nickservauth, new_nickserv_nick($network, $nickname, $password));
262 save_nickservnick("$irssidir/$nickservauth_file");
263
264 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'saved_nickname', $network, $nickname);
265 }
266 }
267
268 sub add_network {
269
270 my ($network, $hostname) = split(" ", @_[0], 2);
271 my ($correct_net, $correct_host);
272
273 if ($network eq "" || $hostname eq "") {
274 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_usage_network');
275 return;
276 }
277
278 if ($network) {
279 my ($ircnet) = Irssi::chatnet_find($network);
280
281 if (!$ircnet) {
282 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_no_net', $network);
283 return;
284 } elsif (already_loaded_net($network)) {
285 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'already_loaded_network', $network);
286 return;
287 } else {
288 $correct_net = 1;
289 }
290 }
291
292 if ($hostname) {
293 if ($hostname !~ /^[.+a-zA-Z0-9_-]{1,9}@[.+a-zA-Z0-9_-]{1,}$/) {
294 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_wrong_host', $hostname);
295 return;
296 } else {
297 $correct_host = 1;
298 }
299 }
300
301 if ($correct_net && $correct_host) {
302 push(@nickservnet, new_nickserv_network($network, $hostname));
303 save_nickservnet("$irssidir/$nickservnet_file");
304
305 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'saved_network', $network, $hostname);
306 }
307 }
308
309 sub already_loaded_net {
310
311 my ($ircnet) = @_;
312 my $loaded = check_loaded_net($ircnet);
313
314 if ($loaded > -1) {
315 return 1;
316 }
317
318 return 0;
319 }
320
321 sub check_loaded_net {
322
323 my ($ircnet) = @_;
324
325 $ircnet = lc($ircnet);
326
327 for (my $loaded = 0; $loaded < @nickservnet; ++$loaded) {
328 return $loaded if (lc($nickservnet[$loaded]->{name}) eq $ircnet);
329 }
330
331 return -1;
332 }
333
334 sub already_loaded_nick {
335
336 my ($nickname, $network) = @_;
337 my $loaded = check_loaded_nick($nickname, $network);
338
339 if ($loaded > -1) {
340 return 1;
341 }
342
343 return 0
344 }
345
346 sub check_loaded_nick {
347
348 my ($nickname, $network) = @_;
349
350 $nickname = lc($nickname);
351 $network = lc($network);
352
353 for (my $loaded = 0; $loaded < @nickservauth; ++$loaded) {
354 return $loaded if (lc($nickservauth[$loaded]->{nick}) eq $nickname && lc ($nickservauth[$loaded]->{ircnet}) eq $network);
355 }
356
357 return -1;
358 }
359
360 sub list_net {
361
362 if (@nickservnet == 0) {
363 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'network_empty');
364 } else {
365 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'network_info');
366
367 for (my $n = 0; $n < @nickservnet ; ++$n) {
368 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'network_print', $n, $nickservnet[$n]->{name}, $nickservnet[$n]->{host});
369 }
370 }
371 }
372
373 sub list_nick {
374
375 if (@nickservauth == 0) {
376 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickname_empty');
377 } else {
378 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickname_info');
379
380 for (my $n = 0; $n < @nickservauth ; ++$n) {
381 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickname_print', $n, $nickservauth[$n]->{ircnet}, $nickservauth[$n]->{nick}, "*" x length($nickservauth[$n]->{pass}));
382 }
383 }
384 }
385
386 sub nickserv_notice {
387
388 my ($server, $data, $nick, $address) = @_;
389 my ($target, $text) = $data =~ /^(\S*)\s:(.*)/;
390
391 if (is_nickserv($server->{tag}, $address)) {
392 if ($text =~ /^If this is your nickname, type \/msg NickServ/ || $text =~ /^This nickname is registered and protected. If it is your/ || $text =~ /This nickname is registered\. Please choose a different nickname,/ || $text =~ /^This nickname is registered. Please choose a different nickname/) {
393 my $password = get_password($server->{tag}, $server->{nick});
394
395 if ($password == -1) {
396 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_request', $server->{tag});
397 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound_nick', $server->{nick}, $server->{tag});
398 Irssi::signal_stop();
399 return;
400 }
401
402 Irssi::signal_stop();
403 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_request', $server->{tag});
404 $server->command("^MSG NickServ IDENTIFY $password");
405 } elsif ($text =~ /If this is your nickname, type \/NickServ/) {
406 my $password = get_password($server->{tag}, $server->{nick});
407
408 if ($password == -1) {
409 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_request', $server->{tag});
410 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound_nick', $server->{nick}, $server->{tag});
411 Irssi::signal_stop();
412 return;
413 }
414
415 Irssi::signal_stop();
416 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_request', $server->{tag});
417 $server->command("^QUOTE NickServ :IDENTIFY $password");
418 } elsif ($text =~ /If this is your nickname, type \/msg NS/) {
419 my $password = get_password($server->{tag}, $server->{nick});
420
421 if ($password == -1) {
422 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_request', $server->{tag});
423 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound_nick', $server->{nick}, $server->{tag});
424 Irssi::signal_stop();
425 return;
426 }
427
428 Irssi::signal_stop();
429 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_request', $server->{tag});
430 $server->command("^MSG NS IDENTIFY $password");
431 } elsif ($text =~ /If you do not (.*) within one minute, you will be disconnected/) {
432 Irssi::signal_stop();
433 } elsif ($text =~ /^This nickname is owned by someone else/) {
434 Irssi::signal_stop();
435 } elsif ($text =~ /^nick, type (.*) Otherwise,/) {
436 Irssi::signal_stop();
437 } elsif ($text =~ /^please choose a different nick./) {
438 Irssi::signal_stop();
439 } elsif ($text =~ /^You have already identified/ || $text =~ /^This nick is already identified./) {
440 Irssi::signal_stop();
441 } elsif ($text =~ /^Password accepted - you are now recognized/) {
442 Irssi::signal_stop();
443 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_accepted', $server->{tag});
444 } elsif ($text =~ /^Password Incorrect/ || $text =~ /^Password incorrect./) {
445 Irssi::signal_stop();
446 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_wrong', $server->{tag});
447 }
448 }
449 }
450
451 sub is_nickserv {
452
453 my ($net, $host) = @_;
454
455 for (my $loaded = 0; $loaded < @nickservnet; ++$loaded) {
456 return 1 if (lc($nickservnet[$loaded]->{name}) eq lc($net) && lc($nickservnet[$loaded]->{host}) eq lc($host));
457 }
458 return 0;
459 }
460
461 sub get_password {
462
463 my ($ircnet, $nick) = @_;
464
465 for (my $loaded = 0; $loaded < @nickservauth; ++$loaded) {
466 return $nickservauth[$loaded]->{pass} if (lc($nickservauth[$loaded]->{ircnet}) eq lc($ircnet) && lc($nickservauth[$loaded]->{nick}) eq lc($nick));
467 }
468
469 return -1;
470 }
471
472 sub del_network {
473
474 my ($ircnet) = split(" ", @_[0], 1);
475 my ($ircnetindex);
476
477 if ($ircnet eq "") {
478 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delusage');
479 return;
480 }
481
482 for (my $index = 0; $index < @nickservnet; ++$index) {
483 if (lc($nickservnet[$index]->{name}) eq lc($ircnet)) {
484 $ircnetindex = 1;
485 }
486 }
487
488 if ($ircnetindex) {
489 @nickservnet = grep {lc($_->{name}) ne lc($ircnet)} @nickservnet;
490 @nickservauth = grep {lc($_->{ircnet}) ne lc($ircnet)} @nickservauth;
491 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delled', $ircnet);
492 save_nickservnet("$irssidir/$nickservnet_file");
493 save_nickservnick("$irssidir/$nickservauth_file");
494 } else {
495 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound', $ircnet);
496 }
497 }
498
499 sub del_nickname {
500
501 my ($ircnet, $nickname) = split(" ", @_[0], 2);
502 my ($nickindex);
503
504 if ($ircnet eq "" || $nickname eq "") {
505 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delnickusage');
506 return;
507 }
508
509 for (my $index = 0; $index < @nickservauth; ++$index) {
510 if (lc($nickservauth[$index]->{ircnet}) eq lc($ircnet) && lc($nickservauth[$index]->{nick}) eq lc($nickname)) {
511 $nickindex = splice(@nickservauth, $index, 1);
512 }
513 }
514
515 if ($nickindex) {
516 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delled_nick', $ircnet, $nickname);
517 save_nickservnick("$irssidir/$nickservauth_file");
518 } else {
519 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound_nick', $ircnet, $nickname);
520 }
521 }
522
523 sub nickserv_runsub {
524
525 my ($data, $server, $item) = @_;
526 $data =~ s/\s+$//g;
527
528 if ($data) {
529 Irssi::command_runsub('nickserv', $data, $server, $item);
530 } else {
531 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_usage');
532 }
533 }
534
535 load_nickservnet("$irssidir/$nickservnet_file");
536 load_nickservnick("$irssidir/$nickservauth_file");
537
538 Irssi::command_bind('nickserv', 'nickserv_runsub');
539 Irssi::command_bind('ns', 'nickserv_runsub');
540
541 Irssi::command_bind('nickserv addnet', 'add_network');
542 Irssi::command_bind('ns addnet', 'add_network');
543
544 Irssi::command_bind('nickserv addnick', 'add_nickname');
545 Irssi::command_bind('ns addnick', 'add_nickname');
546
547 Irssi::command_bind('nickserv listnet', 'list_net');
548 Irssi::command_bind('ns listnet', 'list_net');
549
550 Irssi::command_bind('nickserv listnick', 'list_nick');
551 Irssi::command_bind('ns listnick', 'list_nick');
552
553 Irssi::command_bind('nickserv delnet', 'del_network');
554 Irssi::command_bind('ns delnet', 'del_network');
555
556 Irssi::command_bind('nickserv delnick', 'del_nickname');
557 Irssi::command_bind('ns delnick', 'del_nickname');
558
559 Irssi::command_bind('nickserv help' => sub { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_help', $help) });
560 Irssi::command_bind('ns help' => sub { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_help', $help) });
561
562 Irssi::signal_add('event notice', 'nickserv_notice');
563 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_loaded', $IRSSI{name}, $VERSION, $IRSSI{authors});