1#!/usr/local/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
23use strict;
24use Irssi;
25use vars qw($VERSION %IRSSI);
26
27$VERSION = "1.12";
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         => 'https://github.com/irssi/scripts.irssi.org/blob/master/scripts/nickserv.pl',
36    changed     => 'Wed Jun 27 19:23 CEST 2018',
37);
38
39my $irssidir = Irssi::get_irssi_dir();
40
41my @nickservnet = ();
42my $nickservnet_file = "$irssidir/nickserv.networks";
43
44my @nickservauth = ();
45my $nickservauth_file = "$irssidir/nickserv.auth";
46
47my @nickservpostcmd = ();
48my $nickservpostcmd_file = "$irssidir/nickserv.postcmd";
49
50my $help = <<EOF;
51
52Usage: (all on one line)
53/NICKSERV [addnet <ircnet> <services\@host>]
54          [addnick <ircnet> <nickname> <password>]
55          [addpostcmd <ircnet> <nickname> <command>]
56          [delnet <ircnet>]
57          [delnick <ircnet> <nick>]
58          [delpostcmd <ircnet> <nick>]
59          [help listnet listnick listpostcmd]
60
61addnet:      Add a new network into the NickServ list.
62addnick:     Add a new nickname into the NickServ list.
63addpostcmd:  Add a new post auth command for nickname into the NickServ list.
64delnet:      Delete a network from the NickServ list.
65delnick:     Delete a nickname from the NickServ list.
66delpostcmd:  Deletes all post auth commands for the given nickame.
67listnet:     Display the contents of the NickServ network list.
68listnick:    Display the contents of the NickServ nickname list.
69listpostcmd: Display the contents of the NickServ postcmd list.
70help:        Display this useful little helptext.
71
72Examples: (all on one line)
73/NICKSERV addnet Freenode NickServ\@services.
74/NICKSERV addnick Freenode Geert mypass
75/NICKSERV addpostcmd Freenode Geert ^MSG ChanServ invite #heaven
76
77/NICKSERV delnet Freenode
78/NICKSERV delnick Freenode Geert
79
80Note: This script doesn't allow wildcards into the NickServ hostname. You must use the full services\@host.
81      Both /NICKSERV and /NS are valid commands.
82EOF
83
84Irssi::theme_register([
85    'nickserv_usage_network', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV addnet ircnet services@host%_".',
86    'nickserv_usage_nickname', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV addnick ircnet nickname password%_".',
87    'nickserv_usage_postcmd', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV addpostcmd ircnet nickname command%_".',
88    'nickserv_delusage', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV delnet ircnet%_".',
89    'nickserv_delnickusage', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV delnick ircnet nickname%_".',
90    'nickserv_delpostcmdusage', '%R>>%n %_NickServ:%_ Insufficient parameters: Usage "%_/NICKSERV delpostcmd ircnet nickname%_".',
91    'nickserv_delled', '%R>>%n %_NickServ:%_ Deleted %_$0%_ and it\'s nicknames and post commands from the NickServ ircnet list.',
92    'nickserv_delled_nick', '%R>>%n %_NickServ:%_ Deleted %_$1%_ and it\'s post commands from the NickServ list on $0.',
93    'nickserv_delled_postcmd', '%R>>%n %_NickServ:%_ Deleted all entries for %_$1%_ from the NickServ postcmd list on $0.',
94    'nickserv_nfound', '%R>>%n %_NickServ:%_ The NickServ ircnet %_$0%_ could not be found.',
95    'nickserv_nfound_nick', '%R>>%n %_NickServ:%_ The NickServ nickname %_$0%_ could not be found on $1.',
96    'nickserv_nfound_postcmd', '%R>>%n %_NickServ:%_ The NickServ post commands for nickname %_$1%_ could not be found on $0.',
97    'nickserv_usage', '%R>>%n %_NickServ:%_ Insufficient parameters: Use "%_/NICKSERV help%_" for further instructions.',
98    'nickserv_no_net', '%R>>%n %_NickServ:%_ Unknown Irssi ircnet %_$0%_.',
99    'nickserv_wrong_host', '%R>>%n %_NickServ:%_ Malformed services hostname %_$0%_.',
100    'already_loaded_network', '%R>>%n %_NickServ:%_ The ircnet %_$0%_ already exists in the NickServ ircnet list, please remove it first.',
101    'nickserv_loaded_nick', '%R>>%n %_NickServ:%_ The nickname %_$0%_ already exists in the NickServ authlist on %_$1%_, please remove it first.',
102    'nickserv_not_loaded_net', '%R>>%n %_NickServ:%_ The ircnet %_$0%_ doesn\'t exists in the NickServ ircnet list, please add it first.',
103    'nickserv_not_loaded_nick', '%R>>%n %_NickServ:%_ The nickname %_$0%_ doesn\'t exists in the NickServ authlist on %_$1%_, please add it first.',
104    'saved_nickname', '%R>>%n %_NickServ:%_ Added nickname %_$1%_ on %_$0%_.',
105    'saved_postcmd', '%R>>%n %_NickServ:%_ Added postcmd %_$1%_ on %_$0%_: %_%2%_.',
106    'network_print', '$[!-2]0 $[20]1 $2',
107    'password_request', '%R>>%n %_NickServ:%_ Auth Request from NickServ on %_$0%_.',
108    'password_accepted', '%R>>%n %_NickServ:%_ Password accepted on %_$0%_.',
109    'password_wrong', '%R>>%n %_NickServ:%_ Password denied on %_$0%_. Please change the password.',
110    'network_info', '%_ # Ircnet               Services hostname%_',
111    'network_empty', '%R>>%n %_NickServ:%_ Your NickServ ircnet list is empty.',
112    'nickname_print', '$[!-2]0 $[20]1 $[18]2 $3',
113    'nickname_info', '%_ # Ircnet               Nickname           Password%_',
114    'nickname_empty', '%R>>%n %_NickServ:%_ Your NickServ authlist is empty.',
115    'postcmd_print', '$[!-2]0 $[20]1 $[18]2 $3',
116    'postcmd_info', '%_ # Ircnet               Nickname           Postcmd%_',
117    'postcmd_empty', '%R>>%n %_NickServ:%_ Your NickServ postcmd list is empty.',
118    'nickserv_help', '$0',
119    'saved_network', '%R>>%n %_NickServ:%_ Added services mask "%_$1%_" on %_$0%_.',
120    'nickserv_loaded', '%R>>%n %_Scriptinfo:%_ Loaded $0 version $1 by $2.'
121]);
122
123sub load_nickservnet {
124
125    my ($file) = @_;
126
127    @nickservnet = load_file($file, sub {
128        my $new_nsnet = new_nickserv_network(@_);
129        return undef if ($new_nsnet->{name} eq "" || $new_nsnet->{host} eq "");
130        return $new_nsnet;
131    });
132}
133
134sub save_nickservnet {
135
136    save_file($nickservnet_file, \@nickservnet, \&nickservnet_as_list);
137}
138
139sub new_nickserv_network {
140
141    return {
142        name => shift,
143        host => shift
144    };
145}
146
147sub nickservnet_as_list {
148
149    my $nickserv_net = shift;
150
151    return (
152      $nickserv_net->{name},
153      $nickserv_net->{host}
154    );
155}
156
157sub load_nickservnick {
158
159    my ($file) = @_;
160
161    @nickservauth = load_file($file, sub {
162        my $new_nsnick = new_nickserv_nick(@_);
163
164        return undef if ($new_nsnick->{ircnet} eq "" || $new_nsnick->{nick} eq "" || $new_nsnick->{pass} eq "");
165        return $new_nsnick;
166    });
167}
168
169sub save_nickservnick {
170
171    save_file($nickservauth_file, \@nickservauth, \&nickserv_nick_as_list);
172}
173
174sub new_nickserv_nick {
175
176    return {
177        ircnet    => shift,
178        nick      => shift,
179        pass      => shift
180    };
181}
182
183sub nickserv_nick_as_list {
184
185    my $nickserv_nick = shift;
186    return (
187        $nickserv_nick->{ircnet},
188        $nickserv_nick->{nick},
189        $nickserv_nick->{pass}
190    );
191}
192
193sub load_nickservpostcmd {
194
195    my ($file) = @_;
196
197    @nickservpostcmd = load_file($file, sub {
198        my $new_postcmd = new_postcmd(@_);
199
200        return undef if ($new_postcmd->{ircnet} eq "" || $new_postcmd->{nick} eq "" || $new_postcmd->{postcmd} eq "");
201        return $new_postcmd;
202    });
203}
204
205sub save_nickservpostcmd {
206
207    save_file($nickservpostcmd_file, \@nickservpostcmd, \&postcmd_as_list);
208}
209
210sub new_postcmd {
211
212    return {
213        ircnet    => shift,
214        nick      => shift,
215        postcmd   => shift
216    };
217}
218
219sub postcmd_as_list {
220    my $postcmd = shift;
221
222    return (
223        $postcmd->{ircnet},
224        $postcmd->{nick},
225        $postcmd->{postcmd}
226    );
227}
228
229# file: filename to be read
230# parse_line_fn: receives array of entries of a single line as input, should
231#     return parsed data object or undef in the data is incomplete
232# returns: parsed data array
233sub load_file {
234
235  my ($file, $parse_line_fn) = @_;
236  my @parsed_data = ();
237
238  if (-e $file) {
239    open(my $fh, "<", $file);
240    local $/ = "\n";
241
242    while (<$fh>) {
243      chomp;
244      my $data = $parse_line_fn->(split("\t"));
245      push(@parsed_data, $data) if $data;
246    }
247
248    close($fh);
249  }
250
251  return @parsed_data;
252}
253
254# file: filename to be written, is created accessable only by the user
255# data_ref: array ref of data entries
256# serialize_fn: receives a data reference and should return an array or tuples
257#     for that data that will be serialized into one line
258sub save_file {
259
260    my ($file, $data_ref, $serialize_fn) = @_;
261
262    create_private_file($file) unless -e $file;
263
264    open(my $fh, ">", $file) or die "Can't create $file. Reason: $!";
265
266    for my $data (@$data_ref) {
267        print($fh join("\t", $serialize_fn->($data)), "\n");
268    }
269
270    close($fh);
271}
272
273sub create_private_file {
274
275    my ($file) = @_;
276    my $umask = umask 0077; # save old umask
277    open(my $fh, ">", $file) or die "Can't create $file. Reason: $!";
278    close($fh);
279    umask $umask;
280}
281
282sub add_nickname {
283
284    my ($network, $nickname, $password) = split(" ", $_[0], 3);
285    my ($correct_network, $correct_nickname);
286
287    if ($network eq "" || $nickname eq "" || $password eq "") {
288        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_usage_nickname');
289        return;
290    }
291
292    if ($network) {
293        if (!already_loaded_net($network)) {
294            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_not_loaded_net', $network);
295            return;
296        } else {
297            $correct_network = 1;
298        }
299    }
300
301    if ($nickname) {
302        if (already_loaded_nick($nickname, $network)) {
303            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_loaded_nick', $nickname, $network);
304            return;
305        } else {
306            $correct_nickname = 1;
307        }
308    }
309
310    if ($correct_network && $correct_nickname) {
311        push(@nickservauth, new_nickserv_nick($network, $nickname, $password));
312        save_nickservnick();
313
314        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'saved_nickname', $network, $nickname);
315    }
316}
317
318sub add_postcmd {
319
320    my ($network, $nickname, $postcmd) = split(" ", $_[0], 3);
321    my ($correct_network, $correct_nickname);
322
323    if ($network eq "" || $nickname eq "" || $postcmd eq "") {
324        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_usage_postcmd');
325        return;
326    }
327
328    if ($network) {
329        if (!already_loaded_net($network)) {
330            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_not_loaded_net', $network);
331            return;
332        } else {
333            $correct_network = 1;
334        }
335    }
336
337    if ($nickname) {
338        if (!already_loaded_nick($nickname, $network)) {
339            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_not_loaded_nick', $nickname, $network);
340            return;
341        } else {
342            $correct_nickname = 1;
343        }
344    }
345
346    if ($correct_network && $correct_nickname) {
347        push(@nickservpostcmd, new_postcmd($network, $nickname, $postcmd));
348        save_nickservpostcmd();
349
350        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'saved_postcmd', $network, $nickname, $postcmd);
351    }
352}
353
354sub add_network {
355
356    my ($network, $hostname) = split(" ", $_[0], 2);
357    my ($correct_net, $correct_host);
358
359    if ($network eq "" || $hostname eq "") {
360        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_usage_network');
361        return;
362    }
363
364    if ($network) {
365        my ($ircnet) = Irssi::chatnet_find($network);
366
367        if (!$ircnet) {
368            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_no_net', $network);
369            return;
370        } elsif (already_loaded_net($network)) {
371            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'already_loaded_network', $network);
372            return;
373        } else {
374            $correct_net = 1;
375        }
376    }
377
378    if ($hostname) {
379        if ($hostname !~ /^[.+a-zA-Z0-9_-]{1,}@[.+a-zA-Z0-9_-]{1,}$/) {
380            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_wrong_host', $hostname);
381            return;
382        } else {
383            $correct_host = 1;
384        }
385    }
386
387    if ($correct_net && $correct_host) {
388        push(@nickservnet, new_nickserv_network($network, $hostname));
389        save_nickservnet();
390
391        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'saved_network', $network, $hostname);
392    }
393}
394
395sub already_loaded_net {
396
397    my ($ircnet) = @_;
398
399    $ircnet = lc($ircnet);
400
401    for my $loaded (@nickservnet) {
402        return 1 if (lc($loaded->{name}) eq $ircnet);
403    }
404
405    return 0;
406}
407
408sub already_loaded_nick {
409    my ($nickname, $network) = @_;
410
411    $nickname = lc($nickname);
412    $network = lc($network);
413
414    for my $loaded (@nickservauth) {
415        return 1 if (lc($loaded->{nick}) eq $nickname &&
416                     lc($loaded->{ircnet}) eq $network);
417    }
418
419    return 0;
420}
421
422sub list_net {
423
424    if (@nickservnet == 0) {
425        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'network_empty');
426    } else {
427        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'network_info');
428
429        for (my $n = 0; $n < @nickservnet ; ++$n) {
430            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'network_print', $n, $nickservnet[$n]->{name}, $nickservnet[$n]->{host});
431        }
432    }
433}
434
435sub list_nick {
436
437    if (@nickservauth == 0) {
438        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickname_empty');
439    } else {
440        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickname_info');
441
442        for (my $n = 0; $n < @nickservauth ; ++$n) {
443            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickname_print', $n, $nickservauth[$n]->{ircnet}, $nickservauth[$n]->{nick}, "*" x length($nickservauth[$n]->{pass}));
444        }
445    }
446}
447
448sub list_postcmd {
449
450    if (@nickservpostcmd == 0) {
451        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'postcmd_empty');
452    } else {
453        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'postcmd_info');
454
455        for (my $n = 0; $n < @nickservpostcmd ; ++$n) {
456            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'postcmd_print', $n, $nickservpostcmd[$n]->{ircnet}, $nickservpostcmd[$n]->{nick}, $nickservpostcmd[$n]->{postcmd});
457        }
458    }
459}
460
461sub nickserv_notice {
462
463    my ($server, $data, $nick, $address) = @_;
464    my ($target, $text) = $data =~ /^(\S*)\s:(.*)/;
465
466    if (is_nickserv($server->{tag}, $address)) {
467        $text =~ s/[[:cntrl:]]+//g; # remove control crap
468
469        if ($text =~ /^(?:\(?If this is your nick(?:name)?, type|Please identify via|Type) \/msg NickServ (?i:identify)/ || $text =~ /^This nickname is registered and protected.  If it is your/ || $text =~ /This nickname is registered\. Please choose a different nickname/) {
470            my $password = get_password($server->{tag}, $server->{nick});
471
472            if ($password == -1) {
473                Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_request', $server->{tag});
474                Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound_nick', $server->{nick}, $server->{tag});
475                Irssi::signal_stop();
476                return;
477            }
478
479            Irssi::signal_stop();
480            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_request', $server->{tag});
481            $server->command("^MSG NickServ IDENTIFY $password");
482        } elsif ($text =~ /If this is your nickname, type \/NickServ/) {
483            my $password = get_password($server->{tag}, $server->{nick});
484
485            if ($password == -1) {
486                Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_request', $server->{tag});
487                Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound_nick', $server->{nick}, $server->{tag});
488                Irssi::signal_stop();
489                return;
490            }
491
492            Irssi::signal_stop();
493            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_request', $server->{tag});
494            $server->command("^QUOTE NickServ :IDENTIFY $password");
495        } elsif ($text =~ /If this is your nickname, type \/msg NS/) {
496            my $password = get_password($server->{tag}, $server->{nick});
497
498            if ($password == -1) {
499                Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_request', $server->{tag});
500                Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound_nick', $server->{nick}, $server->{tag});
501                Irssi::signal_stop();
502                return;
503            }
504
505            Irssi::signal_stop();
506            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_request', $server->{tag});
507            $server->command("^MSG NS IDENTIFY $password");
508        } elsif ($text =~ /If you do not (.*) within one minute, you will be disconnected/) {
509            Irssi::signal_stop();
510        } elsif ($text =~ /^This nickname is owned by someone else/) {
511            Irssi::signal_stop();
512        } elsif ($text =~ /^nick, type (.*)  Otherwise,/) {
513            Irssi::signal_stop();
514        } elsif ($text =~ /^please choose a different nick./) {
515            Irssi::signal_stop();
516        } elsif ($text =~ /^You have already identified/ || $text =~ /^This nick is already identified./ || $text =~ /^You are already logged in as/) {
517            Irssi::signal_stop();
518        } elsif ($text =~ /^Password accepted - you are now recognized/ || $text =~ /^You are now identified for/) {
519            Irssi::signal_stop();
520            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_accepted', $server->{tag});
521            run_postcmds($server, $server->{tag}, $server->{nick})
522        } elsif ($text =~ /^Password Incorrect/ || $text =~ /^Password incorrect./) {
523            Irssi::signal_stop();
524            Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'password_wrong', $server->{tag});
525        }
526    }
527}
528
529sub run_postcmds {
530	my ($server, $ircnet, $nick) = @_;
531	return if @nickservpostcmd == 0;
532
533	for my $cmd (@nickservpostcmd) {
534		if ($ircnet eq $cmd->{ircnet} &&
535        $nick   eq $cmd->{nick} &&
536        $cmd->{postcmd}) {
537			$server->command($cmd->{postcmd});
538		}
539	}
540}
541
542sub is_nickserv {
543
544    my ($net, $host) = @_;
545
546    for (my $loaded = 0; $loaded < @nickservnet; ++$loaded) {
547        return 1 if (lc($nickservnet[$loaded]->{name}) eq lc($net) &&
548                     lc($nickservnet[$loaded]->{host}) eq lc($host));
549    }
550    return 0;
551}
552
553sub get_password {
554
555    my ($ircnet, $nick) = @_;
556
557    for (my $loaded = 0; $loaded < @nickservauth; ++$loaded) {
558        return $nickservauth[$loaded]->{pass} if (lc($nickservauth[$loaded]->{ircnet}) eq lc($ircnet) &&
559                                                  lc($nickservauth[$loaded]->{nick}) eq lc($nick));
560    }
561
562    return -1;
563}
564
565sub del_network {
566
567    my ($ircnet) = split(" ", $_[0], 1);
568    my ($ircnetindex);
569
570    if ($ircnet eq "") {
571        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delusage');
572        return;
573    }
574
575    for (my $index = 0; $index < @nickservnet; ++$index) {
576        if (lc($nickservnet[$index]->{name}) eq lc($ircnet)) {
577            $ircnetindex = 1;
578        }
579    }
580
581    if ($ircnetindex) {
582        @nickservnet = grep {lc($_->{name}) ne lc($ircnet)} @nickservnet;
583        @nickservauth = grep {lc($_->{ircnet}) ne lc($ircnet)} @nickservauth;
584        @nickservpostcmd = grep {lc($_->{ircnet}) ne lc($ircnet)} @nickservpostcmd;
585        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delled', $ircnet);
586        save_nickservnet();
587        save_nickservnick();
588        save_nickservpostcmd();
589    } else {
590        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound', $ircnet);
591    }
592}
593
594sub del_nickname {
595
596    my ($ircnet, $nickname) = split(" ", $_[0], 2);
597    my ($nickindex);
598
599    if ($ircnet eq "" || $nickname eq "") {
600        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delnickusage');
601        return;
602    }
603
604    for (my $index = 0; $index < @nickservauth; ++$index) {
605        if (lc($nickservauth[$index]->{ircnet}) eq lc($ircnet) &&
606            lc($nickservauth[$index]->{nick}) eq lc($nickname)) {
607            $nickindex = splice(@nickservauth, $index, 1);
608        }
609    }
610
611    if ($nickindex) {
612        @nickservpostcmd = grep {lc($_->{ircnet}) ne lc($ircnet) ||
613                                 lc($_->{nick}) ne lc($nickname)}
614                           @nickservpostcmd;
615
616        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delled_nick', $ircnet, $nickname);
617        save_nickservnick();
618        save_nickservpostcmd();
619    } else {
620        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound_nick', $ircnet, $nickname);
621    }
622}
623
624sub del_postcmd {
625
626    my ($ircnet, $nickname) = split(" ", $_[0], 2);
627
628    if ($ircnet eq "" || $nickname eq "") {
629        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delpostcmdusage');
630        return;
631    }
632
633    my $size_before = scalar(@nickservpostcmd);
634    @nickservpostcmd = grep { !( lc($_->{ircnet}) eq lc($ircnet) && lc($_->{nick}) eq lc($nickname) )} @nickservpostcmd;
635    my $size_after = scalar(@nickservpostcmd);
636
637    if ($size_before != $size_after) {
638        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_delled_postcmd', $ircnet, $nickname);
639        save_nickservpostcmd();
640    } else {
641        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_nfound_postcmd', $ircnet, $nickname);
642    }
643}
644
645sub nickserv_runsub {
646
647    my ($data, $server, $item) = @_;
648    $data =~ s/\s+$//g;
649
650    if ($data) {
651        Irssi::command_runsub('nickserv', $data, $server, $item);
652    } else {
653        Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_usage');
654    }
655}
656
657load_nickservnet($nickservnet_file);
658load_nickservnick($nickservauth_file);
659load_nickservpostcmd($nickservpostcmd_file);
660
661Irssi::command_bind('nickserv', 'nickserv_runsub');
662Irssi::command_bind('ns', 'nickserv_runsub');
663
664Irssi::command_bind('nickserv help' => sub { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_help', $help) });
665Irssi::command_bind('ns help' => sub { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_help', $help) });
666
667# "command binding" -> "function name" mapping
668for my $cmd ((
669  ['addnet'       => 'add_network'],
670  ['addnick'      => 'add_nickname'],
671  ['addpostcmd'   => 'add_postcmd'],
672  ['listnet'      => 'list_net'],
673  ['listnick'     => 'list_nick'],
674  ['listpostcmd'  => 'list_postcmd'],
675  ['delnet'       => 'del_network'],
676  ['delnick'      => 'del_nickname'],
677  ['delpostcmd'   => 'del_postcmd'],
678)) {
679  Irssi::command_bind("nickserv $cmd->[0]", $cmd->[1]);
680  Irssi::command_bind("ns $cmd->[0]",       $cmd->[1]);
681}
682
683Irssi::signal_add('event notice', 'nickserv_notice');
684Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'nickserv_loaded', $IRSSI{name}, $VERSION, $IRSSI{authors});
685