1#
2# $Id: nickident.pl 1736 2007-02-01 14:13:24Z cb $
3#
4# NickServ interface
5#  Original code by Sami Haahtinen / ZaNaGa
6#  Protected channel support added by David McNett <nugget@slacker.com>
7#  Heavily patched by Christoph Berg <cb@df7cb.de>
8#
9
10use strict;
11use vars qw($VERSION %IRSSI);
12
13$VERSION = '20070201';
14%IRSSI = (
15    authors     => 'Sami Haahtinen, Christoph Berg',
16    name        => 'nickident',
17    description => 'identify to nickserv',
18    url         => 'http://cvsweb.oftc.net/svn/oftc-tools/trunk/user/irssi/',
19    license     => 'public domain',
20);
21
22my $name = "nickident";
23my $nickserv_passfile = glob "~/.irssi/nickserv.users";
24my $nickserv_chanfile = glob "~/.irssi/nickserv.channels";
25my @users = ();
26my @chans = ();
27my %nickservs = (
28	openprojects => [ 'NickServ', 'NickServ@services.' ],
29	sourceirc    => [ 'NickServ', 'services@sourceirc.net' ],
30	cuckoonet    => [ 'NickServ', 'services@irc.cuckoo.com' ],
31	slashnet     => [ 'NickServ', 'services@services.slashnet.org' ],
32	roxnet       => [ 'NickServ', 'services@ircsystems.net' ],
33	oftc         => [ 'NickServ', 'services@services.oftc.net' ],
34	techno       => [ 'NickServ', 'services@campus-sbg.at' ],
35	euirc        => [ 'NickServ', 'anope@services.eu-irc.net' ],
36	cacert       => [ 'NickServ', 'services@wireless' ],
37);
38
39use Irssi;
40use Irssi::Irc;
41
42sub join_channels {
43	my ($server) = @_;
44	my $current_ircnet = $server->{'tag'};
45
46	#Irssi::print("$name: Joining channels for $current_ircnet");
47	foreach $_ (@chans) {
48		my ($channel, $ircnet) = split(/:/);
49		if ($current_ircnet =~ /^$ircnet$/i) {
50			#Irssi::print("$name: Joining $channel");
51			#$server->send_message("ChanServ", "UNBAN $channel", "-nick");
52			#sleep 1;
53			Irssi::Server::channels_join($server, $channel, 0);
54		}
55	}
56}
57
58sub get_nickpass {
59	my ($current_nick, $current_ircnet) = @_;
60
61	foreach $_ (@users) {
62		my ($nick, $ircnet, $password) = split(/:/);
63		if ($current_nick =~ /^$nick$/i and $current_ircnet =~ /^$ircnet$/i) {
64			return $password;
65		}
66	}
67	return 0;
68}
69
70sub got_nickserv_msg {
71	my ($nick, $server, $text) = @_;
72	my $password;
73
74	if ($password = get_nickpass($server->{'nick'}, $server->{'tag'})) {
75		# The below is for OPN style.. i need to figure out a way to
76		# make this portable
77		if ($text =~ /This nickname is owned by someone else/i) {
78			Irssi::print("$name: Got authrequest from $nick/" . $server->{'tag'});
79			$server->send_message("nickserv", "IDENTIFY $password", "-nick");
80			Irssi::signal_stop();
81		} elsif ($text =~ /^This nickname is registered and protected\.  If it is your/) {
82		        Irssi::print("$name: Got authrequest from $nick/" . $server->{'tag'});
83			$server->send_message("nickserv", "IDENTIFY $password", "-nick");
84			Irssi::signal_stop();
85		# testnet:
86		# is a registered nickname and you are not on its access list
87		# authenticate yourself to services ^Bnow^B
88		} elsif ($text =~ /^This nick is registered\.  Please choose another\.|is a registered nickname and you are not on its access list|authenticate yourself to services/) {
89		        Irssi::print("$name: Got authrequest from $nick/" . $server->{'tag'});
90			$server->send_message("nickserv", "IDENTIFY $password", "-nick");
91			Irssi::signal_stop();
92		} elsif ($text =~ /nick, type.+msg NickServ IDENTIFY.+password.+Otherwise,|please choose a different nick./i) {
93			Irssi::signal_stop();
94		} elsif ($text =~ /Password accepted - you are now recognized./ ||
95		         $text =~ /Wow, you managed to remember your password.  That's a miracle by your usual standard./ ||
96		 	 $text =~ /You are sucessfully identified as/ ) {
97			Irssi::print("$name: Got a positive response from $nick/" . $server->{'tag'});
98			join_channels($server);
99			Irssi::signal_stop();
100		}
101	}
102}
103
104sub event_nickserv_message {
105	my ($server, $data, $nick, $address) = @_;
106	my ($target, $text) = $data =~ /^(\S*)\s:(.*)/;
107
108	foreach my $key (keys %nickservs) {
109		if ( ($nickservs{$key}->[0] =~ /^$nick$/i)
110			and ($nickservs{$key}->[1] =~ /^$address$/i) ) {
111			got_nickserv_msg($nick, $server, $text)
112		}
113	}
114}
115
116sub cmd_nickident {
117	my ($data, $server, $witem) = @_;
118	if (my $password = get_nickpass($server->{'nick'}, $server->{'tag'})) {
119		$server->send_message("nickserv", "IDENTIFY $password", "-nick");
120	} else {
121		Irssi::print("$name: No password for $server->{'nick'}/$server->{'tag'} found");
122	}
123}
124
125sub create_users {
126	Irssi::print("$name: Creating basic userfile in $nickserv_passfile. please edit it and run /nickserv_read");
127	if(!(open NICKUSERS, ">$nickserv_passfile")) {
128		Irssi::print("$name: Unable to create file $nickserv_passfile");
129	}
130
131	print NICKUSERS "# This file should contain all your protected nicks\n";
132	print NICKUSERS "# with the corresponding ircnet tag and password.\n";
133	print NICKUSERS "#\n";
134	print NICKUSERS "# Nick and IrcNet Tag are case insensitive\n";
135	print NICKUSERS "#\n";
136	print NICKUSERS "# Nick          IrcNet Tag      Password\n";
137	print NICKUSERS "# --------      ----------      --------\n";
138
139	close NICKUSERS;
140	chmod 0600, $nickserv_passfile;
141}
142
143sub create_chans {
144	Irssi::print("$name: Creating basic channelfile in $nickserv_chanfile. please edit it and run /nickserv_read");
145	if(!(open NICKCHANS, ">$nickserv_chanfile")) {
146		Irssi::print("$name: Unable to create file $nickserv_chanfile");
147	}
148
149	print NICKCHANS "# This file should contain a list of all channels\n";
150	print NICKCHANS "# which you don't want to join until after you've\n";
151	print NICKCHANS "# successfully identified with NickServ.  This is\n";
152 	print NICKCHANS "# useful for channels which are access-controlled.\n";
153	print NICKCHANS "#\n";
154	print NICKCHANS "# Channel       IrcNet Tag\n";
155	print NICKCHANS "# --------      ----------\n";
156
157	close NICKCHANS;
158	chmod 0600, $nickserv_chanfile;
159}
160
161sub read_users {
162	my $count = 0;
163	@users = ();
164
165	if (!(open NICKUSERS, "<$nickserv_passfile")) {
166		create_users;
167	};
168
169	# first we test the file with mask 066 (we don't actually care if the
170	# file is executable by others.. what could they do with it =)
171	my $mode = (stat($nickserv_passfile))[2];
172	if ($mode & 066) {
173		Irssi::print("$name: Your password file should be mode 0600. Go fix it!");
174		Irssi::print("$name: Use command: chmod 0600 $nickserv_passfile");
175	}
176
177	# apparently Irssi resets $/, so we set it here.
178	$/ = "\n";
179	while( my $line = <NICKUSERS>) {
180		if ($line =~ /^\s*([^#]\S+)\s+(\S+)\s+(\S+)/) {
181			push @users, "$1:$2:$3";
182			$count++;
183		}
184	}
185	Irssi::print("$name: Found $count accounts");
186
187	close NICKUSERS;
188}
189
190sub read_chans {
191	my $count = 0;
192	@chans = ();
193
194	if (!(open NICKCHANS, "<$nickserv_chanfile")) {
195		create_chans;
196	};
197
198	# first we test the file with mask 066 (we don't actually care if the
199	# file is executable by others.. what could they do with it =)
200	my $mode = (stat($nickserv_chanfile))[2];
201	if ($mode & 066) {
202		Irssi::print("$name: Your channels file should be mode 0600. Go fix it!");
203		Irssi::print("$name: Use command: chmod 0600 $nickserv_chanfile");
204	}
205
206	# apparently Irssi resets $/, so we set it here.
207	$/ = "\n";
208	while( my $line = <NICKCHANS>) {
209		next if /^#\s/;
210		if ($line =~ /^\s*(\S+)\s+(\S+)\s*$/)  {
211			push @chans, "$1:$2";
212			$count++;
213		}
214	}
215	Irssi::print("$name: Found $count channels");
216
217	close NICKCHANS;
218}
219
220sub read_files {
221	read_users();
222	read_chans();
223}
224
225
226Irssi::signal_add("event notice", "event_nickserv_message");
227Irssi::command_bind('nickident_read', 'read_files');
228Irssi::command_bind('nickident', 'cmd_nickident');
229
230read_files();
231