]> jfr.im git - irc/SurrealServices/srsv.git/blame - branches/0.5.0/modules/serviceslibs/nickserv.pm
Remove some debug lines
[irc/SurrealServices/srsv.git] / branches / 0.5.0 / modules / serviceslibs / nickserv.pm
CommitLineData
aecfa1fd 1# This file is part of SurrealServices.
2#
3# SurrealServices is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 2 of the License, or
6# (at your option) any later version.
7#
8# SurrealServices is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with SurrealServices; if not, write to the Free Software
15# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16package nickserv;
17
18use strict;
19use Time::Local;
20use SrSv::Timer qw(add_timer);
21use SrSv::IRCd::State qw($ircline synced initial_synced %IRCd_capabilities);
22use SrSv::Agent;
23use SrSv::Conf qw(main services sql);
24use SrSv::Conf2Consts qw(main services sql);
25use SrSv::HostMask qw(normalize_hostmask hostmask_to_regexp parse_mask parse_hostmask make_hostmask);
26
27use SrSv::MySQL qw( $dbh :sql_types );
28use SrSv::MySQL::Glob;
29
30use SrSv::Shared qw(%newuser %olduser);
31
32use SrSv::Time;
33use SrSv::Text::Format qw(columnar);
34use SrSv::Errors;
35
36use SrSv::Log;
37
38use SrSv::User '/./';
39use SrSv::User::Notice;
40use SrSv::Help qw( sendhelp );
41
42use SrSv::NickReg::Flags;
43use SrSv::NickReg::User '/./';
44use SrSv::Hash::Passwords;
45
46use SrSv::NickControl::Enforcer qw(%enforcers);
47
48use SrSv::Email;
5e682044 49use SrSv::Insp::UUID;
aecfa1fd 50use SrSv::Util qw( makeSeqList );
7b3a5814 51use SrSv::IRCd::Send qw (getAgentRevUuid ircd::getAgentUuid);
aecfa1fd 52use SrSv::Debug;
53
54use SrSv::NickReg::NickText;
55
56use SrSv::IPv6;
57
58require SrSv::MySQL::Stub;
5e682044 59use Data::Dumper;
aecfa1fd 60use constant {
61 # Clone exception max limit.
62 # This number typically means infinite/no-limit.
63 # It is 2**24-1
64 MAX_LIM => 16777215,
65
66 # This could be made a config option
67 # But our config system currently sucks.
68 MAX_PROFILE => 10,
69 # This value likely cannot be increased very far
70 # as the following limits would apply:
71 # 106 (nick/hostmask), 6 (NOTICE), 30 (destination-nick), 32 (key length) = 174
72 # 510 - 174 = 336
73 # but this does not take into account additional spaces/colons
74 # or reformatting by the SrSv::Format code.
75 # Likely the maximum value is ~300
76 MAX_PROFILE_LEN => 250,
77};
78
7d4055c0 79our $nsnick_default = 'NickServ1';
aecfa1fd 80our $nsnick = $nsnick_default;
7b3a5814 81our $nsuser = { NICK => $nsnick, ID => ircd::getAgentUuid($nsnick) }; #FIXME - erry
aecfa1fd 82our $cur_lock;
83our $cnt_lock = 0;
84
85our @protect_short = ('none', 'normal', 'high', 'kill');
86our @protect_long = (
87 'You will not be required to identify to use this nick.',
88 'You must identify within 60 seconds to use this nick.',
89 'You must identify before using this nick.',
90 'You must identify before using this nick or you will be disconnected.'
91);
92our %protect_level = (
93 'none' => 0,
94 'no' => 0,
95 'false' => 0,
96 'off' => 0,
97 '0' => 0,
98
99 'true' => 1,
100 'yes' => 1,
101 'on' => 1,
102 'normal' => 1,
103 '1' => 1,
104
105 'high' => 2,
106 '2' => 2,
107
108 'kill' => 3,
109 '3' => 3
110);
111
112our (
5e682044 113 $nick_check, $nick_checkExists,
114 $nick_create, $nick_create2, $nick_create_old, $nick_change, $nick_quit, $nick_delete, $nick_id_delete,
aecfa1fd 115 $get_quit_empty_chans, $nick_chan_delete, $chan_user_partall,
116 $get_hostless_nicks,
5e682044 117 $id_change,
aecfa1fd 118 $get_squit_lock, $squit_users, $squit_nickreg, $get_squit_empty_chans, $squit_lastquit,
119
120 $del_nickchg_id, $add_nickchg, $reap_nickchg,
121
122 $get_nick_inval, $inc_nick_inval,
123 $is_registered,
124 $is_alias_of,
125
126 $get_guest, $set_guest,
127
128 $get_lock, $release_lock,
129
130 $get_umodes, $set_umodes,
131
132 $get_info,
133 $set_vhost, $set_ident, $set_ip,
134 $update_regnick_vhost, $get_regd_time, $get_nickreg_quit,
135
136 $chk_clone_except, $count_clones,
137
138 $set_pass,
139 $set_email,
140
141 $get_root_nick, $get_id_nick, $chk_pass, $identify, $identify_ign, $id_update, $logout, $unidentify, $unidentify_single,
142 $update_lastseen, $quit_update, $update_nickalias_last,
143 $set_protect_level,
144
145 $get_register_lock, $register, $create_alias, $drop, $change_root,
146
147 $get_aliases, $get_glist, $count_aliases, $get_random_alias, $delete_alias, $delete_aliases,
148 $get_all_access, $del_all_access, $change_all_access, $change_akicks, $change_founders,
149 $change_successors, $change_svsops,
150
151 $lock_user_table, $unlock_tables,
152
153 $get_matching_nicks,
154
155 $cleanup_nickid, $cleanup_users, $cleanup_chanuser,
156 $get_dead_users,
157
158 $get_expired, $get_near_expired, $set_near_expired,
159
160 $get_watches, $check_watch, $set_watch, $del_watch, $drop_watch,
161 $get_silences, $check_silence, $set_silence, $del_silence, $drop_silence,
162 $get_silence_by_num,
163 $get_expired_silences, $del_expired_silences,
164
165 $get_seen,
166
167 $set_greet, $get_greet, $get_greet_nick, $del_greet,
168 $get_num_nicktext_type, $drop_nicktext,
169
170 $get_auth_chan, $get_auth_num, $del_auth, $list_auth, $add_auth,
171
172 $del_nicktext,
173
174 $set_umode_ntf, $get_umode_ntf,
175
176 $set_vacation_ntf, $get_vacation_ntf,
177
178 $set_authcode_ntf, $get_authcode_ntf,
179
180 $get_nicks_by_email,
5e682044 181
182 $nick_deleteChanUser, $nick_deleteNickCh, $nick_deleteNickId,
92c29160 183 $id_delUser, $nick_delUser,
aecfa1fd 184);
185
186sub init() {
1eb006d9 187 $nsuser = { NICK => $nsnick, ID => ircd::getAgentUuid($nsnick) };
aecfa1fd 188 $nick_check = $dbh->prepare("SELECT id FROM user WHERE nick=? AND online=0 AND time=?");
5e682044 189 $nick_checkExists = $dbh -> prepare ("SELECT nick FROM user WHERE id=? AND time=?");
190 $nick_deleteChanUser = $dbh -> prepare ("DELETE FROM chanuser WHERE nickid=?");
191 $nick_deleteNickCh = $dbh -> prepare ("DELETE FROM nickchg WHERE nickid=?");
192 $nick_deleteNickId = $dbh -> prepare ("DELETE FROM nickid WHERE id=?");
193 $id_delUser = $dbh->prepare ("DELETE FROM user WHERE id=?");
92c29160 194 $nick_delUser = $dbh->prepare ("DELETE FROM user WHERE nick=?");
aecfa1fd 195 $nick_create = $dbh->prepare("INSERT INTO user SET nick=?, time=?, inval=0, ident=?, host=?, vhost=?, server=?, modes=?,
196 gecos=?, flags=?, cloakhost=?, online=1");
5e682044 197 $nick_create2 = $dbh->prepare("INSERT INTO user SET id=?, nick=?, time=?, inval=0, ident=?, host=?, vhost=?, server=?, modes=?,
198 gecos=?, flags=?, cloakhost=?, online=1");
aecfa1fd 199# $nick_create = $dbh->prepare("INSERT INTO user SET id=(RAND()*294967293)+1, nick=?, time=?, inval=0, ident=?, host=?, vhost=?, server=?, modes=?, gecos=?, flags=?, cloakhost=?, online=1");
200 $nick_create_old = $dbh->prepare("UPDATE user SET nick=?, ident=?, host=?, vhost=?, server=?, modes=?, gecos=?,
201 flags=?, cloakhost=?, online=1 WHERE id=?");
5e682044 202 $nick_change = $dbh->prepare("UPDATE user SET nick=? WHERE nick=?");
aecfa1fd 203 $nick_quit = $dbh->prepare("UPDATE user SET online=0, quittime=UNIX_TIMESTAMP() WHERE nick=?");
204 $nick_delete = $dbh->prepare("DELETE FROM user WHERE nick=?");
205 $nick_id_delete = $dbh->prepare("DELETE FROM nickid WHERE id=?");
206 $get_quit_empty_chans = $dbh->prepare("SELECT cu2.chan, COUNT(*) AS c
207 FROM chanuser AS cu1, chanuser AS cu2
208 WHERE cu1.nickid=?
209 AND cu1.chan=cu2.chan AND cu1.joined=1 AND cu2.joined=1
210 GROUP BY cu2.chan HAVING c=1 ORDER BY NULL");
211 $nick_chan_delete = $dbh->prepare("DELETE FROM chanuser WHERE nickid=?");
212 $chan_user_partall = $dbh->prepare("UPDATE chanuser SET joined=0 WHERE nickid=?");
213 $get_hostless_nicks = $dbh->prepare("SELECT nick FROM user WHERE vhost='*'");
214
215 $get_squit_lock = $dbh->prepare("LOCK TABLES chanuser WRITE, chanuser AS cu1 READ LOCAL, chanuser AS cu2 READ LOCAL, user WRITE, nickreg WRITE, nickid WRITE, chanban WRITE, chan WRITE, chanreg READ LOCAL, nicktext WRITE");
216 $squit_users = $dbh->prepare("UPDATE chanuser, user
217 SET chanuser.joined=0, user.online=0, user.quittime=UNIX_TIMESTAMP()
218 WHERE user.id=chanuser.nickid AND user.server=?");
219 # Must call squit_nickreg and squit_lastquit before squit_users as it modifies user.online
220 $squit_nickreg = $dbh->prepare("UPDATE nickreg, nickid, user
221 SET nickreg.last=UNIX_TIMESTAMP()
222 WHERE nickreg.id=nickid.nrid AND nickid.id=user.id
223 AND user.online=1 AND user.server=?");
224=cut
225 $squit_lastquit = $dbh->prepare("UPDATE nickid, user, nicktext
226 SET nicktext.data=?
227 WHERE nicktext.nrid=nickid.nrid AND nickid.id=user.id
228 AND user.online=1 AND user.server=?");
229=cut
230 $squit_lastquit = $dbh->prepare("REPLACE INTO nicktext ".
231 "SELECT nickid.nrid, ".NTF_QUIT.", 0, '', ? ".
232 "FROM nickid JOIN user ON (nickid.id=user.id) ".
233 "WHERE user.online=1 AND user.server=?");
234 $get_squit_empty_chans = $dbh->prepare("SELECT cu2.chan, COUNT(*) AS c
235 FROM user, chanuser AS cu1, chanuser AS cu2
236 WHERE user.server=? AND cu1.nickid=user.id
237 AND cu1.chan=cu2.chan AND cu1.joined=1 AND cu2.joined=1
238 GROUP BY cu2.chan HAVING c=1 ORDER BY NULL");
239
240 $del_nickchg_id = $dbh->prepare("DELETE FROM nickchg WHERE nickid=?");
241 $add_nickchg = $dbh->prepare("REPLACE INTO nickchg SELECT ?, id, ? FROM user WHERE nick=?");
242 $reap_nickchg = $dbh->prepare("DELETE FROM nickchg WHERE seq<?");
243
244 $get_nick_inval = $dbh->prepare("SELECT nick, inval FROM user WHERE id=?");
245 $inc_nick_inval = $dbh->prepare("UPDATE user SET inval=inval+1 WHERE id=?");
246
247 $is_registered = $dbh->prepare("SELECT 1 FROM nickalias WHERE alias=?");
248 $is_alias_of = $dbh->prepare("SELECT 1 FROM nickalias AS n1 LEFT JOIN nickalias AS n2 ON n1.nrid=n2.nrid
249 WHERE n1.alias=? AND n2.alias=? LIMIT 1");
250
251 $get_guest = $dbh->prepare("SELECT flags & @{[UF_GUEST]} FROM user WHERE nick=?");
252 $set_guest = $dbh->prepare("UPDATE user SET flags = IF(?, flags | @{[UF_GUEST]}, flags & ~@{[UF_GUEST]})
253 WHERE nick=?");
254
255 $get_lock = $dbh->prepare("SELECT GET_LOCK(?, 10)");
256 $release_lock = $dbh->prepare("SELECT RELEASE_LOCK(?)");
257
258 $get_umodes = $dbh->prepare("SELECT modes FROM user WHERE id=?");
259 $set_umodes = $dbh->prepare("UPDATE user SET modes=? WHERE id=?");
260
261 $get_info = $dbh->prepare("SELECT nickreg.email, nickreg.regd, nickreg.last, nickreg.flags, nickreg.ident,
262 nickreg.vhost, nickreg.gecos, nickalias.last
263 FROM nickreg, nickalias WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
264 $get_nickreg_quit = $dbh->prepare("SELECT nicktext.data FROM nickreg, nicktext, nickalias
265 WHERE nickalias.nrid=nickreg.id AND nickalias.alias=? AND
266 (nicktext.nrid=nickreg.id AND nicktext.type=".NTF_QUIT.")");
267 $set_ident = $dbh->prepare("UPDATE user SET ident=? WHERE id=?");
268 $set_vhost = $dbh->prepare("UPDATE user SET vhost=? WHERE id=?");
269 $set_ip = $dbh->prepare("UPDATE user SET ip=?, ipv6=? WHERE id=?");
270 $update_regnick_vhost = $dbh->prepare("UPDATE nickreg,nickid SET nickreg.vhost=?
271 WHERE nickreg.id=nickid.nrid AND nickid.id=?");
272 $get_regd_time = $dbh->prepare("SELECT nickreg.regd FROM nickreg, nickalias
273 WHERE nickalias.nrid=nickreg.id and nickalias.alias=?");
274
275 $chk_clone_except = $dbh->prepare("SELECT
276 GREATEST(IF((user.ip >> (32 - sesexip.mask)) = (sesexip.ip >> (32 - sesexip.mask)), sesexip.lim, 0),
277 IF(IF(sesexname.serv, user.server, user.host) LIKE sesexname.host, sesexname.lim, 0)) AS n
278 FROM user, sesexip, sesexname WHERE user.id=? ORDER BY n DESC LIMIT 1");
279 $count_clones = $dbh->prepare("SELECT COUNT(*) FROM user WHERE ip=? AND online=1");
280
281 $get_root_nick = $dbh->prepare("SELECT nickreg.nick FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
282 $get_id_nick = $dbh->prepare("SELECT nickreg.nick FROM nickreg WHERE nickreg.id=?");
283 $identify = $dbh->prepare("INSERT INTO nickid SELECT ?, nickalias.nrid FROM nickalias WHERE alias=?");
284 $identify_ign = $dbh->prepare("INSERT IGNORE INTO nickid SELECT ?, nickalias.nrid FROM nickalias WHERE alias=?");
285 $id_update = $dbh->prepare("UPDATE nickreg, user SET
286 nickreg.last=UNIX_TIMESTAMP(), nickreg.ident=user.ident,
287 nickreg.vhost=user.vhost, nickreg.gecos=user.gecos,
288 nickreg.nearexp=0, nickreg.flags = (nickreg.flags & ~". NRF_VACATION .")
289 WHERE nickreg.nick=? AND user.id=?");
290 $logout = $dbh->prepare("DELETE FROM nickid WHERE id=?");
291 $unidentify = $dbh->prepare("DELETE FROM nickid USING nickreg, nickid WHERE nickreg.nick=? AND nickid.nrid=nickreg.id");
292
293 $update_lastseen = $dbh->prepare("UPDATE nickreg,nickid SET nickreg.last=UNIX_TIMESTAMP()
294 WHERE nickreg.id=nickid.nrid AND nickid.id=?");
295 $update_nickalias_last = $dbh->prepare("UPDATE nickalias SET last=UNIX_TIMESTAMP() WHERE alias=?");
296 $quit_update = $dbh->prepare("REPLACE INTO nicktext
297 SELECT nickreg.id, ".NTF_QUIT().", 0, NULL, ? FROM nickreg, nickid
298 WHERE nickreg.id=nickid.nrid AND nickid.id=?");
299
300 $set_protect_level = $dbh->prepare("UPDATE nickalias SET protect=? WHERE alias=?");
301
302
303 $set_email = $dbh->prepare("UPDATE nickreg, nickalias SET nickreg.email=? WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
304
305 $set_pass = $dbh->prepare("UPDATE nickreg, nickalias SET nickreg.pass=? WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
306
307 $get_register_lock = $dbh->prepare("LOCK TABLES nickalias WRITE, nickreg WRITE");
308 $register = $dbh->prepare("INSERT INTO nickreg SET nick=?, pass=?, email=?, flags=".NRF_HIDEMAIL().", regd=UNIX_TIMESTAMP(), last=UNIX_TIMESTAMP()");
309 $create_alias = $dbh->prepare("INSERT INTO nickalias SELECT id, ?, NULL, NULL FROM nickreg WHERE nick=?");
310
311 $drop = $dbh->prepare("DELETE FROM nickreg WHERE nick=?");
312
313 $get_aliases = $dbh->prepare("SELECT nickalias.alias FROM nickalias, nickreg WHERE
314 nickalias.nrid=nickreg.id AND nickreg.nick=? ORDER BY nickalias.alias");
315 $get_glist = $dbh->prepare("SELECT nickalias.alias, nickalias.protect, nickalias.last
316 FROM nickalias, nickreg WHERE
317 nickalias.nrid=nickreg.id AND nickreg.nick=? ORDER BY nickalias.alias");
318 $count_aliases = $dbh->prepare("SELECT COUNT(*) FROM nickalias, nickreg WHERE
319 nickalias.nrid=nickreg.id AND nickreg.nick=?");
320 $get_random_alias = $dbh->prepare("SELECT nickalias.alias FROM nickalias, nickreg WHERE
321 nickalias.nrid=nickreg.id AND nickreg.nick=? AND nickalias.alias != nickreg.nick LIMIT 1");
322 $delete_alias = $dbh->prepare("DELETE FROM nickalias WHERE alias=?");
323 $delete_aliases = $dbh->prepare("DELETE FROM nickalias USING nickreg, nickalias WHERE
324 nickalias.nrid=nickreg.id AND nickreg.nick=?");
325
326 $get_all_access = $dbh->prepare("SELECT chanacc.chan, chanacc.level, chanacc.adder, chanacc.time FROM nickalias, chanacc WHERE chanacc.nrid=nickalias.nrid AND nickalias.alias=? ORDER BY chanacc.chan");
327 $del_all_access = $dbh->prepare("DELETE FROM chanacc USING chanacc, nickreg WHERE chanacc.nrid=nickreg.id AND nickreg.nick=?");
328
329 $change_root = $dbh->prepare("UPDATE nickreg SET nick=? WHERE nick=?");
330
331 $unlock_tables = $dbh->prepare("UNLOCK TABLES");
332
333 $get_matching_nicks = $dbh->prepare("SELECT nickalias.alias, nickreg.nick, nickreg.ident, nickreg.vhost FROM nickalias, nickreg WHERE nickalias.nrid=nickreg.id AND nickalias.alias LIKE ? AND nickreg.ident LIKE ? AND nickreg.vhost LIKE ? LIMIT 50");
334
335 $cleanup_chanuser = $dbh->prepare("DELETE FROM chanuser USING chanuser
336 LEFT JOIN user ON (chanuser.nickid=user.id) WHERE user.id IS NULL;");
337 $cleanup_nickid = $dbh->prepare("DELETE FROM nickid USING nickid
338 LEFT JOIN user ON(nickid.id=user.id)
339 WHERE user.id IS NULL");
340 $cleanup_users = $dbh->prepare("DELETE FROM user WHERE online=0 AND quittime>0 AND quittime<?");
341 $get_dead_users = $dbh->prepare("SELECT id,nick,time,online,quittime FROM user
342 WHERE online=0 AND quittime>0 AND quittime<?");
343
344 $get_expired = $dbh->prepare("SELECT nickreg.nick, nickreg.email, nickreg.ident, nickreg.vhost
345 FROM nickreg LEFT JOIN nickid ON(nickreg.id=nickid.nrid)
346 LEFT JOIN svsop ON(nickreg.id=svsop.nrid)
347 WHERE nickid.nrid IS NULL AND svsop.nrid IS NULL ".
348 'AND ('.(services_conf_nearexpire ? 'nickreg.nearexp!=0 AND' : '').
349 " ( !(nickreg.flags & " . NRF_HOLD . ") AND !(nickreg.flags & " . NRF_VACATION . ") AND nickreg.last<? ) OR
350 ( (nickreg.flags & " . NRF_VACATION . ") AND nickreg.last<? ) ) OR
351 ( (nickreg.flags & ". NRF_EMAILREG .") AND nickreg.last<?)");
352 $get_near_expired = $dbh->prepare("SELECT nickreg.nick, nickreg.email, nickreg.flags, nickreg.last
353 FROM nickreg LEFT JOIN nickid ON(nickreg.id=nickid.nrid)
354 LEFT JOIN svsop ON(nickreg.id=svsop.nrid)
355 WHERE nickid.nrid IS NULL AND svsop.nrid IS NULL AND nickreg.nearexp=0 AND
356 ( ( !(nickreg.flags & " . NRF_HOLD . ") AND !(nickreg.flags & " . NRF_VACATION . ") AND nickreg.last<? ) OR
357 ( (nickreg.flags & " . NRF_VACATION . ") AND nickreg.last<? )
358 )");
359 $set_near_expired = $dbh->prepare("UPDATE nickreg SET nearexp=1 WHERE nick=?");
360
361 $get_watches = $dbh->prepare("SELECT watch.mask, watch.time
362 FROM watch
363 JOIN nickalias ON (watch.nrid=nickalias.nrid)
364 WHERE nickalias.alias=?");
365 $check_watch = $dbh->prepare("SELECT 1
366 FROM watch
367 JOIN nickalias ON (watch.nrid=nickalias.nrid)
368 WHERE nickalias.alias=? AND watch.mask=?");
369 $set_watch = $dbh->prepare("INSERT INTO watch SELECT nrid, ?, ? FROM nickalias WHERE alias=?");
370 $del_watch = $dbh->prepare("DELETE FROM watch USING watch
371 JOIN nickalias ON (watch.nrid=nickalias.nrid)
372 WHERE nickalias.alias=? AND watch.mask=?");
373 $drop_watch = $dbh->prepare("DELETE FROM watch
374 USING nickreg JOIN watch ON (watch.nrid=nickreg.id)
375 WHERE nickreg.nick=?");
376 $get_silences = $dbh->prepare("SELECT silence.mask, silence.time, silence.expiry, silence.comment
377 FROM silence
378 JOIN nickalias ON (silence.nrid=nickalias.nrid)
379 WHERE nickalias.alias=? ORDER BY silence.time");
380 $check_silence = $dbh->prepare("SELECT 1 FROM silence
381 JOIN nickalias ON (silence.nrid=nickalias.nrid)
382 WHERE nickalias.alias=? AND silence.mask=?");
383 $set_silence = $dbh->prepare("INSERT INTO silence SELECT nrid, ?, ?, ?, ? FROM nickalias WHERE alias=?");
384 $del_silence = $dbh->prepare("DELETE FROM silence USING silence, nickalias
385 WHERE silence.nrid=nickalias.nrid AND nickalias.alias=? AND silence.mask=?");
386 $drop_silence = $dbh->prepare("DELETE FROM silence USING nickreg, silence
387 WHERE silence.nrid=nickreg.id AND nickreg.nick=?");
388 $get_expired_silences = $dbh->prepare("SELECT nickreg.nick, silence.mask, silence.comment
389 FROM nickreg
390 JOIN silence ON (nickreg.id=silence.nrid)
391 WHERE silence.expiry < UNIX_TIMESTAMP() AND silence.expiry!=0 ORDER BY nickreg.nick");
392 $del_expired_silences = $dbh->prepare("DELETE silence.* FROM silence
393 WHERE silence.expiry < UNIX_TIMESTAMP() AND silence.expiry!=0");
394 $get_silence_by_num = $dbh->prepare("SELECT silence.mask, silence.time, silence.expiry, silence.comment
395 FROM silence
396 JOIN nickalias ON (silence.nrid=nickalias.nrid)
397 WHERE nickalias.alias=? ORDER BY silence.time LIMIT 1 OFFSET ?");
398 $get_silence_by_num->bind_param(2, 0, SQL_INTEGER);
399
400 $get_seen = $dbh->prepare("SELECT nickalias.alias, nickreg.nick, nickreg.last FROM nickreg, nickalias
401 WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
402
403 $set_greet = $dbh->prepare("REPLACE INTO nicktext SELECT nickreg.id, ".NTF_GREET.", 0, NULL, ?
404 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
405 $get_greet = $dbh->prepare("SELECT nicktext.data FROM nicktext, nickid
406 WHERE nicktext.nrid=nickid.nrid AND nicktext.type=".NTF_GREET." AND nickid.id=?
407 LIMIT 1");
408 $get_greet_nick = $dbh->prepare("SELECT nicktext.data FROM nicktext, nickalias
409 WHERE nicktext.nrid=nickalias.nrid AND nicktext.type=".NTF_GREET." AND nickalias.alias=?");
410 $del_greet = $dbh->prepare("DELETE nicktext.* FROM nicktext, nickreg, nickalias WHERE
411 nicktext.type=".NTF_GREET." AND nickreg.id=nickalias.nrid AND nickalias.alias=?");
412
413 $get_num_nicktext_type = $dbh->prepare("SELECT COUNT(nicktext.id) FROM nicktext, nickalias
414 WHERE nicktext.nrid=nickalias.nrid AND nickalias.alias=? AND nicktext.type=?");
415 $drop_nicktext = $dbh->prepare("DELETE FROM nicktext USING nickreg
416 JOIN nicktext ON (nicktext.nrid=nickreg.id)
417 WHERE nickreg.nick=?");
418
419 $get_auth_chan = $dbh->prepare("SELECT nicktext.data FROM nicktext, nickalias WHERE
420 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH().") AND nickalias.alias=? AND nicktext.chan=?");
421 $get_auth_num = $dbh->prepare("SELECT nicktext.chan, nicktext.data FROM nicktext, nickalias WHERE
422 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH().") AND nickalias.alias=? LIMIT 1 OFFSET ?");
423 $get_auth_num->bind_param(2, 0, SQL_INTEGER);
424 $del_auth = $dbh->prepare("DELETE nicktext.* FROM nicktext, nickalias WHERE
425 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH().") AND nickalias.alias=? AND nicktext.chan=?");;
426 $list_auth = $dbh->prepare("SELECT nicktext.chan, nicktext.data FROM nicktext, nickalias WHERE
427 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH().") AND nickalias.alias=?");
428
429 $del_nicktext = $dbh->prepare("DELETE nicktext.* FROM nickreg
430 JOIN nickalias ON (nickalias.nrid=nickreg.id)
431 JOIN nicktext ON (nicktext.nrid=nickreg.id)
432 WHERE nicktext.type=? AND nickalias.alias=?");
433
434 $set_umode_ntf = $dbh->prepare("REPLACE INTO nicktext SELECT nickreg.id, ".NTF_UMODE().", 1, ?, NULL
435 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
436 $get_umode_ntf = $dbh->prepare("SELECT nicktext.chan FROM nickreg, nickalias, nicktext
437 WHERE nicktext.type=(".NTF_UMODE().") AND nicktext.nrid=nickalias.nrid AND nickalias.alias=?");
438
439 $set_vacation_ntf = $dbh->prepare("INSERT INTO nicktext SELECT nickreg.id, ".NTF_VACATION().", 0, ?, NULL
440 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
441 $get_vacation_ntf = $dbh->prepare("SELECT nicktext.chan FROM nickalias, nicktext
442 WHERE nicktext.nrid=nickalias.nrid AND nicktext.type=".NTF_VACATION()." AND nickalias.alias=?");
443
444 $set_authcode_ntf = $dbh->prepare("REPLACE INTO nicktext SELECT nickreg.id, ".NTF_AUTHCODE().", 0, '', ?
445 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
446 $get_authcode_ntf = $dbh->prepare("SELECT 1 FROM nickalias, nicktext
447 WHERE nicktext.nrid=nickalias.nrid AND nicktext.type=".NTF_AUTHCODE()." AND nickalias.alias=? AND nicktext.data=?");
448
449 $get_nicks_by_email = $dbh->prepare("SELECT nickreg.nick, nickreg.ident, nickreg.vhost FROM nickreg
450 WHERE nickreg.email LIKE ? GROUP BY nickreg.nick");
451
452}
453import SrSv::MySQL::Stub {
454 add_profile_ntf => ['INSERT', "REPLACE INTO nicktext SELECT nickreg.id, @{[NTF_PROFILE]}, 0, ?, ?
455 FROM nickreg JOIN nickalias ON (nickreg.id=nickalias.nrid) WHERE nickalias.alias=?"],
456 get_profile_ntf => ['ARRAY', "SELECT chan, data FROM nicktext
457 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
458 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=?"],
459 del_profile_ntf => ['NULL', "DELETE nicktext.* FROM nicktext
460 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
461 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=? AND nicktext.chan=?"],
462 wipe_profile_ntf => ['NULL', "DELETE nicktext.* FROM nicktext
463 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
464 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=?"],
465 count_profile_ntf => ['SCALAR', "SELECT COUNT(chan) FROM nicktext
466 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
467 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=?"],
468
469 protect_level => ['SCALAR', 'SELECT protect FROM nickalias WHERE alias=?'],
470 get_pass => ['SCALAR', "SELECT nickreg.pass
471 FROM nickreg JOIN nickalias ON (nickreg.id=nickalias.nrid)
472 WHERE nickalias.alias=?"],
473 get_email => ['SCALAR', "SELECT nickreg.email
474 FROM nickalias JOIN nickreg ON (nickreg.id=nickalias.nrid)
475 WHERE nickalias.alias=?"],
476 count_silences => ['SCALAR', "SELECT COUNT(silence.nrid) FROM silence
477 JOIN nickalias ON (silence.nrid=nickalias.nrid)
478 WHERE nickalias.alias=?"],
479 count_watches => ['SCALAR', "SELECT COUNT(watch.nrid) FROM watch
480 JOIN nickalias ON (watch.nrid=nickalias.nrid)
481 WHERE nickalias.alias=?"],
482
483 add_autojoin_ntf => ['INSERT', "INSERT INTO nicktext
484 SELECT nickreg.id, @{[NTF_JOIN]}, 0, ?, NULL
485 FROM nickreg JOIN nickalias ON (nickreg.id=nickalias.nrid)
486 WHERE nickalias.alias=?"],
487 get_autojoin_ntf => ['COLUMN', "SELECT chan
488 FROM nicktext
489 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
490 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=?"],
491 wipe_autojoin_ntf => ['NULL', "DELETE nicktext.* FROM nickreg
492 JOIN nickalias ON (nickalias.nrid=nickreg.id)
493 JOIN nicktext ON (nicktext.nrid=nickreg.id)
494 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=?"],
495 del_autojoin_ntf => ['NULL', "DELETE nicktext.* FROM nickreg
496 JOIN nickalias ON (nickalias.nrid=nickreg.id)
497 JOIN nicktext ON (nicktext.nrid=nickreg.id)
498 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=? AND nicktext.chan=?"],
499 check_autojoin_ntf => ['SCALAR', "SELECT 1 FROM nicktext
500 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
501 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=? AND nicktext.chan=?"],
502 get_autojoin_by_num => ['SCALAR', "SELECT nicktext.chan
503 FROM nicktext
504 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
505 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=? LIMIT 1 OFFSET ?"],
506};
507
508
509### NICKSERV COMMANDS ###
510
511sub ns_ajoin_list($$) {
512 my ($user, $nick) = @_;
513 my @data;
514 my $i = 0;
515 foreach my $chan (get_autojoin_ntf($nick)) {
516 push @data, [++$i, $chan];
517 }
518
519 notice( $user, columnar( {TITLE => "Channels in \002$nick\002's ajoin",
520 NOHIGHLIGHT => nr_chk_flag_user($user, NRF_NOHIGHLIGHT)}, @data ) );
521}
522sub ns_ajoin_del($$@) {
523 my ($user, $nick, @args) = @_;
524 my ($subj, $obj);
525 if(lc(get_user_nick($user)) eq lc($nick)) {
526 $subj='your';
527 $obj='you';
528 } else {
529 $subj="\002$nick\002\'s";
530 $obj="\002$nick\002";
531 }
532 my @entries;
533 foreach my $arg (@args) {
534 if ($arg =~ /^[0-9\.,-]+$/) {
535 foreach my $num (makeSeqList($arg)) {
536 if(my $chan = get_autojoin_by_num($nick, $num - 1)) {
537 push @entries, $chan;
538 } else {
539 notice($user, "No entry \002#$num\002 was found in $subj ajoin list");
540 }
541 }
542 } elsif($arg =~ /^#.*?,#/) {
543 push @entries, split(',', $arg);
544 } else {
545 push @entries, $arg;
546 }
547 }
548 foreach my $entry (@entries) {
549 if(check_autojoin_ntf($nick, $entry)) {
550 del_autojoin_ntf($nick, $entry);
551 notice($user,"Successfully removed \002$entry\002 from $subj ajoin list.");
552 }
553 else {
554 notice($user, "\002$entry\002 was not in $subj ajoin!");
555 }
556 }
557}
558sub ns_ajoin_wipe($$) {
559 my ($user, $nick) = @_;
560 my ($subj, $obj);
561 if(lc(get_user_nick($user)) eq lc($nick)) {
562 $subj='your';
563 $obj='you';
564 } else {
565 $subj="\002$nick\002\'s";
566 $obj="\002$nick\002";
567 }
568 my $count = wipe_autojoin_ntf($nick);
569 if($count) {
570 notice($user,"Successfully wiped \002$count\002 entries from $subj ajoin list.");
571 } else {
572 notice($user,"No entries deleted.");
573 }
574}
575
576sub ns_ajoin_join($$) {
577 my ($user, $nick) = @_;
578 #ns_ajoin_list($user, $nick);
579 do_ajoin($user, $nick);
580}
581
582sub ns_ajoin($@) {
583 my ($user, @args) = @_;
584 my $nick;
585 my $src = get_user_nick($user);
586 my @chans = grep(/^(#|\d)/, @args);
587 my @parms = grep(!/^(#|\d)/, @args);
588 if(scalar(@parms) > 1) {
589 $nick = shift @parms;
590 } else {
591 $nick = $src;
592 }
593 my $cmd = shift @parms;
594 my ($subj, $obj);
595 if(lc($src) eq lc($nick)) {
596 $subj='Your';
597 $obj='You';
598 } else {
599 $subj="\002$nick\002\'s";
600 $obj="\002$nick\002";
601 }
602
603 my $override = adminserv::can_do($user, 'SERVOP');
604 if(is_identified($user, $nick) || $override) {
605 if(!is_registered($src)) {
606 notice($user, "\002$nick\002 is not registered.");
607 return;
608 }
609 } else {
610 notice($user, "Permission denied for \002$nick\002");
611 return;
612 }
613 if ($cmd =~ /^add$/i) {
614 if(!scalar(@chans)) {
615 notice($user, "Syntax: \002AJOIN ADD #channel\002");
616 notice ($user, "Type \002/msg NickServ HELP AJOIN\002 for more help");
617 }
618 foreach my $chanlist (@chans) {
619 if (defined($chanlist) && $chanlist !~ /^#/) {
620 $chanlist = "#" . $chanlist;
621 }
622 foreach my $chan (split(',', $chanlist)) {
623 if(check_autojoin_ntf($nick, $chan)) {
624 notice ($user, $chan . " is already in $subj ajoin list! ");
625 next;
626 } else {
627 add_autojoin_ntf($chan, $nick);
628 notice($user, "\002$chan\002 added to $subj ajoin.");
629 }
630 }
631 }
632 }
633 elsif ($cmd =~ /^list$/i) {
634 ns_ajoin_list($user, $nick);
635 }
636 elsif ($cmd =~ /^join$/i) {
637 ns_ajoin_join($user, $nick);
638 }
639 elsif ($cmd =~ /^del(ete)?$/i) {
640 ns_ajoin_del($user, $nick, @chans);
641 }
642 elsif ($cmd =~ /^(clear|wipe)$/i) {
643 ns_ajoin_wipe($user, $nick);
644 }
645 else {
646 notice($user,"Syntax: AJOIN ADD/DEL/LIST/WIPE");
647 notice ($user,"Type \002/msg NickServ HELP AJOIN\002 for more help!");
648 }
649}
650
651our %high_priority_cmds = (
652 'id' => 1,
653 'identify' => 1,
654 'sid' => 1,
655 'sidentify' => 1,
656 'gidentify' => 1,
657 'ghost' => 1,
658);
659
660sub dispatch($$$) {
7b3a5814 661 $nsuser = { NICK => $nsnick, ID => ircd::getAgentUuid($nsnick) };
5e682044 662 my ($user, $dstUser, $msg) = @_;
663 return unless (lc $dstUser->{NICK} eq lc $nsnick);
aecfa1fd 664 $msg =~ s/^\s+//;
665 my @args = split(/\s+/, $msg);
666 my $cmd = shift @args;
5e682044 667 get_user_id ($user);
668 my $src = $user->{NICK};
7b3a5814 669 $user->{AGENT} = $nsuser;
aecfa1fd 670 return if flood_check($user);
aecfa1fd 671 if(!defined($high_priority_cmds{lc $cmd}) &&
672 !adminserv::is_svsop($user) &&
673 $SrSv::IRCd::State::queue_depth > main_conf_highqueue)
674 {
675 notice($user, get_user_agent($user)." is too busy right now. Please try your command again later.");
676 return;
677 }
678
679 if($cmd =~ /^help$/i) {
680 sendhelp($user, 'nickserv', @args)
681 }
682 elsif ($cmd =~ /^ajoin$/i) {
683 ns_ajoin($user, shift @args, @args);
684 }
685 elsif($cmd =~ /^id(entify)?$/i) {
686 if(@args == 1) {
687 ns_identify($user, $src, $args[0]);
688 } elsif(@args == 2) {
689 ns_identify($user, $args[0], $args[1]);
690 } else {
691 notice($user, 'Syntax: IDENTIFY [nick] <password>');
692 }
693 }
694 elsif($cmd =~ /^sid(entify)?$/i) {
695 if(@args == 2) {
696 ns_identify($user, $args[0], $args[1], 1);
697 } else {
698 notice($user, 'Syntax: SIDENTIFY <nick> <password>');
699 }
700 }
701 elsif($cmd =~ /^gid(entify)?$/i) {
702 if(@args == 2) {
703 ns_identify($user, $args[0], $args[1], 2);
704 } else {
705 notice($user, 'Syntax: GIDENTIFY <nick> <password>');
706 }
707 }
708 elsif($cmd =~ /^logout$/i) {
709 ns_logout($user);
710 }
711 elsif($cmd =~ /^release$/i) {
712 if(@args == 1) {
713 ns_release($user, $args[0]);
714 } elsif(@args == 2) {
715 ns_release($user, $args[0], $args[1]);
716 } else {
717 notice($user, 'Syntax: RELEASE <nick> [password]');
718 }
719 }
720 elsif($cmd =~ /^ghost$/i) {
721 if(@args == 1) {
722 ns_ghost($user, $args[0]);
723 } elsif(@args == 2) {
724 ns_ghost($user, $args[0], $args[1]);
725 } else {
726 notice($user, 'Syntax: GHOST <nick> [password]');
727 }
728 }
729 elsif($cmd =~ /^register$/i) {
730 if(@args == 2) {
731 ns_register($user, $args[0], $args[1]);
732 } else {
733 notice($user, 'Syntax: REGISTER <password> <email>');
734 }
735 }
736 elsif($cmd =~ /^(?:link|group)$/i) {
737 if(@args == 2) {
738 ns_link($user, $args[0], $args[1]);
739 } else {
740 notice($user, 'Syntax: LINK <nick> <password>');
741 }
742 }
743 elsif($cmd =~ /^info$/i) {
744 if(@args >= 1) {
745 ns_info($user, @args);
746 } else {
747 notice($user, 'Syntax: INFO <nick> [nick ...]');
748 }
749 }
750 elsif($cmd =~ /^set$/i) {
751 ns_set_parse($user, @args);
752 }
753 elsif($cmd =~ /^(drop|unlink)$/i) {
754 if(@args == 1) {
755 ns_unlink($user, $src, $args[0]);
756 }
757 elsif(@args == 2) {
758 ns_unlink($user, $args[0], $args[1]);
759 }
760 else {
761 notice($user, 'Syntax: UNLINK [nick] <password>');
762 }
763 }
764 elsif($cmd =~ /^dropgroup$/i) {
765 if(@args == 1) {
766 ns_dropgroup($user, $src, $args[0]);
767 }
768 elsif(@args == 2) {
769 ns_dropgroup($user, $args[0], $args[1]);
770 }
771 else {
772 notice($user, 'Syntax: DROPGROUP [nick] <password>');
773 }
774 }
775 elsif($cmd =~ /^chgroot$/i) {
776 if(@args == 1) {
777 ns_changeroot($user, $src, $args[0]);
778 }
779 elsif(@args == 2) {
780 ns_changeroot($user, $args[0], $args[1]);
781 }
782 else {
783 notice($user, 'Syntax: CHGROOT [oldroot] <newroot>');
784 }
785 }
786 elsif($cmd =~ /^sendpass$/i) {
787 if(@args == 1) {
788 ns_sendpass($user, $args[0]);
789 } else {
790 notice($user, 'Syntax: SENDPASS <nick>');
791 }
792 }
793 elsif($cmd =~ /^(?:glist|links)$/i) {
794 if(@args == 0) {
795 ns_glist($user, $src);
796 }
797 elsif(@args >= 1) {
798 ns_glist($user, @args);
799 }
800 else {
801 notice($user, 'Syntax: GLIST [nick] [nick ...]');
802 }
803 }
804 elsif($cmd =~ /^(?:alist|listchans)$/i) {
805 if(@args == 0) {
806 ns_alist($user, $src);
807 }
808 elsif(@args >= 1) {
809 ns_alist($user, @args);
810 }
811 else {
812 notice($user, 'Syntax: ALIST [nick] [nick ...]');
813 }
814 }
815 elsif($cmd =~ /^list$/i) {
816 if(@args == 1) {
817 ns_list($user, $args[0]);
818 } else {
819 notice($user, 'Syntax: LIST <mask>');
820 }
821 }
822 elsif($cmd =~ /^watch$/i) {
823 if ($args[0] =~ /^(add|del|list)$/i) {
824 ns_watch($user, $src, @args);
825 }
826 elsif ($args[1] =~ /^(add|del|list)$/i) {
827 ns_watch($user, @args);
828 }
829 else {
830 notice($user, 'Syntax: WATCH <ADD|DEL|LIST> [nick]');
831 }
832 }
833 elsif($cmd =~ /^silence$/i) {
834 if ($args[0] =~ /^(add|del|list)$/i) {
835 ns_silence($user, $src, @args);
836 }
837 elsif ($args[1] =~ /^(add|del|list)$/i) {
838 ns_silence($user, @args);
839 }
840 else {
841 notice($user, 'Syntax: SILENCE [nick] <ADD|DEL|LIST> [mask] [+expiry] [comment]');
842 }
843 }
844 elsif($cmd =~ /^(acc(ess)?|stat(us)?)$/i) {
845 if (@args >= 1) {
846 ns_acc($user, @args);
847 }
848 else {
849 notice($user, 'Syntax: ACC <nick> [nick ...]');
850 }
851 }
852 elsif($cmd =~ /^seen$/i) {
853 if(@args >= 1) {
854 ns_seen($user, @args);
855 }
856 else {
857 notice($user, 'Syntax: SEEN <nick> [nick ...]');
858 }
859 }
860 elsif($cmd =~ /^recover$/i) {
861 if(@args == 1) {
862 ns_recover($user, $args[0]);
863 } elsif(@args == 2) {
864 ns_recover($user, $args[0], $args[1]);
865 } else {
866 notice($user, 'Syntax: RECOVER <nick> [password]');
867 }
868 }
869 elsif($cmd =~ /^auth$/i) {
870 if (@args >= 1) {
871 ns_auth($user, @args);
872 }
873 else {
874 notice($user, 'Syntax: AUTH [nick] <LIST|ACCEPT|DECLINE> [num|chan]');
875 }
876 }
877 elsif($cmd =~ /^(?:emailreg|(?:auth|email)code)$/i) {
878 if(scalar(@args) >= 2 and scalar(@args) <= 3) {
879 ns_authcode($user, @args);
880 } else {
881 notice($user, 'Syntax: AUTHCODE <nick> <code> [newpassword]');
882 }
883 }
884 elsif($cmd =~ /^profile$/i) {
885 ns_profile($user, @args);
886 }
887 elsif($cmd =~ /^liste?mail/i) {
888 if ($#args == 0) {
889 ns_listemail($user, $args[0]);
890 } else {
891 notice($user, 'Syntax: LISTEMAIL <email@domain.tld>');
892 }
893 }
894 else {
895 notice($user, "Unrecognized command.", "For help, type: \002/msg nickserv help\002");
896 wlog($nsnick, LOG_DEBUG(), "$src tried to use NickServ $msg");
897 }
898}
899
900sub ns_identify($$$;$) {
901 my ($user, $nick, $pass, $svsnick) = @_;
902 my $src = get_user_nick($user);
903
904 my $root = get_root_nick($nick);
905 unless($root) {
906 notice($user, 'Your nick is not registered.');
907 return 0;
908 }
909
910 if($svsnick) {
911 if(lc($src) ne lc($nick) and is_online($nick)) {
912 if($svsnick == 2) {
913 ns_ghost($user, $nick, $pass) or return;
914 } else {
915 notice($user, $nick.' is already in use. Please use GHOST, GIDENTIFY or RECOVER');
916 $svsnick = 0;
917 }
918 }
919 if (is_identified($user, $nick)) {
920 if(lc $src eq lc $nick) {
921 notice($user, "Cannot only change case of nick");
922 return;
923 }
5e682044 924 ircd::svsnick($nsuser, $user, $nick);
925 ircd::setumode($nsuser, $user, '+r');
aecfa1fd 926 return 1;
927 }
928 }
929 # cannot be an else, note change of $svsnick above.
930 if (!$svsnick and is_identified($user, $nick)) {
931 notice($user, 'You are already identified for nick '.$nick.'.');
932 return 0;
933 }
934
935 my $flags = nr_get_flags($root);
936
937 if($flags & NRF_FREEZE) {
938 notice($user, "This nick has been frozen and may not be used.", $err_deny);
939 services::ulog($nsnick, LOG_INFO(), "\00305attempted to identify to frozen nick \003\002$nick\002", $user);
940 return;
941 }
942
943 if($flags & NRF_EMAILREG) {
944 notice($user, "This nick is awaiting an email validation code. Please check your email for instructions.");
945 return;
946 }
947
948 elsif($flags & NRF_SENDPASS) {
949 notice($user, "This nick is awaiting a SENDPASS authentication code. Please check your email for instructions.");
950 return;
951 }
952
953 my $uid = get_user_id($user);
954 unless(chk_pass($root, $pass, $user)) {
955 if(inc_nick_inval($user)) {
956 notice($user, $err_pass);
957 }
958 services::ulog($nsnick, LOG_INFO(), "failed to identify to nick $nick (root: $root)", $user);
959 return 0;
960 }
961
962 return do_identify($user, $nick, $root, $flags, $svsnick);
963}
964
965sub ns_logout($) {
966 my ($user) = @_;
967 my $uid = get_user_id($user);
968
969 $update_lastseen->execute($uid);
970 $logout->execute($uid);
971 delete($user->{NICKFLAGS});
5e682044 972 ircd::nolag($nsnick, '-', $user);
aecfa1fd 973 notice($user, 'You are now logged out');
974 services::ulog($nsnick, LOG_INFO(), "used NickServ LOGOUT", $user);
975}
976
977sub ns_release($$;$) {
978 my ($user, $nick, $pass) = @_;
979
980 if(nr_chk_flag($nick, NRF_FREEZE)) {
981 notice($user, "This nick has been frozen and may not be used.", $err_deny);
982 services::ulog($nsnick, LOG_INFO(), "\00305attempted to release frozen nick \003\002$nick\002", $user);
983 return;
984 }
985
986 unless(is_identified($user, $nick)) {
987 if($pass) {
988 my $s = ns_identify($user, $nick, $pass);
989 return if($s == 0); #failed to identify
990 if($s == 1) {
991 notice($user, "Nick $nick is not being held.");
992 return;
993 }
994 } else {
995 notice($user, $err_deny);
996 return;
997 }
998 }
999 elsif(enforcer_quit($nick)) {
1000 notice($user, 'Your nick has been released from custody.');
1001 } else {
1002 notice($user, "Nick $nick is not being held.");
1003 }
1004}
1005
1006sub ns_ghost($$;$) {
1007
1008my @ghostbusters_quotes = (
1009 'Ray. If someone asks if you are a god, you say, "yes!"',
1010 'I feel like the floor of a taxicab.',
1011 'I don\'t have to take this abuse from you, I\'ve got hundreds of people dying to abuse me.',
1012 'He slimed me.',
1013 'This chick is *toast*.',
1014 '"Where do these stairs go?" "They go up."',
1015 '"That\'s the bedroom, but nothing ever happened in there." "What a crime."',
1016 'NOBODY steps on a church in my town.',
1017 'Whoa, whoa, whoa! Nice shootin\', Tex!',
1018 'It\'s the Stay Puft Marshmallow Man.',
1019 '"Symmetrical book stacking. Just like the Philadelphia mass turbulence of 1947." "You\'re right, no human being would stack books like this."',
1020 '"Egon, this reminds me of the time you tried to drill a hole through your head. Remember that?" "That would have worked if you hadn\'t stopped me."',
1021 '"Ray has gone bye-bye, Egon... what\'ve you got left?" "Sorry, Venkman, I\'m terrified beyond the capacity for rational thought."',
1022 'Listen! Do you smell something?',
1023 'As they say in T.V., I\'m sure there\'s one big question on everybody\'s mind, and I imagine you are the man to answer that. How is Elvis, and have you seen him lately?',
1024 '"You know, you don\'t act like a scientist." "They\'re usually pretty stiff." "You\'re more like a game show host."',
1025);
1026 my ($user, $nick, $pass) = @_;
1027 my $src = get_user_nick($user);
1028
1029 if(nr_chk_flag($nick, NRF_FREEZE)) {
1030 notice($user, "This nick has been frozen and may not be used.", $err_deny);
1031 services::ulog($nsnick, LOG_INFO(), "\00305attempted to ghost frozen nick \003\002$nick\002", $user);
1032 return 0;
1033 }
1034
1035 unless(is_identified($user, $nick)) {
1036 if($pass) {
1037 my $s = ns_identify($user, $nick, $pass);
1038 return 0 if($s == 0); #failed to identify
1039 } else {
1040 notice($user, $err_deny);
1041 return 0;
1042 }
1043 }
1044
1045 if(!is_online($nick)) {
1046 notice($user, "\002$nick\002 is not online");
1047 return 0;
1048 } elsif(lc $src eq lc $nick) {
1049 notice($user, "I'm sorry, $src, I'm afraid I can't do that.");
1050 return 0;
1051
1052 } else {
1053 my $ghostbusters = @ghostbusters_quotes[int rand(scalar(@ghostbusters_quotes))];
92c29160 1054 my $baduser = {NICK => $nick};
1055 get_user_id ($baduser);
1056 ircd::irckill($nsuser, $baduser, "GHOST command used by $src ($ghostbusters)");
aecfa1fd 1057 notice($user, "Your ghost has been disconnected");
1058 services::ulog($nsnick, LOG_INFO(), "used NickServ GHOST on $nick", $user);
1059 #nick_delete($nick);
1060 return 1;
1061 }
1062}
1063
1064sub ns_register($$$) {
1065 my ($user, $pass, $email) = @_;
1066 my $src = get_user_nick($user);
1067
1068 if($src =~ /^guest/i) {
1069 notice($user, $err_deny);
1070 return;
1071 }
1072
1073 unless(validate_email($email)) {
1074 notice($user, $err_email);
1075 return;
1076 }
1077
1078 if ($pass =~ /pass/i) {
1079 notice($user, 'Try a more secure password.');
1080 return;
1081 }
1082
1083 my $uid = get_user_id($user);
1084
1085 $get_register_lock->execute; $get_register_lock->finish;
1086
1087 if(not is_registered($src)) {
1088 $register->execute($src, hash_pass($pass), $email); $register->finish();
1089 $create_alias->execute($src, $src); $create_alias->finish;
1090 if (defined(services_conf_default_protect)) {
1091 $set_protect_level->execute((defined(services_conf_default_protect) ?
1092 $protect_level{lc services_conf_default_protect} : 1), $src);
1093 $set_protect_level->finish();
1094 }
1095 $unlock_tables->execute; $unlock_tables->finish;
1096
1097 if(services_conf_validate_email) {
1098 nr_set_flag($src, NRF_EMAILREG());
1099 authcode($src, 'emailreg', $email);
1100 notice($user, "Your registration is not yet complete.",
1101 "Your nick will expire within ".
1102 (services_conf_validate_expire == 1 ? '24 hours' : services_conf_validate_expire.' days').
1103 " if you do not enter the validation code.",
1104 "Check your email for further instructions.");
1105 }
1106 else {
1107 $identify->execute($uid, $src); $identify->finish();
1108 notice($user, 'You are now registered and identified.');
5e682044 1109 ircd::setumode($nsuser, $user, '+r');
aecfa1fd 1110 }
1111
1112 $id_update->execute($src, $uid); $id_update->finish();
86a50b12 1113 services::ulog($nsnick, LOG_INFO(), "registered $src (email: $email)".
aecfa1fd 1114 (services_conf_validate_email ? ' requires email validation code' : ''),
92c29160 1115 $src);
aecfa1fd 1116 } else {
1117 $unlock_tables->execute; $unlock_tables->finish;
1118 notice($user, 'Your nickname has already been registered.');
1119 }
1120}
1121
1122sub ns_link($$$) {
1123 my ($user, $nick, $pass) = @_;
1124
1125 my $root = get_root_nick($nick);
1126 my $src = get_user_nick($user);
1127 my $uid = get_user_id($user);
1128
1129 if($src =~ /^guest/i) {
1130 notice($user, $err_deny);
1131 return;
1132 }
1133
1134 unless (is_registered($nick)) {
1135 if(is_registered($src)) {
1136 notice($user, "The nick \002$nick\002 is not registered. You need to change your nick to \002$nick\002 and then link to \002$src\002.");
1137 } else { # if neither $nick nor $src are registered
1138 notice($user, "You need to register your nick first. For help, type \002/ns help register");
1139 }
1140 return;
1141 }
1142
1143 unless(chk_pass($root, $pass, $user)) {
1144 notice($user, $err_pass);
1145 return;
1146 }
1147
1148 if(nr_chk_flag($nick, NRF_FREEZE) and (lc $pass ne 'force')) {
1149 notice($user, "\002$root\002 has been frozen and may not be used.");
1150 return;
1151 }
1152
1153 if(is_alias_of($src, $nick)) {
1154 notice($user, "\002$nick\002 is already linked to \002$src\002.");
1155 return;
1156 }
1157
1158 $get_register_lock->execute; $get_register_lock->finish;
1159
1160 if(is_registered($src)) {
1161 $unlock_tables->execute; $unlock_tables->finish;
1162
1163 if(is_identified($user, $src)) {
1164 notice($user, "You cannot link an already registered nick. Type this and try again: \002/ns drop $src <password>");
1165 return;
1166 } else {
1167 notice($user, 'Your nickname has already been registered.');
1168 return;
1169 }
1170 } else {
1171 $create_alias->execute($src, $root); $create_alias->finish();
1172 if (defined(services_conf_default_protect)) {
1173 $set_protect_level->execute((defined(services_conf_default_protect) ?
1174 $protect_level{lc services_conf_default_protect} : 1), $src);
1175 $set_protect_level->finish();
1176 }
1177 $unlock_tables->execute; $unlock_tables->finish;
1178
1179 if(is_identified($user, $root)) {
1180 $identify_ign->execute($uid, $root); $identify_ign->finish();
1181 $id_update->execute($root, $uid); $id_update->finish();
1182 } else {
1183 ns_identify($user, $root, $pass);
1184 }
1185 }
1186
1187 notice($user, "\002$src\002 is now linked to \002$root\002.");
1188 services::ulog($nsnick, LOG_INFO(), "made $src an alias of $root.", $user);
1189
1190 check_identify($user);
1191}
1192
1193sub ns_unlink($$$) {
1194 my ($user, $nick, $pass) = @_;
1195 my $uid = get_user_id($user);
1196 my $src = get_user_nick($user);
1197
1198 my $root = get_root_nick($nick);
1199 unless(chk_pass($root, $pass, $user)) {
1200 notice($user, $err_pass);
1201 return;
1202 }
1203
1204 if(nr_chk_flag($nick, NRF_FREEZE) and (lc $pass ne 'force')) {
1205 notice($user, "\002$root\002 has been frozen and may not be used.", $err_deny);
1206 services::ulog($nsnick, LOG_INFO(), "\00305attempted to unlink \002$nick\002 from frozen nick \002$root\002", $user);
1207 return;
1208 }
1209
1210 if(lc $root eq lc $nick) {
1211 $count_aliases->execute($root);
1212 my ($count) = $count_aliases->fetchrow_array;
1213 if($count == 1) {
1214 ns_dropgroup_real($user, $root);
1215 return;
1216 }
1217
1218 $get_random_alias->execute($root);
1219 my ($new) = $get_random_alias->fetchrow_array;
1220 ns_changeroot($user, $root, $new, 1);
1221
1222 $root = $new;
1223 }
1224
1225 unidentify_single($nick);
1226 delete_alias($nick);
1227 enforcer_quit($nick);
1228
1229 notice($user, "\002$nick\002 has been unlinked from \002$root\002.");
1230 services::ulog($nsnick, LOG_INFO(), "removed alias $nick from $root.", $user);
1231}
1232
1233sub ns_dropgroup($$$) {
1234 my ($user, $nick, $pass) = @_;
1235 my $uid = get_user_id($user);
1236 my $src = get_user_nick($user);
1237 my $root = get_root_nick($nick);
1238
1239 if(adminserv::get_svs_level($root)) {
1240 notice($user, "A nick with services access may not be dropped.");
1241 return;
1242 }
1243
1244 unless(chk_pass($root, $pass, $user)) {
1245 notice($user, $err_pass);
1246 return;
1247 }
1248
1249 if(nr_chk_flag($nick, NRF_FREEZE) and (lc $pass ne 'force')) {
1250 notice($user, "This nick has been frozen and may not be used.", $err_deny);
1251 services::ulog($nsnick, LOG_INFO(), "\00305attempted to dropgroup frozen nick \002$root\002", $user);
1252 return;
1253 }
1254
1255 ns_dropgroup_real($user, $root);
1256}
1257
1258sub ns_dropgroup_real($$) {
1259 my ($user, $root) = @_;
1260 my $src = get_user_nick($user);
1261
1262 unidentify($root, "Your nick, \002$root\002, was dropped by \002$src\002.", $src);
1263 dropgroup($root);
1264 #enforcer_quit($nick);
1265 notice($user, "Your nick(s) have been dropped. Thanks for playing.");
1266
1267 services::ulog($nsnick, LOG_INFO(), "dropped group $root.", $user);
1268}
1269
1270sub ns_changeroot($$$;$) {
1271 my ($user, $old, $new, $force) = @_;
1272
1273 $force or chk_identified($user, $old) or return;
1274
1275 my $root = get_root_nick($old);
1276
1277 if(lc($new) eq lc($root)) {
1278 notice($user, "\002$root\002 is already your root nick.");
1279 return;
1280 }
1281
1282 unless(get_root_nick($new) eq $root) {
1283 notice($user, "\002$new\002 is not an alias of your nick. Type \002/msg nickserv help link\002 for information about creating aliases.");
1284 return;
1285 }
1286
1287 changeroot($root, $new);
1288
1289 notice($user, "Your root nick is now \002$new\002.");
1290 services::ulog($nsnick, LOG_INFO(), "changed root $root to $new.", $user);
1291}
1292
1293sub ns_info($@) {
1294 my ($user, @nicks) = @_;
1295
1296 foreach my $nick (@nicks) {
1297 my $root = get_root_nick($nick);
1298
1299 $get_info->execute($nick);
1300 my @result = $get_info->fetchrow_array;
1301 $get_info->finish();
1302
1303 unless(@result) {
1304 notice($user, "The nick \002$nick\002 is not registered.");
1305 next;
1306 }
1307
1308 my ($email, $regd, $last, $flags, $ident, $vhost, $gecos, $alias_used) = @result;
1309 # the quit entry might not exist if the user hasn't quit yet.
1310 $get_nickreg_quit->execute($nick);
1311 my ($quit) = $get_nickreg_quit->fetchrow_array(); $get_nickreg_quit->finish();
1312 my $hidemail = $flags & NRF_HIDEMAIL;
1313
1314 $get_greet_nick->execute($nick);
1315 my ($greet) = $get_greet_nick->fetchrow_array(); $get_greet_nick->finish();
1316 $get_umode_ntf->execute($nick);
1317 my ($umode) = $get_umode_ntf->fetchrow_array(); $get_umode_ntf->finish();
1318
1319 my $svslev = adminserv::get_svs_level($root);
1320 my $protect = protect_level($nick);
1321 my $showprivate = (is_identified($user, $nick) or
1322 adminserv::is_svsop($user, adminserv::S_HELP()));
1323
1324 my ($seens, $seenm) = do_seen($nick);
1325
1326 my @data;
1327
1328 push @data, {FULLROW=>"(Online now, $seenm.)"} if $seens == 2;
1329 push @data, ["Last seen:", "$seenm."] if $seens == 1;
1330
1331 push @data,
1332 ["Last seen address:", "$ident\@$vhost"],
1333 ["Registered:", gmtime2($regd)];
1334 push @data, ["Last used:", ($alias_used ? gmtime2($alias_used) : 'Unknown')] if $showprivate;
1335 push @data, ["Last real name:", $gecos];
1336
1337 push @data, ["Services Rank:", $adminserv::levels[$svslev]]
1338 if $svslev;
1339 push @data, ["E-mail:", $email] unless $hidemail;
1340 push @data, ["E-mail:", "$email (Hidden)"]
1341 if($hidemail and $showprivate);
1342 push @data, ["Alias of:", $root]
1343 if ((lc $root ne lc $nick) and $showprivate);
1344
1345 my @extra;
1346
1347 push @extra, "Last quit: $quit" if $quit;
1348 push @extra, $protect_long[$protect] if $protect;
1349 push @extra, "Does not accept memos." if($flags & NRF_NOMEMO);
1350 push @extra, "Cannot be added to channel access lists." if($flags & NRF_NOACC);
1351 push @extra, "Will not be automatically opped in channels." if($flags & NRF_NEVEROP);
1352 push @extra, "Requires authorization to be added to channel access lists."
1353 if($flags & NRF_AUTH);
1354 push @extra, "Is frozen and may not be used." if($flags & NRF_FREEZE);
1355 push @extra, "Will not expire." if($flags & NRF_HOLD);
1356 push @extra, "Is currently on vacation." if($flags & NRF_VACATION);
1357 push @extra, "Registration pending email-code verification." if($flags & NRF_EMAILREG);
1358 push @extra, "UModes on Identify: ".$umode if ($umode and $showprivate);
1359 push @extra, "Greeting: ".$greet if ($greet and $showprivate);
1360 push @extra, "Disabled highlighting of alternating lines." if ($flags & NRF_NOHIGHLIGHT);
1361
1362 notice($user, columnar({TITLE => "NickServ info for \002$nick\002:",
1363 NOHIGHLIGHT => nr_chk_flag_user($user, NRF_NOHIGHLIGHT)},
1364 @data, {COLLAPSE => \@extra, BULLET => 1}));
1365 }
1366}
1367
1368sub ns_set_parse($@) {
1369 my ($user, @parms) = @_;
1370 my $src = get_user_nick($user);
1371# This is a new NS SET parser
1372# required due to it's annoying syntax
1373#
1374# Most commands have only 2 params at most
1375# the target (which is implied to be src when not spec'd)
1376# However in the case of GREET num-params is unbounded
1377#
1378# Alternative parsings would be possible,
1379# one being to use a regexp for valid set/keys
1380 if (lc($parms[1]) eq 'greet') {
1381 ns_set($user, @parms);
1382 }
1383 elsif(lc($parms[0]) eq 'greet') {
1384 ns_set($user, $src, @parms);
1385 }
1386 else {
1387 if(@parms == 2) {
1388 ns_set($user, $src, $parms[0], $parms[1]);
1389 }
1390 elsif(@parms == 3) {
1391 ns_set($user, $parms[0], $parms[1], $parms[2]);
1392 }
1393 else {
1394 notice($user, 'Syntax: SET [nick] <option> <value>');
1395 return;
1396 }
1397 }
1398}
1399
1400sub ns_set($$$$) {
1401 my ($user, $target, $set, @parms) = @_;
1402 my $src = get_user_nick($user);
1403 my $override = (adminserv::can_do($user, 'SERVOP') or
1404 (adminserv::can_do($user, 'FREEZE') and $set =~ /^freeze$/i) ? 1 : 0);
1405
1406 unless(is_registered($target)) {
1407 notice($user, "\002$target\002 is not registered.");
1408 return;
1409 }
1410 unless(is_identified($user, $target) or $override) {
1411 notice($user, $err_deny);
1412 return;
1413 }
1414
1415 unless (
1416 $set =~ /^protect$/i or
1417 $set =~ /^e?-?mail$/i or
1418 $set =~ /^pass(?:w(?:or)?d)?$/i or
1419 $set =~ /^hidee?-?mail$/i or
1420 $set =~ /^nomemo$/i or
1421 $set =~ /^no(?:acc|op)$/i or
1422 $set =~ /^neverop$/i or
1423 $set =~ /^auth$/i or
1424 $set =~ /^(hold|no-?expire)$/i or
1425 $set =~ /^freeze$/i or
1426 $set =~ /^vacation$/i or
1427 $set =~ /^greet$/i or
1428 $set =~ /^u?modes?$/i or
1429 $set =~ /^(email)?reg$/i or
1430 $set =~ /^nohighlight$/i or
1431 $set =~ /^(?:(?:chg)?root|display)$/i
1432 ) {
1433 notice($user, qq{"$set" is not a valid NickServ setting.});
1434 return;
1435 }
1436
1437 my ($subj, $obj);
1438 if($src eq $target) {
1439 $subj='Your';
1440 $obj='You';
1441 } else {
1442 $subj="\002$target\002\'s";
1443 $obj="\002$target\002";
1444 }
1445 delete($user->{NICKFLAGS});
1446
1447 if($set =~ /^protect$/i) {
1448 my $level = $protect_level{lc shift @parms};
1449 unless (defined($level)) {
1450 notice($user, "Syntax: SET PROTECT <none|normal|high|kill>");
1451 return;
1452 }
1453
1454 $set_protect_level->execute($level, $target);
1455 notice($user, "$subj protection level is now set to \002".$protect_short[$level]."\002. ".$protect_long[$level]);
1456
1457 return;
1458 }
1459
1460 elsif($set =~ /^e?-?mail$/i) {
1461 unless(@parms == 1) {
1462 notice($user, 'Syntax: SET EMAIL <address>');
1463 return;
1464 }
1465 my $email = $parms[0];
1466
1467 unless(validate_email($email)) {
1468 notice($user, $err_email);
1469 return;
1470 }
1471
1472 $set_email->execute($email, $target);
1473 notice($user, "$subj email address has been changed to \002$email\002.");
1474 services::ulog($nsnick, LOG_INFO(), "changed email of \002$target\002 to $email", $user);
1475
1476 return;
1477 }
1478
1479 elsif($set =~ /^pass(?:w(?:or)?d)?$/i) {
1480 unless(@parms == 1) {
1481 notice($user, 'Syntax: SET PASSWD <address>');
1482 return;
1483 }
1484 if($parms[0] =~ /pass/i) {
1485 notice($user, 'Try a more secure password.');
1486 }
1487
1488 $set_pass->execute(hash_pass($parms[0]), $target);
1489 notice($user, "$subj password has been changed.");
1490 services::ulog($nsnick, LOG_INFO(), "changed password of \002$target\002", $user);
1491 if(nr_chk_flag($target, NRF_SENDPASS())) {
1492 $del_nicktext->execute(NTF_AUTHCODE, $target); $del_nicktext->finish();
1493 nr_set_flag($target, NRF_SENDPASS(), 0);
1494 }
1495
1496 return;
1497 }
1498
1499 elsif($set =~ /^greet$/i) {
1500 unless(@parms) {
1501 notice($user, 'Syntax: SET [nick] GREET <NONE|greeting>');
1502 return;
1503 }
1504
1505 my $greet = join(' ', @parms);
1506 if ($greet =~ /^(none|off)$/i) {
1507 $del_greet->execute($target);
1508 notice($user, "$subj greet has been deleted.");
1509 services::ulog($nsnick, LOG_INFO(), "deleted greet of \002$target\002", $user);
1510 }
1511 else {
1512 $set_greet->execute($greet, $target);
1513 notice($user, "$subj greet has been set to \002$greet\002");
1514 services::ulog($nsnick, LOG_INFO(), "changed greet of \002$target\002", $user);
1515 }
1516
1517 return;
1518 }
1519 elsif($set =~ /^u?modes?$/i) {
1520 unless(@parms == 1) {
1521 notice($user, 'Syntax: SET UMODE <+modes-modes|none>');
1522 return;
1523 }
1524
1525 if (lc $parms[0] eq 'none') {
1526 $del_nicktext->execute(NTF_UMODE, $target); $del_nicktext->finish();
1527 notice($user, "$obj will not receive any automatic umodes.");
1528 }
1529 else {
1530 my ($modes, $rejected) = modes::allowed_umodes($parms[0]);
1531 $del_nicktext->execute(NTF_UMODE, $target); $del_nicktext->finish(); # don't allow dups
1532 $set_umode_ntf->execute($modes, $target); $set_umode_ntf->finish();
1533 foreach my $usernick (get_nick_user_nicks $target) {
5e682044 1534 ircd::setumode($nsuser, $user, $modes)
aecfa1fd 1535 }
1536
1537 my @out;
1538 push @out, "Cannot set these umodes: " . $rejected if $rejected;
1539 push @out, "$subj automatic umodes have been set to: \002" . ($modes ? $modes : 'none');
1540 notice($user, @out);
1541 }
1542 return;
1543 }
1544 elsif($set =~ /^(?:(?:chg)?root|display)$/i) {
1545 ns_changeroot($user, $target, $parms[0], $override);
1546 return;
1547 }
1548
1549 my $val;
1550 if($parms[0] =~ /^(?:no|off|false|0)$/i) { $val = 0; }
1551 elsif($parms[0] =~ /^(?:yes|on|true|1)$/i) { $val = 1; }
1552 else {
1553 notice($user, "Please say \002on\002 or \002off\002.");
1554 return;
1555 }
1556
1557 if($set =~ /^hidee?-?mail$/i) {
1558 nr_set_flag($target, NRF_HIDEMAIL, $val);
1559
1560 if($val) {
1561 notice($user, "$subj email address is now hidden.");
1562 } else {
1563 notice($user, "$subj email address is now visible.");
1564 }
1565
1566 return;
1567 }
1568
1569 if($set =~ /^nomemo$/i) {
1570 nr_set_flag($target, NRF_NOMEMO, $val);
1571
1572 if($val) {
1573 notice($user, "$subj memos will be blocked.");
1574 } else {
1575 notice($user, "$subj memos will be delivered.");
1576 }
1577
1578 return;
1579 }
1580
1581 if($set =~ /^no(?:acc|op)$/i) {
1582 nr_set_flag($target, NRF_NOACC, $val);
1583
1584 if($val) {
1585 notice($user, "$obj may not be added to channel access lists.");
1586 } else {
1587 notice($user, "$obj may be added to channel access lists.");
1588 }
1589
1590 return;
1591 }
1592
1593 if($set =~ /^neverop$/i) {
1594 nr_set_flag($target, NRF_NEVEROP, $val);
1595
1596 if($val) {
1597 notice($user, "$obj will not be granted status upon joining channels.");
1598 } else {
1599 notice($user, "$obj will be granted status upon joining channels.");
1600 }
1601
1602 return;
1603 }
1604
1605 if($set =~ /^auth$/i) {
1606 nr_set_flag($target, NRF_AUTH, $val);
1607
1608 if($val) {
1609 notice($user, "$obj must now authorize additions to channel access lists.");
1610 } else {
1611 notice($user, "$obj will not be asked to authorize additions to channel access lists.");
1612 }
1613
1614 return;
1615 }
1616
1617 if($set =~ /^(hold|no-?expire)$/i) {
1618 unless (adminserv::can_do($user, 'SERVOP') or
1619 is_identified($user, $target) and adminserv::is_ircop($user))
1620 {
1621 notice($user, $err_deny);
1622 return;
1623 }
1624
1625 nr_set_flag($target, NRF_HOLD, $val);
1626
1627 if($val) {
1628 notice($user, "\002$target\002 is now held from expiration.");
1629 services::ulog($nsnick, LOG_INFO(), "has held \002$target\002", $user);
1630 } else {
1631 notice($user, "\002$target\002 will now expire normally.");
1632 services::ulog($nsnick, LOG_INFO(), "released \002$target\002 from hold", $user);
1633 }
1634
1635 return;
1636 }
1637
1638 if($set =~ /^freeze$/i) {
1639 unless (adminserv::can_do($user, 'FREEZE') or
1640 is_identified($user, $target) and adminserv::is_ircop($user))
1641 {
1642 notice($user, $err_deny);
1643 return;
1644 }
1645
1646 nr_set_flag($target, NRF_FREEZE, $val);
1647
1648 if($val) {
1649 notice($user, "\002$target\002 is now frozen.");
1650 unidentify($target, "Your nick, \002$target\002, has been frozen and may no longer be used.");
1651 services::ulog($nsnick, LOG_INFO(), "froze \002$target\002", $user);
1652 } else {
1653 notice($user, "\002$target\002 is no longer frozen.");
1654 services::ulog($nsnick, LOG_INFO(), "unfroze \002$target\002", $user);
1655 }
1656
1657 return;
1658 }
1659
1660 if($set =~ /^vacation$/i) {
1661 if ($val) {
1662 $get_regd_time->execute($target);
1663 my ($regd) = $get_regd_time->fetchrow_array;
1664 $get_regd_time->finish();
1665
1666 if(($regd > (time() - 86400 * int(services_conf_vacationexpire / 3))) and !$override) {
1667 notice($user, "$target is not old enough to use VACATION",
1668 'Minimum age is '.int(services_conf_vacationexpire / 3).' days');
1669 return;
1670 }
1671
1672 $get_vacation_ntf->execute($target);
1673 my ($last_vacation) = $get_vacation_ntf->fetchrow_array();
1674 $get_vacation_ntf->finish();
1675 if(defined($last_vacation)) {
1676 $last_vacation = unpack('N', MIME::Base64::decode($last_vacation));
1677 if ($last_vacation > (time() - 86400 * int(services_conf_vacationexpire / 3)) and !$override) {
1678 notice($user, "I'm sorry, \002$src\002, I'm afraid I can't do that.",
1679 "Last vacation ended ".gmtime2($last_vacation),
1680 'Minimum time between vacations is '.int(services_conf_vacationexpire / 3).' days.');
1681 return;
1682 }
1683 }
1684 }
1685
1686 nr_set_flag($target, NRF_VACATION, $val);
1687
1688 services::ulog($nsnick, LOG_INFO(),
1689 ($val ? 'enabled' : 'disabled')." vacation mode for \002$target\002", $user);
1690 notice($user, "Vacation mode ".($val ? 'enabled' : 'disabled')." for \002$target\002");
1691 return;
1692 }
1693
1694 if($set =~ /^(email)?reg$/i) {
1695 unless (adminserv::can_do($user, 'SERVOP'))
1696 {
1697 notice($user, $err_deny);
1698 return;
1699 }
1700
1701 nr_set_flag($target, NRF_EMAILREG, $val);
1702
1703 if($val) {
1704 authcode($target, 'emailreg');
1705 notice($user, "\002$target\002 now needs an email validation code.");
1706 unidentify($target, ["Your nick, \002$target\002, has been flagged for an email validation audit.",
1707 "Your nick will expire within 24 hours if you do not enter the validation code.",
1708 "Check your email for further instructions."]);
1709 services::ulog($nsnick, LOG_INFO(), "requested an email audit for \002$target\002", $user);
1710 } else {
1711 $del_nicktext->execute(NTF_AUTHCODE, $target); $del_nicktext->finish();
1712 notice($user, "\002$target\002 is now fully registered.");
1713 services::ulog($nsnick, LOG_INFO(), "validated the email for \002$target\002", $user);
1714 }
1715
1716 return;
1717 }
1718
1719 if($set =~ /^nohighlight$/i) {
1720 nr_set_flag($target, NRF_NOHIGHLIGHT, $val);
1721
1722 if($val) {
1723 notice($user, "$obj will no longer have alternative highlighting of lists.");
1724 } else {
1725 notice($user, "$obj will have alternative highlighting of lists.");
1726 }
1727
1728 return;
1729 }
1730
1731}
1732
1733sub ns_sendpass($$) {
1734 my ($user, $nick) = @_;
1735
1736 unless(adminserv::is_svsop($user, adminserv::S_HELP() )) {
1737 notice($user, $err_deny);
1738 return;
1739 }
1740
1741 my $email = get_email($nick);
1742
1743 unless($email) {
1744 notice($user, "\002$nick\002 is not registered or does not have an email address.");
1745 return;
1746 }
1747
1748 my $pass = get_pass($nick);
1749 if ($pass and !is_hashed($pass)) {
1750 send_email($email, "$nsnick Password Reminder",
1751 "The password for the nick $nick is:\n$pass");
1752 notice($user, "Password for \002$nick\002 has been sent to \002$email\002.");
1753 } else {
1754 authcode($nick, 'sendpass', $email);
1755 nr_set_flag($nick, NRF_SENDPASS);
1756 notice($user, "Password authentication code for \002$nick\002 has been sent to \002$email\002.");
1757 }
1758
1759 services::ulog($nsnick, LOG_INFO(), "used SENDPASS on $nick ($email)", $user);
1760}
1761
1762sub ns_glist($@) {
1763 my ($user, @targets) = @_;
1764
1765 foreach my $target (@targets) {
1766 my $root = get_root_nick($target);
1767 unless($root) {
1768 notice $user, "\002$target\002 is not registered.";
1769 next;
1770 }
1771
1772 unless(is_identified($user, $target) or
1773 adminserv::is_svsop($user, adminserv::S_HELP())
1774 ) {
1775 notice $user, "$target: $err_deny";
1776 next;
1777 }
1778
1779 my @data;
1780 $get_glist->execute($root);
1781 while(my ($alias, $protect, $last) = $get_glist->fetchrow_array) {
1782 my $time_ago;
1783 if(0) {
1784 # This needs a new NS GLIST cmd, like NS GLISTA or something.
1785 # The idea is a command that shows the long version of the time_ago.
1786 $time_ago = time_ago($last, 1);
1787 } else {
1788 $time_ago = time_ago($last);
1789 }
1790 push @data, ["\002$alias\002", "Protect: $protect_short[$protect]",
1791 ($last ? "Last used $time_ago ago" : '')
1792 ];
1793 }
1794
1795 notice $user, columnar {TITLE => "Group list for \002$root\002 (" . $get_glist->rows . " nicks):",
1796 NOHIGHLIGHT => nr_chk_flag_user($user, NRF_NOHIGHLIGHT)}, @data;
1797
1798 $get_glist->finish();
1799 }
1800}
1801
1802sub ns_alist($@) {
1803 my ($user, @targets) = @_;
1804
1805 foreach my $target (@targets) {
1806 (adminserv::is_svsop($user, adminserv::S_HELP()) and (
1807 chk_registered($user, $target) or next)
1808 ) or chk_identified($user, $target) or next;
1809
1810 my @data;
1811
1812 $get_all_access->execute($target);
1813 while(my ($c, $l, $a, $t) = $get_all_access->fetchrow_array) {
1814 next unless $l > 0;
1815 push @data, [$c, $chanserv::plevels[$l+$chanserv::plzero], ($a ? "($a)" : ''),
1816 gmtime2($t)];
1817 }
1818
1819 notice $user, columnar {TITLE => "Access listing for \002$target\002 (".scalar(@data)." entries)",
1820 NOHIGHLIGHT => nr_chk_flag_user($user, NRF_NOHIGHLIGHT)}, @data;
1821 }
1822}
1823
1824sub ns_list($$) {
1825 my ($user, $mask) = @_;
1826
1827 unless(adminserv::is_svsop($user, adminserv::S_HELP())) {
1828 notice($user, $err_deny);
1829 return;
1830 }
1831
1832 my ($mnick, $mident, $mhost) = glob2sql(parse_mask($mask));
1833
1834 $mnick = '%' if($mnick eq '');
1835 $mident = '%' if($mident eq '');
1836 $mhost = '%' if($mhost eq '');
1837
1838 my @data;
1839 $get_matching_nicks->execute($mnick, $mident, $mhost);
1840 while(my ($rnick, $rroot, $rident, $rhost) = $get_matching_nicks->fetchrow_array) {
1841 push @data, [$rnick, ($rroot ne $rnick ? $rroot : ''), $rident . '@' . $rhost];
1842 }
1843
1844 notice $user, columnar {TITLE => "Registered nicks matching \002$mask\002:",
1845 NOHIGHLIGHT => nr_chk_flag_user($user, NRF_NOHIGHLIGHT)}, @data;
1846}
1847
1848sub ns_watch($$$;$) {
1849 my ($user, $target, $cmd, $mask) = @_;
1850 my $src = get_user_nick($user);
1851
1852 my $root = get_root_nick($target);
1853 unless ($root) {
1854 notice($user, "\002$target\002 is not registered.");
1855 return;
1856 }
1857 unless(is_identified($user, $target)) {
1858 notice($user, $err_deny);
1859 return;
1860 }
1861
1862 if ($cmd =~ /^add$/i) {
1863 my $max_watches = $IRCd_capabilities{WATCH}; # load here for caching.
026939ee 1864 if ($max_watches eq "") {
1865 notice ($user, "The IRCd is not configured to support WATCH. Please contact your friendly network administrators.");
1866 return;
1867 }
aecfa1fd 1868 if(count_watches($root) >= $max_watches) {
1869 notice($user, "WATCH list for $target full, there is a limit of $max_watches. Please trim your list.");
1870 return;
1871 }
1872
1873 if($mask =~ /\!/ or $mask =~ /\@/) {
1874 my ($mnick, $mident, $mhost) = parse_mask($mask);
1875 if ($mnick =~ /\*/) {
1876 notice($user, "Invalid mask: \002$mask\002",
1877 'A WATCH mask cannot wildcard the nick.');
1878 return;
1879 }
1880 }
1881
1882 $check_watch->execute($root, $mask);
1883 if ($check_watch->fetchrow_array) {
1884 notice($user, "\002$mask\002 is already in \002$target\002's watch list.");
1885 return;
1886 }
1887
1888 $set_watch->execute($mask, time(), $root);
5e682044 1889 ircd::svswatch($nsuser, $user, "+$mask");
aecfa1fd 1890 notice($user, "\002$mask\002 added to \002$target\002's watch list.");
1891 return;
1892 }
1893 elsif ($cmd =~ /^del(ete)?$/i) {
1894 $check_watch->execute($root, $mask);
026939ee 1895 if ($IRCd_capabilities{WATCH} eq "") {
1896 notice ($user, "The IRCd is not configured to support WATCH. Please contact your friendly network administrators.");
1897 return;
1898 }
aecfa1fd 1899 unless ($check_watch->fetchrow_array) {
1900 notice($user, "\002$mask\002 is not in \002$target\002's watch list.");
1901 return;
1902 }
1903 $del_watch->execute($root, $mask);
5e682044 1904 ircd::svswatch($nsuser, $user, "-$mask");
aecfa1fd 1905 notice($user, "\002$mask\002 removed from \002$target\002's watch list.");
1906 }
1907 elsif ($cmd =~ /^list$/i) {
1908 my @data;
1909
1910 $get_watches->execute($root);
1911 while(my ($mask, $time) = $get_watches->fetchrow_array) {
1912 push @data, [$mask, gmtime2($time)];
1913 }
1914
1915 notice $user, columnar {TITLE => "Watch list for \002$target\002:",
1916 NOHIGHLIGHT => nr_chk_flag_user($user, NRF_NOHIGHLIGHT)}, @data;
1917 }
1918 else {
1919 notice($user, 'Syntax: WATCH <ADD|DEL|LIST> [nick]');
1920 }
1921}
1922
1923sub ns_silence($$$;$@) {
1924 my ($user, $target, $cmd, $mask, @args) = @_;
1925 my ($expiry, $comment);
1926 my $src = get_user_nick($user);
1927 my ($subj, $obj);
1928 if(lc(get_user_nick($user)) eq lc($target)) {
1929 $subj='your';
1930 $obj='you';
1931 } else {
1932 $subj="\002$target\002\'s";
1933 $obj="\002$target\002";
1934 }
1935
1936sub get_silence_by_num($$) {
1937# This one cannot be converted to SrSv::MySQL::Stub, due to bind_param call
1938 my ($nick, $num) = @_;
1939 $get_silence_by_num->execute($nick, $num-1);
1940 my ($mask) = $get_silence_by_num->fetchrow_array();
1941 $get_silence_by_num->finish();
1942 return $mask;
1943}
1944
1945 my $root = get_root_nick($target);
1946 my $isRegistered;
1947 if(!defined($root)) {
1948 #notice($user, "\002$target\002 is not registered.");
1949 $isRegistered = 0;
1950 #return;
1951 } else {
1952 $isRegistered = 1;
1953 }
1954
1955 if($isRegistered && !is_identified($user, $target)) {
1956 notice($user, $err_deny);
1957 return;
1958 }
1959
1960 if ($cmd =~ /^add$/i) {
1961 my $max_silences = $IRCd_capabilities{SILENCE};
026939ee 1962 if ($max_silences eq "") {
1963 notice ($user, "The IRCd is not configured to support SILENCE. Please contact your friendly network administrators.");
1964 return;
1965 }
aecfa1fd 1966 if(count_silences($root) >= $max_silences) {
1967 notice($user, "SILENCE list for $target full, there is a limit of $max_silences. Please trim your list.");
1968 return;
1969 }
1970
1971 if (substr($args[0],0,1) eq '+') {
1972 $expiry = shift @args;
1973 }
1974 elsif (substr($args[-1],0,1) eq '+') {
1975 $expiry = pop @args;
1976 }
1977 $comment = join(' ', @args);
1978
1979 if($mask !~ /[!@.]/) {
1980 my $target_user = { NICK => $mask };
1981 unless(get_user_id($target_user)) {
1982 notice($user, qq{"\002$mask\002" is not a known user, nor a valid hostmask.});
1983 return;
1984 }
1985 $comment = $mask unless $comment;
1986 no warnings 'misc';
1987 my ($ident, $vhost) = get_vhost($target_user);
1988 my ($nick, $ident, $vhost) = make_hostmask(10, $mask, $ident, $vhost);
1989 $mask = $nick.'!'.$ident.'@'.$vhost;
1990 }
1991 else {
1992 $mask = normalize_hostmask($mask);
1993 }
1994
1995=cut
1996 if("$nsnick!services\@".main_conf_local =~ hostmask_to_regexp($mask)) {
1997 notice($user, "You shouldn't add NickServ to your SILENCE list.");
1998 return;
1999 }
2000=cut
2001
2002 if(defined $expiry) {
2003 $expiry = parse_time($expiry) + time();
2004 }
2005 else {
2006 $expiry = 0;
2007 };
2008 if($isRegistered) {
2009 $check_silence->execute($root, $mask);
2010 if ($check_silence->fetchrow_array) {
2011 notice($user, "\002$mask\002 is already in $subj SILENCE list.");
2012 return;
2013 }
2014
2015 $set_silence->execute($mask, time(), $expiry, $comment, $root);
2016 }
5e682044 2017 ircd::svssilence($nsuser, $user, "+$mask");
aecfa1fd 2018 notice($user, "\002$mask\002 added to $subj SILENCE list.");
2019 }
2020 elsif ($cmd =~ /^del(ete)?$/i) {
2021 my @masks;
2022 if ($mask =~ /^[0-9\.,-]+$/) {
2023 foreach my $num (makeSeqList($mask)) {
2024 push @masks, get_silence_by_num($root, $num) or next;
2025 }
2026 if(scalar(@masks) == 0) {
2027 notice($user, "Unable to find any silences matching $mask");
2028 return;
2029 }
2030 } else {
2031 @masks = ($mask);
2032 }
2033 my @reply; my @out_masks;
2034 foreach my $mask (@masks) {
2035 $check_silence->execute($root, $mask);
2036 unless ($check_silence->fetchrow_array) {
2037 $mask = normalize_hostmask($mask);
2038
2039 $check_silence->execute($root, $mask);
2040 unless ($check_silence->fetchrow_array) {
2041 push @reply, "\002$mask\002 is not in $subj SILENCE list.";
2042 next;
2043 }
2044 }
2045 $del_silence->execute($root, $mask);
2046 push @out_masks, "-$mask";
2047 push @reply, "\002$mask\002 removed from $subj SILENCE list.";
2048 }
5e682044 2049 ircd::svssilence($nsuser, $user, @out_masks);
aecfa1fd 2050 notice($user, @reply);
2051 }
2052 elsif ($cmd =~ /^list$/i) {
2053 $get_silences->execute($root);
2054
2055 my @reply; my $i = 1;
2056 while(my ($mask, $time, $expiry, $comment) = $get_silences->fetchrow_array) {
2057 push @reply, "$i \002[\002 $mask \002]\002 Date added: ".gmtime2($time),
2058 ' '.($comment ? "\002[\002 $comment \002]\002 " : '').
2059 ($expiry ? 'Expires in '.time_rel($expiry-time()) :
2060 "\002[\002 Never expires \002]\002");
2061 $i++;
2062 }
2063
2064 notice($user, "SILENCE list for $obj:", (scalar @reply ? @reply : " list empty"));
2065 }
2066 else {
2067 notice($user, 'Syntax: SILENCE [nick] <ADD|DEL|LIST> [mask] [+expiry] [comment]');
2068 }
2069
2070}
2071
2072sub ns_acc($@) {
2073 my ($user, @targets) = @_;
2074 my @reply;
2075
2076 foreach my $target (@targets) {
2077 unless(is_registered($target)) {
2078 push @reply, "ACC 0 \002$target\002 is not registered.";
2079 next;
2080 }
2081
2082 unless(is_online($target)) {
2083 push @reply, "ACC 1 \002$target\002 is registered and offline.";
2084 next;
2085 }
2086
2087 unless(is_identified({NICK => $target}, $target)) {
2088 push @reply, "ACC 2 \002$target\002 is online but not identified.";
2089 next;
2090 }
2091
2092 push @reply, "ACC 3 \002$target\002 is registered and identified.";
2093 }
2094 notice($user, @reply);
2095}
2096
2097sub ns_seen($@) {
2098 my ($user, @nicks) = @_;
2099
2100 foreach my $nick (@nicks) {
026939ee 2101 if(lc $nick eq lc (($user->{AGENT})->{NICK})) {
aecfa1fd 2102 notice($user, "Oh, a wise guy, eh?");
2103 next;
2104 }
2105 my ($status, $msg) = do_seen($nick);
2106 if($status == 2) {
2107 notice($user, "\002$nick\002 is online now, ".$msg.'.');
2108 } elsif($status == 1) {
2109 notice($user, "\002$nick\002 was last seen ".$msg.'.');
2110 } else {
2111 notice($user, "The nick \002$nick\002 is not registered.");
2112 }
2113 }
2114}
2115
2116sub ns_recover($$;$) {
2117 my ($user, $nick, $pass) = @_;
2118 my $src = get_user_nick($user);
2119
2120 if(nr_chk_flag($nick, NRF_FREEZE)) {
2121 notice($user, "This nick has been frozen and may not be used.", $err_deny);
2122 services::ulog($nsnick, LOG_INFO(), "\00305attempted to recover frozen nick \003\002$nick\002", $user);
2123 return;
2124 }
2125
2126 unless(is_identified($user, $nick)) {
2127 if($pass) {
2128 my $s = ns_identify($user, $nick, $pass);
2129 return if($s == 0); #failed to identify
2130 } else {
2131 notice($user, $err_deny);
2132 return;
2133 }
2134 }
2135
2136 if(!is_online($nick)) {
2137 notice($user, "\002$nick\002 is not online");
2138 return;
2139 } elsif(lc $src eq lc $nick) {
2140 notice($user, "I'm sorry, $src, I'm afraid I can't do that.");
2141 return;
2142
2143 } else {
2144 collide($nick);
2145 notice($user, "User claiming your nick has been collided",
2146 "/msg NickServ RELEASE $nick to get it back before the one-minute timeout.");
2147 services::ulog($nsnick, LOG_INFO(), "used NickServ RECOVER on $nick", $user);
2148 return;
2149 }
2150}
2151
2152sub ns_auth($@) {
2153 my ($user, @args) = @_;
2154 my ($target, $cmd);
2155
2156#These helpers shouldn't be needed anywhere else.
2157# If they ever are, move them to the helpers section
2158 sub get_auth_num($$) {
2159 # this cannot be converted to SrSv::MySQL::Stub, due to bind_param
2160 my ($nick, $num) = @_;
2161 $get_auth_num->execute($nick, $num - 1);
2162 my ($cn, $data) = $get_auth_num->fetchrow_array();
2163 $get_auth_num->finish();
2164 return ($data ? ($cn, split(/:/, $data)) : undef);
2165 }
2166 sub get_auth_chan($$) {
2167 my ($nick, $cn) = @_;
2168 $get_auth_chan->execute($nick, $cn);
2169 my ($data) = $get_auth_chan->fetchrow_array();
2170 $get_auth_chan->finish();
2171 return (split(/:/, $data));
2172 }
2173
2174 if ($args[0] =~ /^(list|accept|approve|decline|reject)$/i) {
2175 $target = get_user_nick($user);
2176 $cmd = lc shift @args;
2177 }
2178 else {
2179 $target = shift @args;
2180 $cmd = lc shift @args;
2181 }
2182
2183 unless (is_registered($target)) {
2184 notice($user, "The nickname \002$target\002 is not registered");
2185 return;
2186 }
2187 unless (is_identified($user, $target)) {
2188 notice($user, $err_deny);
2189 return;
2190 }
2191
2192 if ($cmd eq 'list') {
2193 my @data;
2194 $list_auth->execute($target);
2195 while (my ($cn, $data) = $list_auth->fetchrow_array()) {
2196 my ($adder, $old, $level, $time) = split(':', $data);
2197 push @data, [$cn, $chanserv::levels[$level], $adder, gmtime2($time)];
2198 }
2199 if ($list_auth->rows()) {
2200 notice $user, columnar {TITLE => "Pending authorizations for \002$target\002:",
2201 NOHIGHLIGHT => nr_chk_flag_user($user, NRF_NOHIGHLIGHT)}, @data;
2202 }
2203 else {
2204 notice($user, "There are no pending authorizations for \002$target\002");
2205 }
2206 }
2207 elsif ($cmd eq 'accept' or $cmd eq 'approve') {
2208 my $parm = shift @args;
2209 my ($cn, $adder, $old, $level, $time);
2210 if(misc::isint($parm) and
2211 ($cn, $adder, $old, $level, $time) = get_auth_num($target, $parm))
2212 {
2213 }
2214 elsif ($parm =~ /^\#/ and
2215 ($adder, $old, $level, $time) = get_auth_chan($target, $parm))
2216 {
2217 $cn = $parm;
2218 }
2219 unless ($cn) {
2220 # This should normally be an 'else' as the elsif above should prove false
2221 # For some reason, it doesn't work. the unless ($cn) fixes it.
2222 # It only doesn't work for numbered entries
2223 notice($user, "There is no entry for \002$parm\002 in \002$target\002's AUTH list");
2224 return;
2225 }
2226 my $chan = { CHAN => $cn };
2227 my $root = get_root_nick($target);
2228
2229 # These next 3 lines should use chanserv::set_acc() but it doesn't seem to work.
2230 # It won't let me use a $nick instead of $user
2231 $chanserv::set_acc1->execute($cn, $level, $root);
2232 $chanserv::set_acc2->execute($level, $adder, $cn, $root);
2233 chanserv::set_modes_allnick($root, $chan, $level) unless chanserv::is_neverop($root);
2234
2235 my $log_str = ($old?'move':'addition')." \002$root\002"
2236 . ($old ? ' from the '.$chanserv::levels[$old] : '') .
2237 ' to the '.$chanserv::levels[$level]." list of \002$cn\002";
2238 services::ulog($chanserv::csnick, LOG_INFO(), "accepted the $log_str from $adder", $user, $chan);
2239 notice($user, "You have accepted the $log_str");
2240 $del_auth->execute($target, $cn);
2241 $del_auth->finish();
2242 memoserv::send_memo($chanserv::csnick, $adder, "$target accepted the $log_str");
2243 }
2244 elsif ($cmd eq 'decline' or $cmd eq 'reject') {
2245 my $parm = shift @args;
2246 my ($cn, $adder, $old, $level, $time);
2247 if(misc::isint($parm) and
2248 ($cn, $adder, $old, $level, $time) = get_auth_num($target, $parm))
2249 {
2250 }
2251 elsif ($parm =~ /^\#/ and
2252 ($adder, $old, $level, $time) = get_auth_chan($target, $parm))
2253 {
2254 $cn = $parm;
2255 }
2256 unless ($cn) {
2257 # This should normally be an 'else' as the elsif above should prove false
2258 # For some reason, it doesn't work. the unless ($cn) fixes it.
2259 # It only doesn't work for numbered entries
2260 notice($user, "There is no entry for \002$parm\002 in \002$target\002's AUTH list");
2261 return;
2262 }
2263 my $chan = { CHAN => $cn };
2264
2265 my $root = get_root_nick($target);
2266 my $log_str = ($old?'move':'addition')." \002$root\002"
2267 . ($old ? ' from the '.$chanserv::plevels[$old+$chanserv::plzero] : '') .
2268 ' to the '.$chanserv::plevels[$level+$chanserv::plzero]." list of \002$cn\002";
2269 services::ulog($chanserv::csnick, LOG_INFO(), "declined the $log_str from $adder", $user, $chan);
2270 notice($user, "You have declined $log_str");
2271 $del_auth->execute($target, $cn);
2272 $del_auth->finish();
2273 memoserv::send_memo($chanserv::csnick, $adder, "$target declined the $log_str");
2274 }
2275 #elsif ($cmd eq 'read') {
2276 #}
2277 else {
2278 notice($user, "Unknown AUTH cmd");
2279 }
2280}
2281
2282sub ns_authcode($$$;$) {
2283 my ($user, $target, $code, $pass) = @_;
2284
2285 if ($pass and $pass =~ /pass/i) {
2286 notice($user, 'Try a more secure password.');
2287 return;
2288 }
2289
2290 unless(is_registered($target)) {
2291 notice($user, "\002$target\002 isn't registered.");
2292 return;
2293 }
2294
2295 if(authcode($target, undef, $code)) {
2296 notice($user, "\002$target\002 authenticated.");
2297 services::ulog($nsnick, LOG_INFO(), "logged in to \002$target\002 using an authcode", $user);
2298
2299 do_identify($user, $target, $target);
2300 if($pass) {
2301 ns_set($user, $target, 'PASSWD', $pass)
2302 } elsif(nr_chk_flag($target, NRF_SENDPASS())) {
2303 notice($user, "YOU MUST CHANGE YOUR PASSWORD NOW", "/NS SET $target PASSWD <newpassword>");
2304 }
2305 }
2306 else {
2307 notice($user, "\002$target\002 authentication failed. Please verify that you typed or pasted the code correctly.");
2308 }
2309}
2310
2311sub ns_profile($@) {
2312 my ($user, $first, @args) = @_;
2313
2314 my %profile_dispatch = (
2315 'read' => \&ns_profile_read,
2316 'info' => \&ns_profile_read,
2317
2318 'del' => \&ns_profile_del,
2319 'delete' => \&ns_profile_del,
2320
2321 'set' => \&ns_profile_update,
2322 'update' => \&ns_profile_update,
2323 'add' => \&ns_profile_update,
2324
2325 'wipe' => \&ns_profile_wipe,
2326 );
2327
2328 no warnings 'misc';
2329 if(my $sub = $profile_dispatch{$args[0]}) {
2330 # Second command with nick
2331 shift @args;
2332 $sub->($user, $first, @args);
2333 }
2334 elsif(my $sub = $profile_dispatch{$first}) {
2335 # Second command without nick
2336 $sub->($user, get_user_nick($user), @args);
2337 }
2338 elsif(@args == 0) {
2339 # No second command
2340 ns_profile_read($user, ($first || get_user_nick($user)));
2341 }
2342 else {
2343 notice $user,
2344 "Syntax: PROFILE [nick] [SET|DEL|READ|WIPE ...]",
2345 "For help, type: \002/ns help profile\002";
2346 }
2347}
2348
2349sub ns_profile_read($$@) {
2350 my ($user, $target, @args) = @_;
2351
2352 foreach my $nick ((scalar(@args) ? @args : $target)) {
2353 next unless chk_registered($user, $nick);
2354 my @profile_entries = get_profile_ntf($nick);
2355 if(scalar(@profile_entries)) {
2356 notice $user, columnar({TITLE => "Profile information for \002$nick\002:",
2357 NOHIGHLIGHT => nr_chk_flag_user($user, NRF_NOHIGHLIGHT)},
2358 map( ["$_->[0]:", $_->[1]], @profile_entries )
2359 );
2360 }
2361 else {
2362 notice $user, "\002$nick\002 has not created a profile.";
2363 }
2364 }
2365}
2366
2367sub ns_profile_update($$@) {
2368 my ($user, $target, @args) = @_;
2369
2370 return unless chk_registered($user, $target);
2371
2372 unless(is_identified($user, $target) or
2373 adminserv::is_svsop($user, adminserv::S_HELP())
2374 ) {
2375 notice($user, "$target: $err_deny");
2376 return;
2377 }
2378
2379 my ($key, $data) = (shift @args, join(' ', @args));
2380
2381 unless ($key and $data) {
2382 notice $user, "Syntax: PROFILE [nick] SET <item> <text>",
2383 "For help, type: \002/ns help profile\002";
2384 return;
2385 }
2386
2387 if(count_profile_ntf($target) >= MAX_PROFILE) {
2388 notice($user, "You may not have more than ".MAX_PROFILE." profile items.");
2389 return;
2390 }
2391 elsif (length($key) > 32) {
2392 notice($user, "Item name may not be longer than 32 characters.");
2393 return;
2394 }
2395 elsif (length($data) > MAX_PROFILE_LEN) {
2396 my $over = length($data) - MAX_PROFILE_LEN;
2397 notice($user, "Your entry is $over characters too long. (".MAX_PROFILE_LEN." max.)");
2398 return;
2399 }
2400 add_profile_ntf($key, $data, $target);
2401 notice($user, "\002$target\002's \002$key\002 is now \002$data\002");
2402}
2403
2404sub ns_profile_del($$@) {
2405 my ($user, $target, @args) = @_;
2406
2407 return unless chk_registered($user, $target);
2408
2409 unless(is_identified($user, $target) or
2410 adminserv::is_svsop($user, adminserv::S_HELP())
2411 ) {
2412 notice($user, "$target: $err_deny");
2413 return;
2414 }
2415
2416 my $key = shift @args;
2417
2418 unless ($key) {
2419 notice $user, "Syntax: PROFILE [nick] DEL <item>",
2420 "For help, type: \002/ns help profile\002";
2421 return;
2422 }
2423
2424 if(del_profile_ntf($target, $key) == 0) {
2425 notice($user, "There is no profile item \002$key\002 for \002$target\002");
2426 } else {
2427 notice($user, "Profile item \002$key\002 for \002$target\002 deleted.");
2428 }
2429}
2430
2431sub ns_profile_wipe($$@) {
2432 my ($user, $target, undef) = @_;
2433
2434 unless (is_registered($target)) {
2435 notice($user, "$target is not registered.");
2436 next;
2437 }
2438 unless(is_identified($user, $target) or
2439 adminserv::is_svsop($user, adminserv::S_HELP())
2440 ) {
2441 notice($user, "$target: $err_deny");
2442 return;
2443 }
2444
2445 wipe_profile_ntf($target);
2446 notice($user, "Profile for \002$target\002 wiped.");
2447}
2448
2449sub ns_listemail($$) {
2450 my ($user, $email) = @_;
2451 unless(adminserv::is_svsop($user, adminserv::S_HELP())) {
2452 notice($user, $err_deny);
2453 return;
2454 }
2455 my $likeemail = glob2sql($email);
2456 my (@found, $count);
2457
2458 $get_nicks_by_email->execute($likeemail);
2459 while (my ($nick, $ident, $host) = $get_nicks_by_email->fetchrow_array) {
2460 push @found, " $nick ($ident\@$host)";
2461 }
2462 $email =~ s/\%/\*/g;
2463 if ($#found >= 0) {
2464 notice($user, "Nicks matching an email address consisting of \002$email\002");
2465 for(@found) {
2466 notice($user, $_);
2467 $count++;
2468 }
2469 notice($user, "Found \002$count\002 matching nicks.");
2470 } else {
2471 notice($user, "There were no nicknames registered with an email address consisting of \002$email\002");
2472 }
2473}
2474
2475### MISCELLANEA ###
2476
2477sub do_seen($$) {
2478 my ($nick) = @_;
2479 my ($status, $msg);
2480
2481 $get_seen->execute($nick);
2482 if (my ($alias, $root, $lastseen) = $get_seen->fetchrow_array) {
2483 if(my @usernicks = get_nick_user_nicks($nick)) {
2484 $status = 2;
2485 $msg = "using ".(@usernicks==1 ? 'the nick ' : 'the following nicks: ').join(', ', map "\002$_\002", @usernicks);
2486 }
2487 else {
2488 $status = 1;
2489 $msg = time_ago($lastseen) . " ago (".gmtime2($lastseen).")";
2490 }
2491 }
2492 else {
2493 $status = 0; $msg = undef();
2494 }
2495
2496 return ($status, $msg);
2497}
2498
2499# For a whole group:
2500sub unidentify($$;$) {
2501 my ($nick, $msg, $src) = @_;
2502
2503 $nick = get_root_nick($nick);
2504
2505 foreach my $t (get_nick_user_nicks $nick) {
5e682044 2506 my $user = { NICK => $nick, AGENT => $nsuser };
2507 get_user_id ($user);
2508 ircd::notice($nsuser, $user, (ref $msg ? @$msg : $msg)) unless(lc $t eq lc $src);
aecfa1fd 2509 if(is_alias_of($nick, $t)) {
5e682044 2510 ircd::setumode($nsuser, $user, '-r');
aecfa1fd 2511 }
2512 }
2513
2514 $unidentify->execute($nick);
2515}
2516
2517# For a single alias:
2518sub unidentify_single($$) {
2519 my ($nick, $msg) = @_;
5e682044 2520 my $user = { NICK => $nick, AGENT => $nsuser };
2521 get_user_id ($user);
aecfa1fd 2522 if(is_online($nick)) {
5e682044 2523 ircd::setumode($nsuser, $user, '-r');
aecfa1fd 2524 }
2525}
2526
2527sub kill_clones($$) {
2528 my ($user, $ip) = @_;
2529 my $uid = get_user_id($user);
2530 my $src = get_user_nick($user);
2531
2532 return 0 if $ip == 0;
2533
2534 $chk_clone_except->execute($uid);
2535 my ($lim) = $chk_clone_except->fetchrow_array;
2536 return 0 if $lim == MAX_LIM();
2537 $lim = services_conf_clone_limit unless $lim;
2538
2539 $count_clones->execute($ip);
2540 my ($c) = $count_clones->fetchrow_array;
2541
2542 if($c > $lim) {
5e682044 2543 ircd::irckill($nsuser, $user, "Session Limit Exceeded");
aecfa1fd 2544 return 1;
2545 }
2546}
2547
2548sub do_ajoin($$) {
2549 my ($user, $nick) = @_;
2550 my $src = get_user_nick($user);
2551 if(my @chans = get_autojoin_ntf($nick)) {
2552 chanserv::cs_join($user, @chans);
2553 }
2554}
2555
2556sub do_identify ($$$;$$) {
2557 my ($user, $nick, $root, $flags, $svsnick) = @_;
2558 my $uid = get_user_id($user);
2559 my $src = get_user_nick($user);
aecfa1fd 2560 $identify_ign->execute($uid, $root);
2561 $id_update->execute($root, $uid);
2562
2563 notice($user, 'You are now identified.');
2564
2565 delete($user->{NICKFLAGS});
2566 if($flags & NRF_VACATION) {
2567 notice($user, "Welcome back from your vacation, \002$nick\002.");
2568 my $ts = MIME::Base64::encode(pack('N', time()));
2569 chomp $ts;
2570 $del_nicktext->execute(NTF_VACATION, $root); $del_nicktext->finish(); #don't allow dups
2571 $set_vacation_ntf->execute($ts, $root);
2572 $set_vacation_ntf->finish();
2573 }
2574
2575 $get_umode_ntf->execute($nick);
2576 my ($umodes) = $get_umode_ntf->fetchrow_array();
2577 $get_umode_ntf->finish();
2578 if(adminserv::get_svs_level($root)) {
2579 $umodes = modes::merge_umodes('+h', $umodes);
5e682044 2580 ircd::nolag($nsuser, '+', $user);
aecfa1fd 2581 }
2582 $umodes = modes::merge_umodes('+r', $umodes) if(is_identified($user, $src));
2583
2584 hostserv::hs_on($user, $root, 1);
2585
5e682044 2586 if(my @chans = get_autojoin_ntf($nick)) {
2587 ircd::svsjoin($nsuser, $user, @chans);
2588 }
aecfa1fd 2589
2590 my $enforced;
2591 if(enforcer_quit($nick)) {
2592 notice($user, 'Your nick has been released from custody.');
2593 $enforced = 1;
2594 }
2595
2596 if (lc($src) eq lc($nick)) {
5e682044 2597 ircd::setumode($nsuser, $user, $umodes);
aecfa1fd 2598 $update_nickalias_last->execute($nick); $update_nickalias_last->finish();
2599 }
2600 elsif($svsnick) {
5e682044 2601 ircd::svsnick($nsuser, $user, $nick);
2602 ircd::setumode($nsuser, $user, modes::merge_umodes('+r', $umodes) );
aecfa1fd 2603 # the update _should_ be taken care of in nick_change()
2604 #$update_nickalias_last->execute($nick); $update_nickalias_last->finish();
2605 }
2606 elsif(defined $umodes) {
5e682044 2607 ircd::setumode($nsuser, $user, $umodes);
aecfa1fd 2608 }
5e682044 2609
aecfa1fd 2610 do_ajoin($user, $nick);
5e682044 2611
2612 nickserv::do_svssilence($user, $root);
2613 nickserv::do_svswatch($user, $root);
2614
2615 chanserv::akick_alluser($user);
2616 chanserv::set_modes_allchan($user, $flags & NRF_NEVEROP);
2617 chanserv::fix_private_join_before_id($user);
2618
2619 services::ulog($nsnick, LOG_INFO(), "identified to nick $nick (root: $root)", $user);
2620
2621 memoserv::notify($user, $root);
2622 notify_auths($user, $root) if $flags & NRF_AUTH;
aecfa1fd 2623 return ($enforced ? 2 : 1);
2624}
2625
2626sub authcode($;$$) {
2627 my ($nick, $type, $email) = @_;
2628 if($type) {
2629 unless (defined($email)) {
2630 $email = get_email($nick);
2631 }
2632
2633 my $authcode = misc::gen_uuid(4, 5);
2634 $set_authcode_ntf->execute($authcode, $nick); $set_authcode_ntf->finish();
2635 send_email($email, "Nick Authentication Code for $nick",
2636 "Hello $nick,\n\n".
2637
2638 "You are receiving this message from the automated nickname\n".
2639 "management system of the ".$IRCd_capabilities{NETWORK}." network.\n\n".
2640 (lc($type) eq 'emailreg' ?
2641 "If you did not try to register your nickname with us, you can\n".
2642 "ignore this message. If you continue getting similar e-mails\n".
2643 "from us, chances are that someone is intentionally abusing your\n".
2644 "e-mail address. Please contact an administrator for help.\n".
2645
2646 "In order to complete your registration, you must follow the\n".
2647 "instructions in this e-mail before ".gmtime2(time+86400)."\n".
2648
2649 "To complete the registration, the next time you connect, issue the\n".
2650 "following command to NickServ:\n\n".
2651
2652 "After you issue the command, your registration will be complete and\n".
2653 "you will be able to use your nickname.\n\n"
2654
2655 : '').
2656 (lc($type) eq 'sendpass' ?
2657 "You requested a password authentication code for the nickname '$nick'\n".
2658 "on the ".$IRCd_capabilities{'NETWORK'}." IRC Network.\n".
2659 "As per our password policies, an authcode has been created for\n".
2660 "you and e-mailed to the address you set in NickServ.\n".
2661 "To complete the process, you need to return to ".$IRCd_capabilities{'NETWORK'}.",\n".
2662 "and execute the following command: \n\n"
2663 : '').
2664
2665 "/NS EMAILCODE $nick $authcode\n\n".
2666
2667 (lc($type) eq 'sendpass' ?
2668 "YOU MUST CHANGE YOUR PASSWORD AT THIS POINT.\n".
2669 "You can do so via the following command: \n\n".
2670 "/NS SET $nick PASSWD newpassword\n\n".
2671 "alternately, try this command: \n\n".
2672
2673 "/NS EMAILCODE $nick $authcode <password>\n\n"
2674 : '').
2675
2676 "---\n".
2677 "If you feel you have gotten this e-mail in error, please contact\n".
2678 "an administrator.\n\n".
2679
2680 "----\n".
2681 "If this e-mail came to you unsolicited and appears to be spam -\n".
2682 "please e-mail ".main_conf_replyto." with a copy of this e-mail\n".
2683 "including all headers.\n\n".
2684
2685 "Thank you.\n");
2686 }
2687 else {
2688 $get_authcode_ntf->execute($nick, $email);
2689 my ($passed) = $get_authcode_ntf->fetchrow_array();
2690 $get_authcode_ntf->finish();
2691 if ($passed) {
2692 nr_set_flag($nick, NRF_EMAILREG(), 0);
2693 unless(nr_chk_flag($nick, NRF_SENDPASS)) {
2694 $del_nicktext->execute(NTF_AUTHCODE, $nick); $del_nicktext->finish();
2695 }
2696 return 1;
2697 }
2698 else {
2699 return 0;
2700 }
2701 }
2702}
2703
2704# This is mostly for logging, be careful using it for anything else
2705sub get_hostmask($) {
2706 my ($user) = @_;
2707 my ($ident, $host);
86a50b12 2708 my $src;
2709 if (ref ($user) eq "HASH") {
86a50b12 2710 $src = get_user_nick($user);
2711 }
2712 else { $src = $user; }
aecfa1fd 2713 ($ident, $host) = get_host($user);
2714
2715 return "$src!$ident\@$host";
2716}
2717
2718sub guestnick($) {
2719 my ($nick) = @_;
aecfa1fd 2720 $set_guest->execute(1, $nick);
2721 my $randnick = 'Guest'.int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10));
2722 #Prevent collisions.
2723 while (is_online($randnick)) {
2724 $randnick = 'Guest'.int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10));
2725 }
5e682044 2726 my $user = { NICK => $nick, AGENT => $nsuser };
2727 get_user_id ($user);
2728 ircd::svsnick($nsuser, $user, $randnick);
aecfa1fd 2729
2730 return $randnick;
2731}
2732
2733sub expire {
2734 return if services_conf_noexpire;
2735
2736=cut
2737 my ($ne, $e, $ve, $eve) = (services_conf_nearexpire, services_conf_nickexpire, services_conf_vacationexpire,
2738 services_conf_validate_expire);
2739=cut
2740
2741 $get_expired->execute(time() - (86400 * services_conf_nickexpire),
2742 time() - (86400 * services_conf_vacationexpire),
2743 time() - (86400 * services_conf_validate_expire));
2744 while(my ($nick, $email, $ident, $vhost) = $get_expired->fetchrow_array) {
2745 dropgroup($nick);
2746 wlog($nsnick, LOG_INFO(), "$nick has expired. Email: $email Vhost: $ident\@$vhost");
2747 }
2748
2749 my $time = time();
2750
2751 return unless services_conf_nearexpire; # if nearexpire is zero, don't.
2752 $get_near_expired->execute(
2753 $time - (86400 * (services_conf_nickexpire - services_conf_nearexpire)),
2754 $time - (86400 * (services_conf_vacationexpire - services_conf_nearexpire))
2755 );
2756 while(my ($nick, $email, $flags, $last) = $get_near_expired->fetchrow_array) {
2757 my $expire_days = services_conf_nearexpire;
2758 if ( ( $flags & NRF_VACATION ) and ( $last < time() - (86400 * services_conf_vacationexpire) )
2759 or (($last < time() - (86400 * services_conf_nickexpire)) ) )
2760 {
2761 $expire_days = 0;
2762 } elsif ( ( $flags & NRF_VACATION ) and ( $last > time() - (86400 * services_conf_vacationexpire) )
2763 or (($last > time() - (86400 * services_conf_nickexpire)) ) )
2764 {
2765 # this terrible invention is to determine how many days until their nick will expire.
2766 # this should almost always be ~7, unless something weird happens like
2767 # F_HOLD or svsop status is removed.
2768 # int truncates, so we add 0.5.
2769 $expire_days = -int(($time - ($last + (86400 *
2770 ( ( $flags & NRF_VACATION ) ? services_conf_vacationexpire : services_conf_nickexpire ) )))
2771 / 86400 + .5);
2772 }
2773 if($expire_days >= 1) {
2774
2775 $get_aliases->execute($nick);
2776 my $aliases = $get_aliases->fetchrow_arrayref();
2777
2778 my $message = "We would like to remind you that your registered nick, $nick, will expire\n".
2779 "in approximately $expire_days days unless you sign on and identify.";
2780 if(scalar(@$aliases) > 1) {
2781 $message .= "\n\nThe following nicks are linked in this group:\n " . join("\n ", @$aliases);
2782 }
2783
2784 send_email($email, "$nsnick Expiration Notice", $message);
2785 }
2786
2787 wlog($nsnick, LOG_INFO(), "$nick will expire ".($expire_days <= 0 ? "today" : "in $expire_days days.")." ($email)");
2788 $set_near_expired->execute($nick);
2789 }
2790}
2791
2792sub expire_silence_timed {
2793 my ($time) = shift;
2794 $time = 60 unless $time;
2795 add_timer('', $time, __PACKAGE__, 'nickserv::expire_silence_timed');
2796
2797 find_expired_silences();
2798}
2799
2800# This code is a mess b/c we can only pull one entry at a time
2801# and we want to batch the list to the user and to the ircd.
2802# our SQL statement explicitly orders the silence entries by nickreg.nick
2803sub find_expired_silences() {
2804 $get_expired_silences->execute();
2805 my ($lastnick, @entries);
2806 while(my ($nick, $mask, $comment) = $get_expired_silences->fetchrow_array()) {
2807 if ($nick eq $lastnick) {
2808 } else {
2809 do_expired_silences($lastnick, \@entries);
2810 @entries = ();
2811 $lastnick = $nick;
2812 }
2813 push @entries, [$mask, $comment];
2814 }
2815 if (@entries) {
2816 do_expired_silences($lastnick, \@entries);
2817 }
2818 $get_expired_silences->finish();
2819 $del_expired_silences->execute(); $del_expired_silences->finish();
2820 return;
2821}
2822
2823sub do_expired_silences($$) {
2824 my $nick = $_[0];
2825 my (@entries) = @{$_[1]};
2826
2827 foreach my $user (get_nick_users $nick) {
2828 $user->{AGENT} = $nsnick;
7b3a5814 2829 get_user_id ($user);
5e682044 2830 ircd::svssilence($nsuser, $user, map ( { '-'.$_->[0] } @entries) );
aecfa1fd 2831 #notice($user, "The following SILENCE entries have expired: ".
2832 # join(', ', map ( { $_->[0] } @entries) ));
2833 notice($user, map( { "The following SILENCE entry has expired: \002".$_->[0]."\002 ".$_->[1] } @entries ) );
2834 }
2835}
2836sub do_svssilence($$) {
2837 my ($user, $rootnick) = @_;
026939ee 2838 if ($IRCd_capabilities{SILENCE} eq "") {
2839 notice ($user, "The IRCd is not configured to support SILENCE. Please contact your friendly network administrators.");
2840 return;
2841 }
aecfa1fd 2842 my $target = get_user_nick($user);
2843
2844 $get_silences->execute($rootnick);
2845 my $count = $get_silences->rows;
2846 unless ($get_silences->rows) {
2847 $get_silences->finish;
2848 return;
2849 }
2850 my @silences;
2851 for(my $i = 1; $i <= $count; $i++) {
2852 my ($mask, $time, $expiry) = $get_silences->fetchrow_array;
2853 push @silences, "+$mask";
2854 }
2855 $get_silences->finish;
5e682044 2856 ircd::svssilence($nsuser, $user, @silences);
aecfa1fd 2857 return;
2858}
2859
2860sub do_svswatch($$) {
2861 my ($user, $rootnick) = @_;
026939ee 2862 if ($IRCd_capabilities{WATCH} eq "") {
2863 notice ($user, "The IRCd is not configured to support WATCH. Please contact your friendly network administrators.");
2864 return;
2865 }
aecfa1fd 2866 my $target = get_user_nick($user);
2867
2868 $get_watches->execute($rootnick);
2869 my $count = $get_watches->rows;
2870 unless ($get_watches->rows) {
2871 $get_watches->finish;
2872 return;
2873 }
2874 my @watches;
2875 for(my $i = 1; $i <= $count; $i++) {
2876 my ($mask, $time, $expiry) = $get_watches->fetchrow_array;
2877 push @watches, "+$mask";
2878 }
2879 $get_watches->finish;
5e682044 2880 ircd::svswatch($nsuser, $user, @watches);
aecfa1fd 2881 return;
2882}
2883
2884sub do_umode($$) {
2885 my ($user, $rootnick) = @_;
2886 my $target = get_user_nick($user);
2887
2888 $get_umode_ntf->execute($rootnick);
2889 my ($umodes) = $get_umode_ntf->fetchrow_array; $get_umode_ntf->finish();
2890
5e682044 2891 ircd::setumode($nsuser, $user, $umodes) if $umodes;
aecfa1fd 2892 return
2893}
2894
2895sub notify_auths($$) {
88eba747 2896 my ($user, $nick) = @_;
aecfa1fd 2897 $get_num_nicktext_type->execute($nick, NTF_AUTH);
2898 my ($count) = $get_num_nicktext_type->fetchrow_array(); $get_num_nicktext_type->finish();
2899 notice($user, "$nick has $count channel authorizations awaiting action.",
2900 "To list them, type /ns auth $nick list") if $count;
2901}
2902
2903### PROTECTION AND ENFORCEMENT ###
2904
2905sub protect($) {
2906 my ($nick) = @_;
2907
2908 return if nr_chk_flag($nick, NRF_EMAILREG());
2909 my $lev = protect_level($nick);
5e682044 2910 my $user = { NICK => $nick, AGENT => $nsuser };
2911 get_user_id ($user);
aecfa1fd 2912 notice($user,
2913 "This nickname is registered and protected. If it is your",
2914 "nick, type \002/msg NickServ IDENTIFY <password>\002. Otherwise,",
2915 "please choose a different nick."
2916 ) unless($lev==3);
2917
2918 if($lev == 1) {
2919 warn_countdown("$nick 60");
2920 }
2921 elsif($lev==2) {
2922 collide($nick);
2923 }
2924 elsif($lev==3) {
2925 ircd::svshold($nick, 60, "If this is your nick, type /NS SIDENTIFY $nick \002password\002");
2926 kill_user($user, "Unauthorized nick use with KILL protection enabled.");
2927 $enforcers{lc $nick} = 1;
2928 add_timer($nick, 60, __PACKAGE__, "nickserv::enforcer_delete");
2929 }
2930
2931 return;
2932}
2933
2934sub warn_countdown($) {
2935 my ($cookie) = @_;
2936 my ($nick, $rem) = split(/ /, $cookie);
7b3a5814 2937 $nsuser = { NICK => $nsnick, ID => ircd::getAgentUuid($nsnick) };
5e682044 2938 my $user = { NICK => $nick, AGENT => $nsuser };
2939 get_user_id($user);
aecfa1fd 2940 if (is_identified($user, $nick)) {
2941 $update_nickalias_last->execute($nick); $update_nickalias_last->finish();
2942 return;
2943 }
7d4055c0 2944 elsif(!(is_online($nick)) or !(is_registered($nick))) { return; }
aecfa1fd 2945
2946 if($rem == 0) {
2947 notice($user, 'Your nick is now being changed.');
2948 collide($nick);
2949 } else {
2950 notice($user,
2951 "If you do not identify or change your nick in $rem seconds, your nick will be changed.");
2952 $rem -= 20;
2953 add_timer("$nick $rem", 20, __PACKAGE__, "nickserv::warn_countdown");
2954 }
2955}
2956
2957sub collide($) {
2958 my ($nick) = @_;
5e682044 2959 my $newnick = guestnick($nick);
aecfa1fd 2960 ircd::svshold($nick, 60, "If this is your nick, type /NS SIDENTIFY $nick \002password\002");
2961 $enforcers{lc $nick} = 1;
2962 add_timer($nick, 60, __PACKAGE__, "nickserv::enforcer_delete");
5e682044 2963 return $newnick;
aecfa1fd 2964}
2965
2966sub enforcer_delete($) {
2967 my ($nick) = @_;
2968 delete($enforcers{lc $nick});
2969};
2970
2971sub enforcer_quit($) {
2972 my ($nick) = @_;
2973 if($enforcers{lc $nick}) {
2974 enforcer_delete($nick);
2975 ircd::svsunhold($nick);
2976 return 1;
2977 }
2978 return 0;
2979}
2980
2981### DATABASE UTILITY FUNCTIONS ###
2982
2983sub get_lock($) {
2984 my ($nick) = @_;
2985
2986 $nick = lc $nick;
2987
2988 if($cur_lock) {
2989 if($cur_lock ne $nick) {
2990 really_release_lock($nick);
2991 die("Tried to get two locks at the same time");
2992 }
2993 $cnt_lock++;
2994 } else {
2995 $cur_lock = $nick;
2996 $get_lock->execute(sql_conf_mysql_db.".user.$nick");
2997 $get_lock->finish;
2998 }
2999}
3000
3001sub release_lock($) {
3002 my ($nick) = @_;
3003
3004 $nick = lc $nick;
3005
3006 if($cur_lock and $cur_lock ne $nick) {
3007 really_release_lock($cur_lock);
3008
3009 die("Tried to release the wrong lock");
3010 }
3011
3012 if($cnt_lock) {
3013 $cnt_lock--;
3014 } else {
3015 really_release_lock($nick);
3016 }
3017}
3018
3019sub really_release_lock($) {
3020 my ($nick) = @_;
3021
3022 $cnt_lock = 0;
3023 $release_lock->execute(sql_conf_mysql_db.".user.$nick");
3024 $release_lock->finish;
3025 undef $cur_lock;
3026}
3027
3028sub get_user_modes($) {
3029 my ($user) = @_;
3030
3031 my $uid = get_user_id($user);
3032 $get_umodes->execute($uid);
3033 my ($umodes) = $get_umodes->fetchrow_array;
3034 $get_umodes->finish();
3035 return $umodes;
3036};
3037
3038sub set_vhost($$) {
3039 my ($user, $vhost) = @_;
3040 my $id = get_user_id($user);
3041
3042 return $set_vhost->execute($vhost, $id);
3043}
3044
3045sub set_ident($$) {
3046 my ($user, $ident) = @_;
3047 my $id = get_user_id($user);
3048
3049 return $set_ident->execute($ident, $id);
3050}
3051
3052sub set_ipv6($$$) {
3053 my ($user, $ip, $ipv6) = @_;
3054 my $id = get_user_id($user);
3055
3056 return $set_ip->execute($ip, $ipv6, $id);
3057}
3058sub set_ip($$) {
3059 my ($user, $ip) = @_;
3060 my $id = get_user_id($user);
3061
3062 return $set_ip->execute($ip, undef, $id);
3063}
3064
3065sub get_root_nick($) {
3066 my ($nick) = @_;
3067
3068 $get_root_nick->execute($nick);
3069 my ($root) = $get_root_nick->fetchrow_array;
3070
3071 return $root;
3072}
3073
3074sub get_id_nick($) {
3075 my ($id) = @_;
3076
3077 $get_id_nick->execute($id);
3078 my ($root) = $get_id_nick->fetchrow_array;
3079
3080 return $root;
3081}
3082
3083sub drop($) {
3084 my ($nick) = @_;
3085
3086 my $ret = $drop->execute($nick);
3087 $drop->finish();
3088 return $ret;
3089}
3090
3091sub changeroot($$) {
3092 my ($old, $new) = @_;
3093
3094 return if(lc $old eq lc $new);
3095
3096 $change_root->execute($new, $old);
3097}
3098
3099sub dropgroup($) {
3100 my ($root) = @_;
3101
3102 $del_all_access->execute($root);
3103 $memoserv::delete_all_memos->execute($root);
3104 $memoserv::wipe_ignore->execute($root);
3105 $memoserv::purge_ignore->execute($root);
3106 chanserv::drop_nick_chans($root);
3107 hostserv::del_vhost($root);
3108 $drop_watch->execute($root);
3109 $drop_silence->execute($root);
3110 $drop_nicktext->execute($root);
3111 $delete_aliases->execute($root);
3112 $chanserv::drop_nick_akick->execute($root);
3113 drop($root);
3114}
3115
3116sub is_alias($) {
3117 my ($nick) = @_;
3118
3119 return (get_root_nick($nick) eq $nick);
3120}
3121
3122sub delete_alias($) {
3123 my ($nick) = @_;
3124 return $delete_alias->execute($nick);
3125}
3126
3127sub delete_aliases($) {
3128 my ($root) = @_;
3129 return $delete_aliases->execute($root);
3130}
3131
3132sub get_all_access($) {
3133 my ($nick) = @_;
3134
3135 $get_all_access->execute($nick);
3136 return $get_all_access->fetchrow_array;
3137}
3138
3139sub del_all_access($) {
3140 my ($root) = @_;
3141
3142 return $del_all_access->execute($root);
3143}
3144
3145sub chk_pass($$$) {
3146 my ($nick, $pass, $user) = @_;
3147
3148 if(lc($pass) eq 'force' and adminserv::can_do($user, 'SERVOP')) {
3149 if(adminserv::get_best_svs_level($user) > adminserv::get_svs_level($nick)) {
3150 return 1;
3151 }
3152 }
3153
3154 return validate_pass(get_pass($nick), $pass);
3155}
3156
3157sub inc_nick_inval($) {
3158 my ($user) = @_;
3159 my $id = get_user_id($user);
3160
3161 $inc_nick_inval->execute($id);
3162 $get_nick_inval->execute($id);
3163 my ($nick, $inval) = $get_nick_inval->fetchrow_array;
3164 if($inval > 3) {
5e682044 3165 ircd::irckill($nsuser, $user, 'Too many invalid passwords.');
aecfa1fd 3166 # unnecessary as irckill calls the quit handler.
3167 #nick_delete($nick);
3168 return 0;
3169 } else {
3170 return 1;
3171 }
3172}
3173
3174sub is_registered($) {
3175 my ($nick) = @_;
3176
3177 $is_registered->execute($nick);
3178 if($is_registered->fetchrow_array) {
3179 return 1;
3180 } else {
3181 return 0;
3182 }
3183}
3184
3185sub chk_registered($;$) {
3186 my ($user, $nick) = @_;
3187 my $src = get_user_nick($user);
3188 my $what;
3189
3190 if($nick) {
3191 if(lc $src eq lc $nick) {
3192 $what = "Your nick";
3193 } else {
3194 $what = "The nick \002$nick\002";
3195 }
3196 } else {
3197 $nick = get_user_nick($user) unless $nick;
3198 $what = "Your nick";
3199 }
3200
3201 unless(is_registered($nick)) {
3202 notice($user, "$what is not registered.");
3203 return 0;
3204 }
3205
3206 return 1;
3207}
3208
3209sub is_alias_of($$) {
3210 $is_alias_of->execute($_[0], $_[1]);
3211 return ($is_alias_of->fetchrow_array ? 1 : 0);
3212}
3213
3214sub check_identify($) {
3215 my ($user) = @_;
3216 my $nick = get_user_nick($user);
3217 if(is_registered($nick)) {
3218 if(is_identified($user, $nick)) {
5e682044 3219 ircd::setumode($nsuser, $user, '+r');
aecfa1fd 3220 $update_nickalias_last->execute($nick); $update_nickalias_last->finish();
3221 return 1;
3222 } else {
3223 protect($nick);
3224 }
3225 }
3226 return 0;
3227}
3228
3229sub cleanup_users() {
3230 add_timer('', services_conf_old_user_age, __PACKAGE__, 'nickserv::cleanup_users');
3231 if(DEBUG) {
3232 ircd::privmsg('ServServ', main_conf_diag, "Starting cleanup_users()");
3233 }
3234
3235 my $time = (time() - (services_conf_old_user_age * 2));
3236 if(DEBUG) {
3237 $get_dead_users->execute($time);
3238 my $arrayRef = $get_dead_users->fetchall_arrayref();
3239 if($arrayRef && scalar(@$arrayRef)) {
3240 ircd::privmsg('ServServ', main_conf_diag, columnar( { BORDER => 1, NOHIGHLIGHT => 1 }, @$arrayRef ) );
3241 }
3242 $get_dead_users->finish();
3243 }
3244 my $rows = $cleanup_users->execute($time) + 0;
3245 $cleanup_nickid->execute();
3246 $cleanup_chanuser->execute();
3247 if(DEBUG) {
3248 ircd::privmsg('ServServ', main_conf_diag, "Deleted $rows dead users\n");
3249 ircd::privmsg('ServServ', main_conf_diag, "Ending cleanup_users()");
3250 }
3251}
3252
3253sub fix_vhosts() {
3254 return; # XXX
3255 add_timer('fix_vhosts', 5, __PACKAGE__, 'nickserv::fix_vhosts');
3256 $get_hostless_nicks->execute();
3257 while (my ($nick) = $get_hostless_nicks->fetchrow_array) {
5e682044 3258 ircd::notice($nsuser, main_conf_diag, "HOSTLESS NICK $nick");
aecfa1fd 3259 ircd::userhost($nick);
3260 ircd::userip($nick);
3261 }
3262 $get_hostless_nicks->finish();
3263}
3264
3265sub nick_cede($) {
3266 my ($nick) = @_;
3267 my $id;
3268
3269 $get_user_id->execute($nick);
3270 if($id = $get_user_id->fetchrow_array) {
3271 $nick_id_delete->execute($id);
3272 $nick_delete->execute($nick);
3273 }
3274}
3275
3276### IRC EVENTS ###
3277
3278sub nick_create {
5e682044 3279 my ($user, $time, $ident, $host, $vhost, $server, $svsstamp, $modes, $gecos, $ip, $cloakhost) = @_;
3280 my $nick = get_user_nick ($user);
aecfa1fd 3281 get_lock($nick);
3282 if ($vhost eq '*') {
3283 if ({modes::splitumodes($modes)}->{x} eq '+') {
3284 if(defined($cloakhost)) {
3285 $vhost = $cloakhost;
3286 }
3287 else { # This should never happen with CLK or VHP
3288 ircd::userhost($nick);
3289 }
3290 } else {
3291 $vhost = $host;
3292 }
3293 }
3294
3295 my $id;
5e682044 3296 if ($id = get_user_id( $user )) {
3297 #$id = decodeUUID ($id);
3298 $nick_checkExists->execute ($id, $time);
3299 my $exists = $nick_checkExists -> fetchrow_array();
3300 my $flags = (synced() ? UF_FINISHED() : 0);
3301 unless (defined($exists)) {
3302 $nick_deleteChanUser -> execute ($id);
3303 $nick_deleteNickCh -> execute ($id);
3304 $nick_deleteNickId -> execute ($id);
3305 $id_delUser -> execute ($id);
92c29160 3306 $nick_delUser -> execute ($nick);
5e682044 3307 $nick_create2 -> execute ($id, $nick, $time, $ident, $host, $vhost, $server, $modes, $gecos, $flags, $cloakhost);
3308 }
3309 else {
3310 $nick_create_old->execute ($nick, $ident, $host, $vhost, $server, $modes, $gecos, $flags, $cloakhost, $id);
3311 }
3312 $add_nickchg->execute($ircline, $nick, $nick);
3313 release_lock($nick);
3314 check_identify($user);
3315 return $id;
3316 }
aecfa1fd 3317 if($svsstamp) {
3318 $get_user_nick->execute($svsstamp);
3319 my ($oldnick) = $get_user_nick->fetchrow_array();
3320 $id = $svsstamp if defined($oldnick);
3321 }
3322 else {
3323 $nick_check->execute($nick, $time);
3324 ($id) = $nick_check->fetchrow_array;
3325 }
3326
3327 if($id) {
3328 $olduser{lc $nick} = 1;
3329 $nick_create_old->execute($nick, $ident, $host, $vhost, $server, $modes, $gecos, UF_FINISHED(), $cloakhost, $id);
3330 } else {
3331 nick_cede($nick);
3332
3333 my $flags = (synced() ? UF_FINISHED() : 0);
3334 my $i;
3335 while($i < 10 and !$nick_create->execute($nick, $time, $ident, $host, $vhost, $server, $modes, $gecos, $flags, $cloakhost)) { $i++ }
3336 $id = get_user_id( { NICK => $nick } ); # There needs to be a better way to do this
3337 }
5e682044 3338 ircd::setsvsstamp($nsuser, $user, $id) unless $svsstamp == $id;
aecfa1fd 3339
3340 $add_nickchg->execute($ircline, $nick, $nick);
3341
3342 release_lock($nick);
3343
3344 $newuser{lc $nick} = 1;
3345
3346 if($ip) {
3347 nickserv::userip(undef, $nick, $ip);
3348 }
3349 else { # This should never happen with NICKIP
3350 ircd::userip($nick);
3351 }
3352
3353 return $id;
3354}
3355
3356sub nick_create_post($) {
3357 my ($nick) = @_;
3358 my $user = { NICK => $nick };
3359 my $old = $olduser{lc $nick};
3360 delete $olduser{lc $nick};
3361
3362 operserv::do_news($nick, 'u') unless($old);
3363
3364 get_lock($nick);
3365
3366 check_identify($user);
3367
3368 release_lock($nick);
3369}
3370
3371sub nick_delete($$) {
5e682044 3372 my ($user, $quit) = @_;
3373 my $nick = $user->{NICK};
aecfa1fd 3374 get_lock($nick);
aecfa1fd 3375 my $id = get_user_id($user);
aecfa1fd 3376 $del_nickchg_id->execute($id); $del_nickchg_id->finish();
aecfa1fd 3377 $quit_update->execute($quit, $id); $quit_update->finish();
3378 $update_lastseen->execute($id); $update_lastseen->finish();
aecfa1fd 3379 $get_quit_empty_chans->execute($id);
aecfa1fd 3380 $chan_user_partall->execute($id); $chan_user_partall->finish();
3381 #$nick_chan_delete->execute($id); $nick_chan_delete->finish();
3382 $nick_quit->execute($nick); $nick_quit->finish();
aecfa1fd 3383 release_lock($nick);
aecfa1fd 3384 while(my ($cn) = $get_quit_empty_chans->fetchrow_array) {
3385 chanserv::channel_emptied({CHAN => $cn});
3386 }
3387 $get_quit_empty_chans->finish();
3388}
3389
3390sub squit($$$) {
3391 my (undef, $servers, $reason) = @_;
3392
3393 $get_squit_lock->execute; $get_squit_lock->finish;
3394
3395 foreach my $server (@$servers) {
3396 $get_squit_empty_chans->execute($server);
3397
3398 $squit_nickreg->execute($server);
3399 $squit_nickreg->finish;
3400
3401 $squit_lastquit->execute("Netsplit from $server", $server);
3402 $squit_lastquit->finish;
3403
3404 $squit_users->execute($server);
3405 $squit_users->finish;
3406
3407 while(my ($cn) = $get_squit_empty_chans->fetchrow_array) {
3408 chanserv::channel_emptied({CHAN => $cn});
3409 }
3410 $get_squit_empty_chans->finish;
3411 }
3412
3413 $unlock_tables->execute; $unlock_tables->finish;
3414}
3415
3416sub nick_change($$$) {
5e682044 3417 my ($user, $new, $time) = @_;
3418 my $old = $user->{NICK};
aecfa1fd 3419 return if(lc $old eq lc $new);
aecfa1fd 3420 get_lock($old);
3421 nick_cede($new);
5e682044 3422 $nick_change->execute($new, $old);
aecfa1fd 3423 $add_nickchg->execute($ircline, $new, $new);
3424 release_lock($old);
aecfa1fd 3425 if($new =~ /^guest/i) {
3426 $get_guest->execute($new);
3427 my ($guest) = $get_guest->fetchrow_array();
3428 if($guest) {
3429 $set_guest->execute(0, $new);
3430 } else {
3431 guestnick($new);
3432 }
3433 return;
3434 }
5e682044 3435 my $user = { NICK => $new, AGENT => $nsuser };
3436 get_user_id($user);
3437 ircd::setumode($nsuser, $user, '-r')
3438 unless check_identify({ NICK => $new });
3439}
3440sub handle_oper($) {
3441 my ($user) = @_;
3442 my $nick = $user->{NICK};
3443 get_lock($nick);
3444 my $id = get_user_id($user);
3445 $get_umodes->execute($id);
3446 my ($omodes) = $get_umodes->fetchrow_array;
3447 $set_umodes->execute(modes::add($omodes, "o", 0), $id);
3448 #this is _safe_. even an oper block with no privs gets +o
3449 #it's just not passed to srsv for some reason, all we get is :UID opertype X
026939ee 3450 release_lock ($nick);
aecfa1fd 3451}
aecfa1fd 3452sub umode($$) {
5e682044 3453 my ($user, $modes) = @_;
3454 my $nick = $user->{NICK};
aecfa1fd 3455 get_lock($nick);
3456
3457 my $id = get_user_id($user);
3458
3459 $get_umodes->execute($id);
3460 my ($omodes) = $get_umodes->fetchrow_array;
3461 $set_umodes->execute(modes::add($omodes, $modes, 0), $id);
3462
3463
3464 my %modelist = modes::splitumodes($modes);
3465 if (defined($modelist{x})) {
3466 if($modelist{x} eq '-') {
3467 my ($ident, $host) = get_host($user);
3468 do_chghost(undef, $nick, $host, 1);
3469 }
3470 elsif(($modelist{x} eq '+') and !defined($modelist{t}) ) {
3471 my (undef, $cloakhost) = get_cloakhost($user);
3472 if($cloakhost) {
3473 do_chghost(undef, $nick, $cloakhost, 1);
3474 } else {
3475 ircd::userhost($nick);
3476 }
3477 }
3478 }
3479=cut
3480# awaiting resolution UnrealIRCd bug 2613
3481 elsif ($modelist{t} eq '-') {
3482 my %omodelist = modes::splitumodes($omodes);
3483 if($omodelist{x} eq '+') {
3484 my (undef, $cloakhost) = get_cloakhost($user);
3485 if($cloakhost) {
3486 do_chghost(undef, $nick, $cloakhost, 1);
3487 } else {
3488 ircd::userhost($nick);
3489 }
3490 }
3491 }
3492=cut
3493 release_lock($nick);
3494
3495 # Else we will get it in a sethost or chghost
3496 # Also be aware, our tracking of umodes xt is imperfect
3497 # as the ircd doesn't always report it to us
3498 # This might need fixing up in chghost()
3499}
3500
3501sub killhandle($$$$) {
92c29160 3502 my ($srcUser, $dstUser, $path, $reason) = @_;
3503 my $dst = $dstUser->{NICK};
3504 my $src = $srcUser->{NICK};
aecfa1fd 3505 unless (is_agent($dst)) {
92c29160 3506 nick_delete($dstUser, "Killed ($src ($reason))");
aecfa1fd 3507 }
3508}
3509
3510sub userip($$$) {
3511 my($src, $nick, $ip) = @_;
3512 my $is_ipv6;
3513 ($is_ipv6, $ip) = is_ipv6($ip);
3514 my $user = { 'NICK' => $nick };
3515 my $new = $newuser{lc $nick};
3516 delete $newuser{lc $nick};
3517 #my $targetid = get_nick_id($target);
3518 my $iip;
3519 if(!$is_ipv6) {
3520 my @ips = split(/\./, $ip);
3521 for(my $i; $i < 4; $i++) {
3522 $iip += $ips[$i] * (2 ** ((3 - $i) * 8));
3523 }
3524 } else {
3525 $iip = Socket6::inet_pton(&AF_INET6, $ip);
3526 }
3527
3528 get_lock($nick);
3529
3530 my $id = get_user_id($user);
3531 if(!$is_ipv6) {
3532 set_ip($user, $iip);
3533 } else {
3534 $iip = get_ipv6_net($ip);
3535 set_ipv6($user, $iip, $ip);
3536 }
3537 my $killed = kill_clones($user, $iip);
3538
3539 release_lock($nick);
3540
3541 nick_create_post($nick) if(!$killed and $new);
3542}
3543
3544sub chghost($$$) {
3545 my ($src, $dst, $vhost) = @_;
3546 my $user = { NICK => $dst };
3547 my $uid = get_user_id($user);
3548
3549 get_lock($dst);
3550 do_chghost($src, $dst, $vhost, 1);
3551
3552 $get_umodes->execute($uid);
3553 my ($omodes) = $get_umodes->fetchrow_array;
3554 # I'm told that this is only valid if CLK is set, and
3555 # there is no good way yet to get info from the ircd/net
3556 # module to this code. it stinks of ircd-specific too
3557 # Also, we currently do any USERHOST replies as CHGHOST events
3558 # However, that is no longer necessary with CLK
3559 $set_umodes->execute(modes::add($omodes, '+xt', 0), $uid);
3560 release_lock($dst);
3561}
3562
3563sub do_chghost($$$;$) {
3564# Don't use this for the handler,
3565# this is only for internal use
3566# where we don't want full loopback semantics.
3567# We call it from the normal handler.
3568 my ($src, $dst, $vhost, $no_lock) = @_;
3569# $no_lock is for where we already took the lock in the caller
3570# MySQL's GET LOCK doesn't allow recursive locks
3571 my $user = { NICK => $dst };
3572 my $uid = get_user_id($user);
3573
3574 $update_regnick_vhost->execute($vhost, $uid);
3575 $update_regnick_vhost->finish();
3576
3577 get_lock($dst) unless $no_lock;
3578
3579 set_vhost($user, $vhost);
3580 chanserv::akick_alluser($user);
3581
3582 release_lock($dst) unless $no_lock;
3583}
3584
3585sub chgident($$$) {
3586 my ($src, $dst, $ident) = @_;
3587 my $user = { NICK => $dst };
3588
3589 set_ident($user, $ident);
3590 chanserv::akick_alluser($user);
3591}
3592
35931;