1 # This file is part of SurrealServices.
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.
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.
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
20 use SrSv
::Timer
qw(add_timer);
21 use SrSv
::IRCd
::State
qw($ircline synced initial_synced %IRCd_capabilities);
23 use SrSv
::Conf
qw(main services sql);
24 use SrSv
::Conf2Consts
qw(main services sql);
25 use SrSv
::HostMask
qw(normalize_hostmask hostmask_to_regexp parse_mask parse_hostmask make_hostmask);
27 use SrSv
::MySQL
qw( $dbh :sql_types );
28 use SrSv
::MySQL
::Glob
;
30 use SrSv
::Shared
qw(%newuser %olduser);
33 use SrSv
::Text
::Format
qw(columnar);
39 use SrSv
::User
::Notice
;
40 use SrSv
::Help
qw( sendhelp );
42 use SrSv
::NickReg
::Flags
;
43 use SrSv
::NickReg
::User
'/./';
44 use SrSv
::Hash
::Passwords
;
46 use SrSv
::NickControl
::Enforcer
qw(%enforcers);
50 use SrSv
::Util
qw( makeSeqList );
51 use SrSv
::IRCd
::Send qw
(getAgentRevUuid ircd
::getAgentUuid
);
54 use SrSv
::NickReg
::NickText
;
58 require SrSv
::MySQL
::Stub
;
61 # Clone exception max limit.
62 # This number typically means infinite/no-limit.
66 # This could be made a config option
67 # But our config system currently sucks.
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
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,
79 our $nsnick_default = 'NickServ';
80 our $nsnick = $nsnick_default;
81 our $nsuser = { NICK
=> $nsnick, ID
=> ircd
::getAgentUuid
($nsnick) }; #FIXME - erry
85 our @protect_short = ('none', 'normal', 'high', 'kill');
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.'
92 our %protect_level = (
113 $nick_check, $nick_checkExists,
114 $nick_create, $nick_create2, $nick_create_old, $nick_change, $nick_quit, $nick_delete, $nick_id_delete,
115 $get_quit_empty_chans, $nick_chan_delete, $chan_user_partall,
118 $get_squit_lock, $squit_users, $squit_nickreg, $get_squit_empty_chans, $squit_lastquit,
120 $del_nickchg_id, $add_nickchg, $reap_nickchg,
122 $get_nick_inval, $inc_nick_inval,
126 $get_guest, $set_guest,
128 $get_lock, $release_lock,
130 $get_umodes, $set_umodes,
133 $set_vhost, $set_ident, $set_ip,
134 $update_regnick_vhost, $get_regd_time, $get_nickreg_quit,
136 $chk_clone_except, $count_clones,
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,
145 $get_register_lock, $register, $create_alias, $drop, $change_root,
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,
151 $lock_user_table, $unlock_tables,
155 $cleanup_nickid, $cleanup_users, $cleanup_chanuser,
158 $get_expired, $get_near_expired, $set_near_expired,
160 $get_watches, $check_watch, $set_watch, $del_watch, $drop_watch,
161 $get_silences, $check_silence, $set_silence, $del_silence, $drop_silence,
163 $get_expired_silences, $del_expired_silences,
167 $set_greet, $get_greet, $get_greet_nick, $del_greet,
168 $get_num_nicktext_type, $drop_nicktext,
170 $get_auth_chan, $get_auth_num, $del_auth, $list_auth, $add_auth,
174 $set_umode_ntf, $get_umode_ntf,
176 $set_vacation_ntf, $get_vacation_ntf,
178 $set_authcode_ntf, $get_authcode_ntf,
182 $nick_deleteChanUser, $nick_deleteNickCh, $nick_deleteNickId,
183 $id_delUser, $nick_delUser,
187 $nick_check = $dbh->prepare("SELECT id FROM user WHERE nick=? AND online=0 AND time=?");
188 $nick_checkExists = $dbh -> prepare
("SELECT nick FROM user WHERE id=? AND time=?");
189 $nick_deleteChanUser = $dbh -> prepare
("DELETE FROM chanuser WHERE nickid=?");
190 $nick_deleteNickCh = $dbh -> prepare
("DELETE FROM nickchg WHERE nickid=?");
191 $nick_deleteNickId = $dbh -> prepare
("DELETE FROM nickid WHERE id=?");
192 $id_delUser = $dbh->prepare ("DELETE FROM user WHERE id=?");
193 $nick_delUser = $dbh->prepare ("DELETE FROM user WHERE nick=?");
194 $nick_create = $dbh->prepare("INSERT INTO user SET nick=?, time=?, inval=0, ident=?, host=?, vhost=?, server=?, modes=?,
195 gecos=?, flags=?, cloakhost=?, online=1");
196 $nick_create2 = $dbh->prepare("INSERT INTO user SET id=?, nick=?, time=?, inval=0, ident=?, host=?, vhost=?, server=?, modes=?,
197 gecos=?, flags=?, cloakhost=?, online=1");
198 # $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");
199 $nick_create_old = $dbh->prepare("UPDATE user SET nick=?, ident=?, host=?, vhost=?, server=?, modes=?, gecos=?,
200 flags=?, cloakhost=?, online=1 WHERE id=?");
201 $nick_change = $dbh->prepare("UPDATE user SET nick=? WHERE nick=?");
202 $nick_quit = $dbh->prepare("UPDATE user SET online=0, quittime=UNIX_TIMESTAMP() WHERE nick=?");
203 $nick_delete = $dbh->prepare("DELETE FROM user WHERE nick=?");
204 $nick_id_delete = $dbh->prepare("DELETE FROM nickid WHERE id=?");
205 $get_quit_empty_chans = $dbh->prepare("SELECT cu2.chan, COUNT(*) AS c
206 FROM chanuser AS cu1, chanuser AS cu2
208 AND cu1.chan=cu2.chan AND cu1.joined=1 AND cu2.joined=1
209 GROUP BY cu2.chan HAVING c=1 ORDER BY NULL");
210 $nick_chan_delete = $dbh->prepare("DELETE FROM chanuser WHERE nickid=?");
211 $chan_user_partall = $dbh->prepare("UPDATE chanuser SET joined=0 WHERE nickid=?");
212 $get_hostless_nicks = $dbh->prepare("SELECT nick FROM user WHERE vhost='*'");
214 $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");
215 $squit_users = $dbh->prepare("UPDATE chanuser, user
216 SET chanuser.joined=0, user.online=0, user.quittime=UNIX_TIMESTAMP()
217 WHERE user.id=chanuser.nickid AND user.server=?");
218 # Must call squit_nickreg and squit_lastquit before squit_users as it modifies user.online
219 $squit_nickreg = $dbh->prepare("UPDATE nickreg, nickid, user
220 SET nickreg.last=UNIX_TIMESTAMP()
221 WHERE nickreg.id=nickid.nrid AND nickid.id=user.id
222 AND user.online=1 AND user.server=?");
224 $squit_lastquit = $dbh->prepare("UPDATE nickid, user, nicktext
226 WHERE nicktext.nrid=nickid.nrid AND nickid.id=user.id
227 AND user.online=1 AND user.server=?");
229 $squit_lastquit = $dbh->prepare("REPLACE INTO nicktext ".
230 "SELECT nickid.nrid, ".NTF_QUIT
.", 0, '', ? ".
231 "FROM nickid JOIN user ON (nickid.id=user.id) ".
232 "WHERE user.online=1 AND user.server=?");
233 $get_squit_empty_chans = $dbh->prepare("SELECT cu2.chan, COUNT(*) AS c
234 FROM user, chanuser AS cu1, chanuser AS cu2
235 WHERE user.server=? AND cu1.nickid=user.id
236 AND cu1.chan=cu2.chan AND cu1.joined=1 AND cu2.joined=1
237 GROUP BY cu2.chan HAVING c=1 ORDER BY NULL");
239 $del_nickchg_id = $dbh->prepare("DELETE FROM nickchg WHERE nickid=?");
240 $add_nickchg = $dbh->prepare("REPLACE INTO nickchg SELECT ?, id, ? FROM user WHERE nick=?");
241 $reap_nickchg = $dbh->prepare("DELETE FROM nickchg WHERE seq<?");
243 $get_nick_inval = $dbh->prepare("SELECT nick, inval FROM user WHERE id=?");
244 $inc_nick_inval = $dbh->prepare("UPDATE user SET inval=inval+1 WHERE id=?");
246 $is_registered = $dbh->prepare("SELECT 1 FROM nickalias WHERE alias=?");
247 $is_alias_of = $dbh->prepare("SELECT 1 FROM nickalias AS n1 LEFT JOIN nickalias AS n2 ON n1.nrid=n2.nrid
248 WHERE n1.alias=? AND n2.alias=? LIMIT 1");
250 $get_guest = $dbh->prepare("SELECT flags & @{[UF_GUEST]} FROM user WHERE nick=?");
251 $set_guest = $dbh->prepare("UPDATE user SET flags = IF(?, flags | @{[UF_GUEST]}, flags & ~@{[UF_GUEST]})
254 $get_lock = $dbh->prepare("SELECT GET_LOCK(?, 10)");
255 $release_lock = $dbh->prepare("SELECT RELEASE_LOCK(?)");
257 $get_umodes = $dbh->prepare("SELECT modes FROM user WHERE id=?");
258 $set_umodes = $dbh->prepare("UPDATE user SET modes=? WHERE id=?");
260 $get_info = $dbh->prepare("SELECT nickreg.email, nickreg.regd, nickreg.last, nickreg.flags, nickreg.ident,
261 nickreg.vhost, nickreg.gecos, nickalias.last
262 FROM nickreg, nickalias WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
263 $get_nickreg_quit = $dbh->prepare("SELECT nicktext.data FROM nickreg, nicktext, nickalias
264 WHERE nickalias.nrid=nickreg.id AND nickalias.alias=? AND
265 (nicktext.nrid=nickreg.id AND nicktext.type=".NTF_QUIT
.")");
266 $set_ident = $dbh->prepare("UPDATE user SET ident=? WHERE id=?");
267 $set_vhost = $dbh->prepare("UPDATE user SET vhost=? WHERE id=?");
268 $set_ip = $dbh->prepare("UPDATE user SET ip=?, ipv6=? WHERE id=?");
269 $update_regnick_vhost = $dbh->prepare("UPDATE nickreg,nickid SET nickreg.vhost=?
270 WHERE nickreg.id=nickid.nrid AND nickid.id=?");
271 $get_regd_time = $dbh->prepare("SELECT nickreg.regd FROM nickreg, nickalias
272 WHERE nickalias.nrid=nickreg.id and nickalias.alias=?");
274 $chk_clone_except = $dbh->prepare("SELECT
275 GREATEST(IF((user.ip >> (32 - sesexip.mask)) = (sesexip.ip >> (32 - sesexip.mask)), sesexip.lim, 0),
276 IF(IF(sesexname.serv, user.server, user.host) LIKE sesexname.host, sesexname.lim, 0)) AS n
277 FROM user, sesexip, sesexname WHERE user.id=? ORDER BY n DESC LIMIT 1");
278 $count_clones = $dbh->prepare("SELECT COUNT(*) FROM user WHERE ip=? AND online=1");
280 $get_root_nick = $dbh->prepare("SELECT nickreg.nick FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
281 $get_id_nick = $dbh->prepare("SELECT nickreg.nick FROM nickreg WHERE nickreg.id=?");
282 $identify = $dbh->prepare("INSERT INTO nickid SELECT ?, nickalias.nrid FROM nickalias WHERE alias=?");
283 $identify_ign = $dbh->prepare("INSERT IGNORE INTO nickid SELECT ?, nickalias.nrid FROM nickalias WHERE alias=?");
284 $id_update = $dbh->prepare("UPDATE nickreg, user SET
285 nickreg.last=UNIX_TIMESTAMP(), nickreg.ident=user.ident,
286 nickreg.vhost=user.vhost, nickreg.gecos=user.gecos,
287 nickreg.nearexp=0, nickreg.flags = (nickreg.flags & ~". NRF_VACATION
.")
288 WHERE nickreg.nick=? AND user.id=?");
289 $logout = $dbh->prepare("DELETE FROM nickid WHERE id=?");
290 $unidentify = $dbh->prepare("DELETE FROM nickid USING nickreg, nickid WHERE nickreg.nick=? AND nickid.nrid=nickreg.id");
292 $update_lastseen = $dbh->prepare("UPDATE nickreg,nickid SET nickreg.last=UNIX_TIMESTAMP()
293 WHERE nickreg.id=nickid.nrid AND nickid.id=?");
294 $update_nickalias_last = $dbh->prepare("UPDATE nickalias SET last=UNIX_TIMESTAMP() WHERE alias=?");
295 $quit_update = $dbh->prepare("REPLACE INTO nicktext
296 SELECT nickreg.id, ".NTF_QUIT
().", 0, NULL, ? FROM nickreg, nickid
297 WHERE nickreg.id=nickid.nrid AND nickid.id=?");
299 $set_protect_level = $dbh->prepare("UPDATE nickalias SET protect=? WHERE alias=?");
302 $set_email = $dbh->prepare("UPDATE nickreg, nickalias SET nickreg.email=? WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
304 $set_pass = $dbh->prepare("UPDATE nickreg, nickalias SET nickreg.pass=? WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
306 $get_register_lock = $dbh->prepare("LOCK TABLES nickalias WRITE, nickreg WRITE");
307 $register = $dbh->prepare("INSERT INTO nickreg SET nick=?, pass=?, email=?, flags=".NRF_HIDEMAIL
().", regd=UNIX_TIMESTAMP(), last=UNIX_TIMESTAMP()");
308 $create_alias = $dbh->prepare("INSERT INTO nickalias SELECT id, ?, NULL, NULL FROM nickreg WHERE nick=?");
310 $drop = $dbh->prepare("DELETE FROM nickreg WHERE nick=?");
312 $get_aliases = $dbh->prepare("SELECT nickalias.alias FROM nickalias, nickreg WHERE
313 nickalias.nrid=nickreg.id AND nickreg.nick=? ORDER BY nickalias.alias");
314 $get_glist = $dbh->prepare("SELECT nickalias.alias, nickalias.protect, nickalias.last
315 FROM nickalias, nickreg WHERE
316 nickalias.nrid=nickreg.id AND nickreg.nick=? ORDER BY nickalias.alias");
317 $count_aliases = $dbh->prepare("SELECT COUNT(*) FROM nickalias, nickreg WHERE
318 nickalias.nrid=nickreg.id AND nickreg.nick=?");
319 $get_random_alias = $dbh->prepare("SELECT nickalias.alias FROM nickalias, nickreg WHERE
320 nickalias.nrid=nickreg.id AND nickreg.nick=? AND nickalias.alias != nickreg.nick LIMIT 1");
321 $delete_alias = $dbh->prepare("DELETE FROM nickalias WHERE alias=?");
322 $delete_aliases = $dbh->prepare("DELETE FROM nickalias USING nickreg, nickalias WHERE
323 nickalias.nrid=nickreg.id AND nickreg.nick=?");
325 $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");
326 $del_all_access = $dbh->prepare("DELETE FROM chanacc USING chanacc, nickreg WHERE chanacc.nrid=nickreg.id AND nickreg.nick=?");
328 $change_root = $dbh->prepare("UPDATE nickreg SET nick=? WHERE nick=?");
330 $unlock_tables = $dbh->prepare("UNLOCK TABLES");
332 $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 $cleanup_chanuser = $dbh->prepare("DELETE FROM chanuser USING chanuser
335 LEFT JOIN user ON (chanuser.nickid=user.id) WHERE user.id IS NULL;");
336 $cleanup_nickid = $dbh->prepare("DELETE FROM nickid USING nickid
337 LEFT JOIN user ON(nickid.id=user.id)
338 WHERE user.id IS NULL");
339 $cleanup_users = $dbh->prepare("DELETE FROM user WHERE online=0 AND quittime>0 AND quittime<?");
340 $get_dead_users = $dbh->prepare("SELECT id,nick,time,online,quittime FROM user
341 WHERE online=0 AND quittime>0 AND quittime<?");
343 $get_expired = $dbh->prepare("SELECT nickreg.nick, nickreg.email, nickreg.ident, nickreg.vhost
344 FROM nickreg LEFT JOIN nickid ON(nickreg.id=nickid.nrid)
345 LEFT JOIN svsop ON(nickreg.id=svsop.nrid)
346 WHERE nickid.nrid IS NULL AND svsop.nrid IS NULL ".
347 'AND ('.(services_conf_nearexpire
? 'nickreg.nearexp!=0 AND' : '').
348 " ( !(nickreg.flags & " . NRF_HOLD
. ") AND !(nickreg.flags & " . NRF_VACATION
. ") AND nickreg.last<? ) OR
349 ( (nickreg.flags & " . NRF_VACATION
. ") AND nickreg.last<? ) ) OR
350 ( (nickreg.flags & ". NRF_EMAILREG
.") AND nickreg.last<?)");
351 $get_near_expired = $dbh->prepare("SELECT nickreg.nick, nickreg.email, nickreg.flags, nickreg.last
352 FROM nickreg LEFT JOIN nickid ON(nickreg.id=nickid.nrid)
353 LEFT JOIN svsop ON(nickreg.id=svsop.nrid)
354 WHERE nickid.nrid IS NULL AND svsop.nrid IS NULL AND nickreg.nearexp=0 AND
355 ( ( !(nickreg.flags & " . NRF_HOLD
. ") AND !(nickreg.flags & " . NRF_VACATION
. ") AND nickreg.last<? ) OR
356 ( (nickreg.flags & " . NRF_VACATION
. ") AND nickreg.last<? )
358 $set_near_expired = $dbh->prepare("UPDATE nickreg SET nearexp=1 WHERE nick=?");
360 $get_watches = $dbh->prepare("SELECT watch.mask, watch.time
362 JOIN nickalias ON (watch.nrid=nickalias.nrid)
363 WHERE nickalias.alias=?");
364 $check_watch = $dbh->prepare("SELECT 1
366 JOIN nickalias ON (watch.nrid=nickalias.nrid)
367 WHERE nickalias.alias=? AND watch.mask=?");
368 $set_watch = $dbh->prepare("INSERT INTO watch SELECT nrid, ?, ? FROM nickalias WHERE alias=?");
369 $del_watch = $dbh->prepare("DELETE FROM watch USING watch
370 JOIN nickalias ON (watch.nrid=nickalias.nrid)
371 WHERE nickalias.alias=? AND watch.mask=?");
372 $drop_watch = $dbh->prepare("DELETE FROM watch
373 USING nickreg JOIN watch ON (watch.nrid=nickreg.id)
374 WHERE nickreg.nick=?");
375 $get_silences = $dbh->prepare("SELECT silence.mask, silence.time, silence.expiry, silence.comment
377 JOIN nickalias ON (silence.nrid=nickalias.nrid)
378 WHERE nickalias.alias=? ORDER BY silence.time");
379 $check_silence = $dbh->prepare("SELECT 1 FROM silence
380 JOIN nickalias ON (silence.nrid=nickalias.nrid)
381 WHERE nickalias.alias=? AND silence.mask=?");
382 $set_silence = $dbh->prepare("INSERT INTO silence SELECT nrid, ?, ?, ?, ? FROM nickalias WHERE alias=?");
383 $del_silence = $dbh->prepare("DELETE FROM silence USING silence, nickalias
384 WHERE silence.nrid=nickalias.nrid AND nickalias.alias=? AND silence.mask=?");
385 $drop_silence = $dbh->prepare("DELETE FROM silence USING nickreg, silence
386 WHERE silence.nrid=nickreg.id AND nickreg.nick=?");
387 $get_expired_silences = $dbh->prepare("SELECT nickreg.nick, silence.mask, silence.comment
389 JOIN silence ON (nickreg.id=silence.nrid)
390 WHERE silence.expiry < UNIX_TIMESTAMP() AND silence.expiry!=0 ORDER BY nickreg.nick");
391 $del_expired_silences = $dbh->prepare("DELETE silence.* FROM silence
392 WHERE silence.expiry < UNIX_TIMESTAMP() AND silence.expiry!=0");
393 $get_silence_by_num = $dbh->prepare("SELECT silence.mask, silence.time, silence.expiry, silence.comment
395 JOIN nickalias ON (silence.nrid=nickalias.nrid)
396 WHERE nickalias.alias=? ORDER BY silence.time LIMIT 1 OFFSET ?");
397 $get_silence_by_num->bind_param(2, 0, SQL_INTEGER
);
399 $get_seen = $dbh->prepare("SELECT nickalias.alias, nickreg.nick, nickreg.last FROM nickreg, nickalias
400 WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
402 $set_greet = $dbh->prepare("REPLACE INTO nicktext SELECT nickreg.id, ".NTF_GREET
.", 0, NULL, ?
403 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
404 $get_greet = $dbh->prepare("SELECT nicktext.data FROM nicktext, nickid
405 WHERE nicktext.nrid=nickid.nrid AND nicktext.type=".NTF_GREET
." AND nickid.id=?
407 $get_greet_nick = $dbh->prepare("SELECT nicktext.data FROM nicktext, nickalias
408 WHERE nicktext.nrid=nickalias.nrid AND nicktext.type=".NTF_GREET
." AND nickalias.alias=?");
409 $del_greet = $dbh->prepare("DELETE nicktext.* FROM nicktext, nickreg, nickalias WHERE
410 nicktext.type=".NTF_GREET
." AND nickreg.id=nickalias.nrid AND nickalias.alias=?");
412 $get_num_nicktext_type = $dbh->prepare("SELECT COUNT(nicktext.id) FROM nicktext, nickalias
413 WHERE nicktext.nrid=nickalias.nrid AND nickalias.alias=? AND nicktext.type=?");
414 $drop_nicktext = $dbh->prepare("DELETE FROM nicktext USING nickreg
415 JOIN nicktext ON (nicktext.nrid=nickreg.id)
416 WHERE nickreg.nick=?");
418 $get_auth_chan = $dbh->prepare("SELECT nicktext.data FROM nicktext, nickalias WHERE
419 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH
().") AND nickalias.alias=? AND nicktext.chan=?");
420 $get_auth_num = $dbh->prepare("SELECT nicktext.chan, nicktext.data FROM nicktext, nickalias WHERE
421 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH
().") AND nickalias.alias=? LIMIT 1 OFFSET ?");
422 $get_auth_num->bind_param(2, 0, SQL_INTEGER
);
423 $del_auth = $dbh->prepare("DELETE nicktext.* FROM nicktext, nickalias WHERE
424 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH
().") AND nickalias.alias=? AND nicktext.chan=?");;
425 $list_auth = $dbh->prepare("SELECT nicktext.chan, nicktext.data FROM nicktext, nickalias WHERE
426 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH
().") AND nickalias.alias=?");
428 $del_nicktext = $dbh->prepare("DELETE nicktext.* FROM nickreg
429 JOIN nickalias ON (nickalias.nrid=nickreg.id)
430 JOIN nicktext ON (nicktext.nrid=nickreg.id)
431 WHERE nicktext.type=? AND nickalias.alias=?");
433 $set_umode_ntf = $dbh->prepare("REPLACE INTO nicktext SELECT nickreg.id, ".NTF_UMODE
().", 1, ?, NULL
434 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
435 $get_umode_ntf = $dbh->prepare("SELECT nicktext.chan FROM nickreg, nickalias, nicktext
436 WHERE nicktext.type=(".NTF_UMODE
().") AND nicktext.nrid=nickalias.nrid AND nickalias.alias=?");
438 $set_vacation_ntf = $dbh->prepare("INSERT INTO nicktext SELECT nickreg.id, ".NTF_VACATION
().", 0, ?, NULL
439 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
440 $get_vacation_ntf = $dbh->prepare("SELECT nicktext.chan FROM nickalias, nicktext
441 WHERE nicktext.nrid=nickalias.nrid AND nicktext.type=".NTF_VACATION
()." AND nickalias.alias=?");
443 $set_authcode_ntf = $dbh->prepare("REPLACE INTO nicktext SELECT nickreg.id, ".NTF_AUTHCODE
().", 0, '', ?
444 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
445 $get_authcode_ntf = $dbh->prepare("SELECT 1 FROM nickalias, nicktext
446 WHERE nicktext.nrid=nickalias.nrid AND nicktext.type=".NTF_AUTHCODE
()." AND nickalias.alias=? AND nicktext.data=?");
448 $get_nicks_by_email = $dbh->prepare("SELECT nickreg.nick, nickreg.ident, nickreg.vhost FROM nickreg
449 WHERE nickreg.email LIKE ? GROUP BY nickreg.nick");
452 import SrSv
::MySQL
::Stub
{
453 add_profile_ntf
=> ['INSERT', "REPLACE INTO nicktext SELECT nickreg.id, @{[NTF_PROFILE]}, 0, ?, ?
454 FROM nickreg JOIN nickalias ON (nickreg.id=nickalias.nrid) WHERE nickalias.alias=?"],
455 get_profile_ntf
=> ['ARRAY', "SELECT chan, data FROM nicktext
456 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
457 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=?"],
458 del_profile_ntf
=> ['NULL', "DELETE nicktext.* FROM nicktext
459 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
460 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=? AND nicktext.chan=?"],
461 wipe_profile_ntf
=> ['NULL', "DELETE nicktext.* FROM nicktext
462 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
463 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=?"],
464 count_profile_ntf
=> ['SCALAR', "SELECT COUNT(chan) FROM nicktext
465 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
466 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=?"],
468 protect_level
=> ['SCALAR', 'SELECT protect FROM nickalias WHERE alias=?'],
469 get_pass
=> ['SCALAR', "SELECT nickreg.pass
470 FROM nickreg JOIN nickalias ON (nickreg.id=nickalias.nrid)
471 WHERE nickalias.alias=?"],
472 get_email
=> ['SCALAR', "SELECT nickreg.email
473 FROM nickalias JOIN nickreg ON (nickreg.id=nickalias.nrid)
474 WHERE nickalias.alias=?"],
475 count_silences
=> ['SCALAR', "SELECT COUNT(silence.nrid) FROM silence
476 JOIN nickalias ON (silence.nrid=nickalias.nrid)
477 WHERE nickalias.alias=?"],
478 count_watches
=> ['SCALAR', "SELECT COUNT(watch.nrid) FROM watch
479 JOIN nickalias ON (watch.nrid=nickalias.nrid)
480 WHERE nickalias.alias=?"],
482 add_autojoin_ntf
=> ['INSERT', "INSERT INTO nicktext
483 SELECT nickreg.id, @{[NTF_JOIN]}, 0, ?, NULL
484 FROM nickreg JOIN nickalias ON (nickreg.id=nickalias.nrid)
485 WHERE nickalias.alias=?"],
486 get_autojoin_ntf
=> ['COLUMN', "SELECT chan
488 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
489 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=?"],
490 wipe_autojoin_ntf
=> ['NULL', "DELETE nicktext.* FROM nickreg
491 JOIN nickalias ON (nickalias.nrid=nickreg.id)
492 JOIN nicktext ON (nicktext.nrid=nickreg.id)
493 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=?"],
494 del_autojoin_ntf
=> ['NULL', "DELETE nicktext.* FROM nickreg
495 JOIN nickalias ON (nickalias.nrid=nickreg.id)
496 JOIN nicktext ON (nicktext.nrid=nickreg.id)
497 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=? AND nicktext.chan=?"],
498 check_autojoin_ntf
=> ['SCALAR', "SELECT 1 FROM nicktext
499 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
500 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=? AND nicktext.chan=?"],
501 get_autojoin_by_num
=> ['SCALAR', "SELECT nicktext.chan
503 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
504 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=? LIMIT 1 OFFSET ?"],
508 ### NICKSERV COMMANDS ###
510 sub ns_ajoin_list
($$) {
511 my ($user, $nick) = @_;
514 foreach my $chan (get_autojoin_ntf
($nick)) {
515 push @data, [++$i, $chan];
518 notice
( $user, columnar
( {TITLE
=> "Channels in \002$nick\002's ajoin",
519 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data ) );
521 sub ns_ajoin_del
($$@) {
522 my ($user, $nick, @args) = @_;
524 if(lc(get_user_nick
($user)) eq lc($nick)) {
528 $subj="\002$nick\002\'s";
529 $obj="\002$nick\002";
532 foreach my $arg (@args) {
533 if ($arg =~ /^[0-9\.,-]+$/) {
534 foreach my $num (makeSeqList
($arg)) {
535 if(my $chan = get_autojoin_by_num
($nick, $num - 1)) {
536 push @entries, $chan;
538 notice
($user, "No entry \002#$num\002 was found in $subj ajoin list");
541 } elsif($arg =~ /^#.*?,#/) {
542 push @entries, split(',', $arg);
547 foreach my $entry (@entries) {
548 if(check_autojoin_ntf
($nick, $entry)) {
549 del_autojoin_ntf
($nick, $entry);
550 notice
($user,"Successfully removed \002$entry\002 from $subj ajoin list.");
553 notice
($user, "\002$entry\002 was not in $subj ajoin!");
557 sub ns_ajoin_wipe
($$) {
558 my ($user, $nick) = @_;
560 if(lc(get_user_nick
($user)) eq lc($nick)) {
564 $subj="\002$nick\002\'s";
565 $obj="\002$nick\002";
567 my $count = wipe_autojoin_ntf
($nick);
569 notice
($user,"Successfully wiped \002$count\002 entries from $subj ajoin list.");
571 notice
($user,"No entries deleted.");
575 sub ns_ajoin_join
($$) {
576 my ($user, $nick) = @_;
577 #ns_ajoin_list($user, $nick);
578 do_ajoin
($user, $nick);
582 my ($user, @args) = @_;
584 my $src = get_user_nick
($user);
585 my @chans = grep(/^(#|\d)/, @args);
586 my @parms = grep(!/^(#|\d)/, @args);
587 if(scalar(@parms) > 1) {
588 $nick = shift @parms;
592 my $cmd = shift @parms;
594 if(lc($src) eq lc($nick)) {
598 $subj="\002$nick\002\'s";
599 $obj="\002$nick\002";
602 my $override = adminserv
::can_do
($user, 'SERVOP');
603 if(is_identified
($user, $nick) || $override) {
604 if(!is_registered
($src)) {
605 notice
($user, "\002$nick\002 is not registered.");
609 notice
($user, "Permission denied for \002$nick\002");
612 if ($cmd =~ /^add$/i) {
613 if(!scalar(@chans)) {
614 notice
($user, "Syntax: \002AJOIN ADD #channel\002");
615 notice
($user, "Type \002/msg NickServ HELP AJOIN\002 for more help");
617 foreach my $chanlist (@chans) {
618 if (defined($chanlist) && $chanlist !~ /^#/) {
619 $chanlist = "#" . $chanlist;
621 foreach my $chan (split(',', $chanlist)) {
622 if(check_autojoin_ntf
($nick, $chan)) {
623 notice
($user, $chan . " is already in $subj ajoin list! ");
626 add_autojoin_ntf
($chan, $nick);
627 notice
($user, "\002$chan\002 added to $subj ajoin.");
632 elsif ($cmd =~ /^list$/i) {
633 ns_ajoin_list
($user, $nick);
635 elsif ($cmd =~ /^join$/i) {
636 ns_ajoin_join
($user, $nick);
638 elsif ($cmd =~ /^del(ete)?$/i) {
639 ns_ajoin_del
($user, $nick, @chans);
641 elsif ($cmd =~ /^(clear|wipe)$/i) {
642 ns_ajoin_wipe
($user, $nick);
645 notice
($user,"Syntax: AJOIN ADD/DEL/LIST/WIPE");
646 notice
($user,"Type \002/msg NickServ HELP AJOIN\002 for more help!");
650 our %high_priority_cmds = (
660 $nsuser = { NICK
=> $nsnick, ID
=> ircd
::getAgentUuid
($nsnick) };
661 my ($user, $dstUser, $msg) = @_;
662 return unless (lc $dstUser->{NICK
} eq lc $nsnick);
664 my @args = split(/\s+/, $msg);
665 my $cmd = shift @args;
667 my $src = $user->{NICK
};
668 $user->{AGENT
} = $nsuser;
669 return if flood_check
($user);
670 if(!defined($high_priority_cmds{lc $cmd}) &&
671 !adminserv
::is_svsop
($user) &&
672 $SrSv::IRCd
::State
::queue_depth
> main_conf_highqueue
)
674 notice
($user, get_user_agent
($user)." is too busy right now. Please try your command again later.");
678 if($cmd =~ /^help$/i) {
679 sendhelp
($user, 'nickserv', @args)
681 elsif ($cmd =~ /^ajoin$/i) {
682 ns_ajoin
($user, shift @args, @args);
684 elsif($cmd =~ /^id(entify)?$/i) {
686 ns_identify
($user, $src, $args[0]);
687 } elsif(@args == 2) {
688 ns_identify
($user, $args[0], $args[1]);
690 notice
($user, 'Syntax: IDENTIFY [nick] <password>');
693 elsif($cmd =~ /^sid(entify)?$/i) {
695 ns_identify
($user, $args[0], $args[1], 1);
697 notice
($user, 'Syntax: SIDENTIFY <nick> <password>');
700 elsif($cmd =~ /^gid(entify)?$/i) {
702 ns_identify
($user, $args[0], $args[1], 2);
704 notice
($user, 'Syntax: GIDENTIFY <nick> <password>');
707 elsif($cmd =~ /^logout$/i) {
710 elsif($cmd =~ /^release$/i) {
712 ns_release
($user, $args[0]);
713 } elsif(@args == 2) {
714 ns_release
($user, $args[0], $args[1]);
716 notice
($user, 'Syntax: RELEASE <nick> [password]');
719 elsif($cmd =~ /^ghost$/i) {
721 ns_ghost
($user, $args[0]);
722 } elsif(@args == 2) {
723 ns_ghost
($user, $args[0], $args[1]);
725 notice
($user, 'Syntax: GHOST <nick> [password]');
728 elsif($cmd =~ /^register$/i) {
730 ns_register
($user, $args[0], $args[1]);
732 notice
($user, 'Syntax: REGISTER <password> <email>');
735 elsif($cmd =~ /^(?:link|group)$/i) {
737 ns_link
($user, $args[0], $args[1]);
739 notice
($user, 'Syntax: LINK <nick> <password>');
742 elsif($cmd =~ /^info$/i) {
744 ns_info
($user, @args);
746 notice
($user, 'Syntax: INFO <nick> [nick ...]');
749 elsif($cmd =~ /^set$/i) {
750 ns_set_parse
($user, @args);
752 elsif($cmd =~ /^(drop|unlink)$/i) {
754 ns_unlink
($user, $src, $args[0]);
757 ns_unlink
($user, $args[0], $args[1]);
760 notice
($user, 'Syntax: UNLINK [nick] <password>');
763 elsif($cmd =~ /^dropgroup$/i) {
765 ns_dropgroup
($user, $src, $args[0]);
768 ns_dropgroup
($user, $args[0], $args[1]);
771 notice
($user, 'Syntax: DROPGROUP [nick] <password>');
774 elsif($cmd =~ /^chgroot$/i) {
776 ns_changeroot
($user, $src, $args[0]);
779 ns_changeroot
($user, $args[0], $args[1]);
782 notice
($user, 'Syntax: CHGROOT [oldroot] <newroot>');
785 elsif($cmd =~ /^sendpass$/i) {
787 ns_sendpass
($user, $args[0]);
789 notice
($user, 'Syntax: SENDPASS <nick>');
792 elsif($cmd =~ /^(?:glist|links)$/i) {
794 ns_glist
($user, $src);
797 ns_glist
($user, @args);
800 notice
($user, 'Syntax: GLIST [nick] [nick ...]');
803 elsif($cmd =~ /^(?:alist|listchans)$/i) {
805 ns_alist
($user, $src);
808 ns_alist
($user, @args);
811 notice
($user, 'Syntax: ALIST [nick] [nick ...]');
814 elsif($cmd =~ /^list$/i) {
816 ns_list
($user, $args[0]);
818 notice
($user, 'Syntax: LIST <mask>');
821 elsif($cmd =~ /^watch$/i) {
822 if ($args[0] =~ /^(add|del|list)$/i) {
823 ns_watch
($user, $src, @args);
825 elsif ($args[1] =~ /^(add|del|list)$/i) {
826 ns_watch
($user, @args);
829 notice
($user, 'Syntax: WATCH <ADD|DEL|LIST> [nick]');
832 elsif($cmd =~ /^silence$/i) {
833 if ($args[0] =~ /^(add|del|list)$/i) {
834 ns_silence
($user, $src, @args);
836 elsif ($args[1] =~ /^(add|del|list)$/i) {
837 ns_silence
($user, @args);
840 notice
($user, 'Syntax: SILENCE [nick] <ADD|DEL|LIST> [mask] [+expiry] [comment]');
843 elsif($cmd =~ /^(acc(ess)?|stat(us)?)$/i) {
845 ns_acc
($user, @args);
848 notice
($user, 'Syntax: ACC <nick> [nick ...]');
851 elsif($cmd =~ /^seen$/i) {
853 ns_seen
($user, @args);
856 notice
($user, 'Syntax: SEEN <nick> [nick ...]');
859 elsif($cmd =~ /^recover$/i) {
861 ns_recover
($user, $args[0]);
862 } elsif(@args == 2) {
863 ns_recover
($user, $args[0], $args[1]);
865 notice
($user, 'Syntax: RECOVER <nick> [password]');
868 elsif($cmd =~ /^auth$/i) {
870 ns_auth
($user, @args);
873 notice
($user, 'Syntax: AUTH [nick] <LIST|ACCEPT|DECLINE> [num|chan]');
876 elsif($cmd =~ /^(?:emailreg|(?:auth|email)code)$/i) {
877 if(scalar(@args) >= 2 and scalar(@args) <= 3) {
878 ns_authcode
($user, @args);
880 notice
($user, 'Syntax: AUTHCODE <nick> <code> [newpassword]');
883 elsif($cmd =~ /^profile$/i) {
884 ns_profile
($user, @args);
886 elsif($cmd =~ /^liste?mail/i) {
888 ns_listemail
($user, $args[0]);
890 notice
($user, 'Syntax: LISTEMAIL <email@domain.tld>');
894 notice
($user, "Unrecognized command.", "For help, type: \002/msg nickserv help\002");
895 wlog
($nsnick, LOG_DEBUG
(), "$src tried to use NickServ $msg");
899 sub ns_identify
($$$;$) {
900 my ($user, $nick, $pass, $svsnick) = @_;
901 my $src = get_user_nick
($user);
903 my $root = get_root_nick
($nick);
905 notice
($user, 'Your nick is not registered.');
910 if(lc($src) ne lc($nick) and is_online
($nick)) {
912 ns_ghost
($user, $nick, $pass) or return;
914 notice
($user, $nick.' is already in use. Please use GHOST, GIDENTIFY or RECOVER');
918 if (is_identified
($user, $nick)) {
919 if(lc $src eq lc $nick) {
920 notice
($user, "Cannot only change case of nick");
923 ircd
::svsnick
($nsuser, $user, $nick);
924 ircd
::setumode
($nsuser, $user, '+r');
928 # cannot be an else, note change of $svsnick above.
929 if (!$svsnick and is_identified
($user, $nick)) {
930 notice
($user, 'You are already identified for nick '.$nick.'.');
934 my $flags = nr_get_flags
($root);
936 if($flags & NRF_FREEZE
) {
937 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
938 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to identify to frozen nick \003\002$nick\002", $user);
942 if($flags & NRF_EMAILREG
) {
943 notice
($user, "This nick is awaiting an email validation code. Please check your email for instructions.");
947 elsif($flags & NRF_SENDPASS
) {
948 notice
($user, "This nick is awaiting a SENDPASS authentication code. Please check your email for instructions.");
952 my $uid = get_user_id
($user);
953 unless(chk_pass
($root, $pass, $user)) {
954 if(inc_nick_inval
($user)) {
955 notice
($user, $err_pass);
957 services
::ulog
($nsnick, LOG_INFO
(), "failed to identify to nick $nick (root: $root)", $user);
961 return do_identify
($user, $nick, $root, $flags, $svsnick);
966 my $uid = get_user_id
($user);
968 $update_lastseen->execute($uid);
969 $logout->execute($uid);
970 delete($user->{NICKFLAGS
});
971 ircd
::nolag
($nsnick, '-', $user);
972 notice
($user, 'You are now logged out');
973 services
::ulog
($nsnick, LOG_INFO
(), "used NickServ LOGOUT", $user);
976 sub ns_release
($$;$) {
977 my ($user, $nick, $pass) = @_;
979 if(nr_chk_flag
($nick, NRF_FREEZE
)) {
980 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
981 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to release frozen nick \003\002$nick\002", $user);
985 unless(is_identified
($user, $nick)) {
987 my $s = ns_identify
($user, $nick, $pass);
988 return if($s == 0); #failed to identify
990 notice
($user, "Nick $nick is not being held.");
994 notice
($user, $err_deny);
998 elsif(enforcer_quit
($nick)) {
999 notice
($user, 'Your nick has been released from custody.');
1001 notice
($user, "Nick $nick is not being held.");
1005 sub ns_ghost
($$;$) {
1007 my @ghostbusters_quotes = (
1008 'Ray. If someone asks if you are a god, you say, "yes!"',
1009 'I feel like the floor of a taxicab.',
1010 'I don\'t have to take this abuse from you, I\'ve got hundreds of people dying to abuse me.',
1012 'This chick is *toast*.',
1013 '"Where do these stairs go?" "They go up."',
1014 '"That\'s the bedroom, but nothing ever happened in there." "What a crime."',
1015 'NOBODY steps on a church in my town.',
1016 'Whoa, whoa, whoa! Nice shootin\', Tex!',
1017 'It\'s the Stay Puft Marshmallow Man.',
1018 '"Symmetrical book stacking. Just like the Philadelphia mass turbulence of 1947." "You\'re right, no human being would stack books like this."',
1019 '"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."',
1020 '"Ray has gone bye-bye, Egon... what\'ve you got left?" "Sorry, Venkman, I\'m terrified beyond the capacity for rational thought."',
1021 'Listen! Do you smell something?',
1022 '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?',
1023 '"You know, you don\'t act like a scientist." "They\'re usually pretty stiff." "You\'re more like a game show host."',
1025 my ($user, $nick, $pass) = @_;
1026 my $src = get_user_nick
($user);
1028 if(nr_chk_flag
($nick, NRF_FREEZE
)) {
1029 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
1030 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to ghost frozen nick \003\002$nick\002", $user);
1034 unless(is_identified
($user, $nick)) {
1036 my $s = ns_identify
($user, $nick, $pass);
1037 return 0 if($s == 0); #failed to identify
1039 notice
($user, $err_deny);
1044 if(!is_online
($nick)) {
1045 notice
($user, "\002$nick\002 is not online");
1047 } elsif(lc $src eq lc $nick) {
1048 notice
($user, "I'm sorry, $src, I'm afraid I can't do that.");
1052 my $ghostbusters = @ghostbusters_quotes[int rand(scalar(@ghostbusters_quotes))];
1053 my $baduser = {NICK
=> $nick};
1054 get_user_id
($baduser);
1055 ircd
::irckill
($nsuser, $baduser, "GHOST command used by $src ($ghostbusters)");
1056 notice
($user, "Your ghost has been disconnected");
1057 services
::ulog
($nsnick, LOG_INFO
(), "used NickServ GHOST on $nick", $user);
1058 #nick_delete($nick);
1063 sub ns_register
($$$) {
1064 my ($user, $pass, $email) = @_;
1065 my $src = get_user_nick
($user);
1067 if($src =~ /^guest/i) {
1068 notice
($user, $err_deny);
1072 unless(validate_email
($email)) {
1073 notice
($user, $err_email);
1077 if ($pass =~ /pass/i) {
1078 notice
($user, 'Try a more secure password.');
1082 my $uid = get_user_id
($user);
1084 $get_register_lock->execute; $get_register_lock->finish;
1086 if(not is_registered
($src)) {
1087 $register->execute($src, hash_pass
($pass), $email); $register->finish();
1088 $create_alias->execute($src, $src); $create_alias->finish;
1089 if (defined(services_conf_default_protect
)) {
1090 $set_protect_level->execute((defined(services_conf_default_protect
) ?
1091 $protect_level{lc services_conf_default_protect
} : 1), $src);
1092 $set_protect_level->finish();
1094 $unlock_tables->execute; $unlock_tables->finish;
1096 if(services_conf_validate_email
) {
1097 nr_set_flag
($src, NRF_EMAILREG
());
1098 authcode
($src, 'emailreg', $email);
1099 notice
($user, "Your registration is not yet complete.",
1100 "Your nick will expire within ".
1101 (services_conf_validate_expire
== 1 ? '24 hours' : services_conf_validate_expire
.' days').
1102 " if you do not enter the validation code.",
1103 "Check your email for further instructions.");
1106 $identify->execute($uid, $src); $identify->finish();
1107 notice
($user, 'You are now registered and identified.');
1108 ircd
::setumode
($nsuser, $user, '+r');
1111 $id_update->execute($src, $uid); $id_update->finish();
1112 services
::ulog
($nsuser, LOG_INFO
(), "registered $src (email: $email)".
1113 (services_conf_validate_email
? ' requires email validation code' : ''),
1116 $unlock_tables->execute; $unlock_tables->finish;
1117 notice
($user, 'Your nickname has already been registered.');
1122 my ($user, $nick, $pass) = @_;
1124 my $root = get_root_nick
($nick);
1125 my $src = get_user_nick
($user);
1126 my $uid = get_user_id
($user);
1128 if($src =~ /^guest/i) {
1129 notice
($user, $err_deny);
1133 unless (is_registered
($nick)) {
1134 if(is_registered
($src)) {
1135 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.");
1136 } else { # if neither $nick nor $src are registered
1137 notice
($user, "You need to register your nick first. For help, type \002/ns help register");
1142 unless(chk_pass
($root, $pass, $user)) {
1143 notice
($user, $err_pass);
1147 if(nr_chk_flag
($nick, NRF_FREEZE
) and (lc $pass ne 'force')) {
1148 notice
($user, "\002$root\002 has been frozen and may not be used.");
1152 if(is_alias_of
($src, $nick)) {
1153 notice
($user, "\002$nick\002 is already linked to \002$src\002.");
1157 $get_register_lock->execute; $get_register_lock->finish;
1159 if(is_registered
($src)) {
1160 $unlock_tables->execute; $unlock_tables->finish;
1162 if(is_identified
($user, $src)) {
1163 notice
($user, "You cannot link an already registered nick. Type this and try again: \002/ns drop $src <password>");
1166 notice
($user, 'Your nickname has already been registered.');
1170 $create_alias->execute($src, $root); $create_alias->finish();
1171 if (defined(services_conf_default_protect
)) {
1172 $set_protect_level->execute((defined(services_conf_default_protect
) ?
1173 $protect_level{lc services_conf_default_protect
} : 1), $src);
1174 $set_protect_level->finish();
1176 $unlock_tables->execute; $unlock_tables->finish;
1178 if(is_identified
($user, $root)) {
1179 $identify_ign->execute($uid, $root); $identify_ign->finish();
1180 $id_update->execute($root, $uid); $id_update->finish();
1182 ns_identify
($user, $root, $pass);
1186 notice
($user, "\002$src\002 is now linked to \002$root\002.");
1187 services
::ulog
($nsnick, LOG_INFO
(), "made $src an alias of $root.", $user);
1189 check_identify
($user);
1192 sub ns_unlink
($$$) {
1193 my ($user, $nick, $pass) = @_;
1194 my $uid = get_user_id
($user);
1195 my $src = get_user_nick
($user);
1197 my $root = get_root_nick
($nick);
1198 unless(chk_pass
($root, $pass, $user)) {
1199 notice
($user, $err_pass);
1203 if(nr_chk_flag
($nick, NRF_FREEZE
) and (lc $pass ne 'force')) {
1204 notice
($user, "\002$root\002 has been frozen and may not be used.", $err_deny);
1205 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to unlink \002$nick\002 from frozen nick \002$root\002", $user);
1209 if(lc $root eq lc $nick) {
1210 $count_aliases->execute($root);
1211 my ($count) = $count_aliases->fetchrow_array;
1213 ns_dropgroup_real
($user, $root);
1217 $get_random_alias->execute($root);
1218 my ($new) = $get_random_alias->fetchrow_array;
1219 ns_changeroot
($user, $root, $new, 1);
1224 unidentify_single
($nick);
1225 delete_alias
($nick);
1226 enforcer_quit
($nick);
1228 notice
($user, "\002$nick\002 has been unlinked from \002$root\002.");
1229 services
::ulog
($nsnick, LOG_INFO
(), "removed alias $nick from $root.", $user);
1232 sub ns_dropgroup
($$$) {
1233 my ($user, $nick, $pass) = @_;
1234 my $uid = get_user_id
($user);
1235 my $src = get_user_nick
($user);
1236 my $root = get_root_nick
($nick);
1238 if(adminserv
::get_svs_level
($root)) {
1239 notice
($user, "A nick with services access may not be dropped.");
1243 unless(chk_pass
($root, $pass, $user)) {
1244 notice
($user, $err_pass);
1248 if(nr_chk_flag
($nick, NRF_FREEZE
) and (lc $pass ne 'force')) {
1249 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
1250 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to dropgroup frozen nick \002$root\002", $user);
1254 ns_dropgroup_real
($user, $root);
1257 sub ns_dropgroup_real
($$) {
1258 my ($user, $root) = @_;
1259 my $src = get_user_nick
($user);
1261 unidentify
($root, "Your nick, \002$root\002, was dropped by \002$src\002.", $src);
1263 #enforcer_quit($nick);
1264 notice
($user, "Your nick(s) have been dropped. Thanks for playing.");
1266 services
::ulog
($nsnick, LOG_INFO
(), "dropped group $root.", $user);
1269 sub ns_changeroot
($$$;$) {
1270 my ($user, $old, $new, $force) = @_;
1272 $force or chk_identified
($user, $old) or return;
1274 my $root = get_root_nick
($old);
1276 if(lc($new) eq lc($root)) {
1277 notice
($user, "\002$root\002 is already your root nick.");
1281 unless(get_root_nick
($new) eq $root) {
1282 notice
($user, "\002$new\002 is not an alias of your nick. Type \002/msg nickserv help link\002 for information about creating aliases.");
1286 changeroot
($root, $new);
1288 notice
($user, "Your root nick is now \002$new\002.");
1289 services
::ulog
($nsnick, LOG_INFO
(), "changed root $root to $new.", $user);
1293 my ($user, @nicks) = @_;
1295 foreach my $nick (@nicks) {
1296 my $root = get_root_nick
($nick);
1298 $get_info->execute($nick);
1299 my @result = $get_info->fetchrow_array;
1300 $get_info->finish();
1303 notice
($user, "The nick \002$nick\002 is not registered.");
1307 my ($email, $regd, $last, $flags, $ident, $vhost, $gecos, $alias_used) = @result;
1308 # the quit entry might not exist if the user hasn't quit yet.
1309 $get_nickreg_quit->execute($nick);
1310 my ($quit) = $get_nickreg_quit->fetchrow_array(); $get_nickreg_quit->finish();
1311 my $hidemail = $flags & NRF_HIDEMAIL
;
1313 $get_greet_nick->execute($nick);
1314 my ($greet) = $get_greet_nick->fetchrow_array(); $get_greet_nick->finish();
1315 $get_umode_ntf->execute($nick);
1316 my ($umode) = $get_umode_ntf->fetchrow_array(); $get_umode_ntf->finish();
1318 my $svslev = adminserv
::get_svs_level
($root);
1319 my $protect = protect_level
($nick);
1320 my $showprivate = (is_identified
($user, $nick) or
1321 adminserv
::is_svsop
($user, adminserv
::S_HELP
()));
1323 my ($seens, $seenm) = do_seen
($nick);
1327 push @data, {FULLROW
=>"(Online now, $seenm.)"} if $seens == 2;
1328 push @data, ["Last seen:", "$seenm."] if $seens == 1;
1331 ["Last seen address:", "$ident\@$vhost"],
1332 ["Registered:", gmtime2
($regd)];
1333 push @data, ["Last used:", ($alias_used ? gmtime2
($alias_used) : 'Unknown')] if $showprivate;
1334 push @data, ["Last real name:", $gecos];
1336 push @data, ["Services Rank:", $adminserv::levels
[$svslev]]
1338 push @data, ["E-mail:", $email] unless $hidemail;
1339 push @data, ["E-mail:", "$email (Hidden)"]
1340 if($hidemail and $showprivate);
1341 push @data, ["Alias of:", $root]
1342 if ((lc $root ne lc $nick) and $showprivate);
1346 push @extra, "Last quit: $quit" if $quit;
1347 push @extra, $protect_long[$protect] if $protect;
1348 push @extra, "Does not accept memos." if($flags & NRF_NOMEMO
);
1349 push @extra, "Cannot be added to channel access lists." if($flags & NRF_NOACC
);
1350 push @extra, "Will not be automatically opped in channels." if($flags & NRF_NEVEROP
);
1351 push @extra, "Requires authorization to be added to channel access lists."
1352 if($flags & NRF_AUTH
);
1353 push @extra, "Is frozen and may not be used." if($flags & NRF_FREEZE
);
1354 push @extra, "Will not expire." if($flags & NRF_HOLD
);
1355 push @extra, "Is currently on vacation." if($flags & NRF_VACATION
);
1356 push @extra, "Registration pending email-code verification." if($flags & NRF_EMAILREG
);
1357 push @extra, "UModes on Identify: ".$umode if ($umode and $showprivate);
1358 push @extra, "Greeting: ".$greet if ($greet and $showprivate);
1359 push @extra, "Disabled highlighting of alternating lines." if ($flags & NRF_NOHIGHLIGHT
);
1361 notice
($user, columnar
({TITLE
=> "NickServ info for \002$nick\002:",
1362 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)},
1363 @data, {COLLAPSE
=> \
@extra, BULLET
=> 1}));
1367 sub ns_set_parse
($@) {
1368 my ($user, @parms) = @_;
1369 my $src = get_user_nick
($user);
1370 # This is a new NS SET parser
1371 # required due to it's annoying syntax
1373 # Most commands have only 2 params at most
1374 # the target (which is implied to be src when not spec'd)
1375 # However in the case of GREET num-params is unbounded
1377 # Alternative parsings would be possible,
1378 # one being to use a regexp for valid set/keys
1379 if (lc($parms[1]) eq 'greet') {
1380 ns_set
($user, @parms);
1382 elsif(lc($parms[0]) eq 'greet') {
1383 ns_set
($user, $src, @parms);
1387 ns_set
($user, $src, $parms[0], $parms[1]);
1389 elsif(@parms == 3) {
1390 ns_set
($user, $parms[0], $parms[1], $parms[2]);
1393 notice
($user, 'Syntax: SET [nick] <option> <value>');
1400 my ($user, $target, $set, @parms) = @_;
1401 my $src = get_user_nick
($user);
1402 my $override = (adminserv
::can_do
($user, 'SERVOP') or
1403 (adminserv
::can_do
($user, 'FREEZE') and $set =~ /^freeze$/i) ? 1 : 0);
1405 unless(is_registered
($target)) {
1406 notice
($user, "\002$target\002 is not registered.");
1409 unless(is_identified
($user, $target) or $override) {
1410 notice
($user, $err_deny);
1415 $set =~ /^protect$/i or
1416 $set =~ /^e?-?mail$/i or
1417 $set =~ /^pass(?:w(?:or)?d)?$/i or
1418 $set =~ /^hidee?-?mail$/i or
1419 $set =~ /^nomemo$/i or
1420 $set =~ /^no(?:acc|op)$/i or
1421 $set =~ /^neverop$/i or
1422 $set =~ /^auth$/i or
1423 $set =~ /^(hold|no-?expire)$/i or
1424 $set =~ /^freeze$/i or
1425 $set =~ /^vacation$/i or
1426 $set =~ /^greet$/i or
1427 $set =~ /^u?modes?$/i or
1428 $set =~ /^(email)?reg$/i or
1429 $set =~ /^nohighlight$/i or
1430 $set =~ /^(?:(?:chg)?root|display)$/i
1432 notice
($user, qq{"$set" is not a valid NickServ setting.});
1437 if($src eq $target) {
1441 $subj="\002$target\002\'s";
1442 $obj="\002$target\002";
1444 delete($user->{NICKFLAGS
});
1446 if($set =~ /^protect$/i) {
1447 my $level = $protect_level{lc shift @parms};
1448 unless (defined($level)) {
1449 notice
($user, "Syntax: SET PROTECT <none|normal|high|kill>");
1453 $set_protect_level->execute($level, $target);
1454 notice
($user, "$subj protection level is now set to \002".$protect_short[$level]."\002. ".$protect_long[$level]);
1459 elsif($set =~ /^e?-?mail$/i) {
1460 unless(@parms == 1) {
1461 notice
($user, 'Syntax: SET EMAIL <address>');
1464 my $email = $parms[0];
1466 unless(validate_email
($email)) {
1467 notice
($user, $err_email);
1471 $set_email->execute($email, $target);
1472 notice
($user, "$subj email address has been changed to \002$email\002.");
1473 services
::ulog
($nsnick, LOG_INFO
(), "changed email of \002$target\002 to $email", $user);
1478 elsif($set =~ /^pass(?:w(?:or)?d)?$/i) {
1479 unless(@parms == 1) {
1480 notice
($user, 'Syntax: SET PASSWD <address>');
1483 if($parms[0] =~ /pass/i) {
1484 notice
($user, 'Try a more secure password.');
1487 $set_pass->execute(hash_pass
($parms[0]), $target);
1488 notice
($user, "$subj password has been changed.");
1489 services
::ulog
($nsnick, LOG_INFO
(), "changed password of \002$target\002", $user);
1490 if(nr_chk_flag
($target, NRF_SENDPASS
())) {
1491 $del_nicktext->execute(NTF_AUTHCODE
, $target); $del_nicktext->finish();
1492 nr_set_flag
($target, NRF_SENDPASS
(), 0);
1498 elsif($set =~ /^greet$/i) {
1500 notice
($user, 'Syntax: SET [nick] GREET <NONE|greeting>');
1504 my $greet = join(' ', @parms);
1505 if ($greet =~ /^(none|off)$/i) {
1506 $del_greet->execute($target);
1507 notice
($user, "$subj greet has been deleted.");
1508 services
::ulog
($nsnick, LOG_INFO
(), "deleted greet of \002$target\002", $user);
1511 $set_greet->execute($greet, $target);
1512 notice
($user, "$subj greet has been set to \002$greet\002");
1513 services
::ulog
($nsnick, LOG_INFO
(), "changed greet of \002$target\002", $user);
1518 elsif($set =~ /^u?modes?$/i) {
1519 unless(@parms == 1) {
1520 notice
($user, 'Syntax: SET UMODE <+modes-modes|none>');
1524 if (lc $parms[0] eq 'none') {
1525 $del_nicktext->execute(NTF_UMODE
, $target); $del_nicktext->finish();
1526 notice
($user, "$obj will not receive any automatic umodes.");
1529 my ($modes, $rejected) = modes
::allowed_umodes
($parms[0]);
1530 $del_nicktext->execute(NTF_UMODE
, $target); $del_nicktext->finish(); # don't allow dups
1531 $set_umode_ntf->execute($modes, $target); $set_umode_ntf->finish();
1532 foreach my $usernick (get_nick_user_nicks
$target) {
1533 ircd
::setumode
($nsuser, $user, $modes)
1537 push @out, "Cannot set these umodes: " . $rejected if $rejected;
1538 push @out, "$subj automatic umodes have been set to: \002" . ($modes ? $modes : 'none');
1539 notice
($user, @out);
1543 elsif($set =~ /^(?:(?:chg)?root|display)$/i) {
1544 ns_changeroot
($user, $target, $parms[0], $override);
1549 if($parms[0] =~ /^(?:no|off|false|0)$/i) { $val = 0; }
1550 elsif($parms[0] =~ /^(?:yes|on|true|1)$/i) { $val = 1; }
1552 notice
($user, "Please say \002on\002 or \002off\002.");
1556 if($set =~ /^hidee?-?mail$/i) {
1557 nr_set_flag
($target, NRF_HIDEMAIL
, $val);
1560 notice
($user, "$subj email address is now hidden.");
1562 notice
($user, "$subj email address is now visible.");
1568 if($set =~ /^nomemo$/i) {
1569 nr_set_flag
($target, NRF_NOMEMO
, $val);
1572 notice
($user, "$subj memos will be blocked.");
1574 notice
($user, "$subj memos will be delivered.");
1580 if($set =~ /^no(?:acc|op)$/i) {
1581 nr_set_flag
($target, NRF_NOACC
, $val);
1584 notice
($user, "$obj may not be added to channel access lists.");
1586 notice
($user, "$obj may be added to channel access lists.");
1592 if($set =~ /^neverop$/i) {
1593 nr_set_flag
($target, NRF_NEVEROP
, $val);
1596 notice
($user, "$obj will not be granted status upon joining channels.");
1598 notice
($user, "$obj will be granted status upon joining channels.");
1604 if($set =~ /^auth$/i) {
1605 nr_set_flag
($target, NRF_AUTH
, $val);
1608 notice
($user, "$obj must now authorize additions to channel access lists.");
1610 notice
($user, "$obj will not be asked to authorize additions to channel access lists.");
1616 if($set =~ /^(hold|no-?expire)$/i) {
1617 unless (adminserv
::can_do
($user, 'SERVOP') or
1618 is_identified
($user, $target) and adminserv
::is_ircop
($user))
1620 notice
($user, $err_deny);
1624 nr_set_flag
($target, NRF_HOLD
, $val);
1627 notice
($user, "\002$target\002 is now held from expiration.");
1628 services
::ulog
($nsnick, LOG_INFO
(), "has held \002$target\002", $user);
1630 notice
($user, "\002$target\002 will now expire normally.");
1631 services
::ulog
($nsnick, LOG_INFO
(), "released \002$target\002 from hold", $user);
1637 if($set =~ /^freeze$/i) {
1638 unless (adminserv
::can_do
($user, 'FREEZE') or
1639 is_identified
($user, $target) and adminserv
::is_ircop
($user))
1641 notice
($user, $err_deny);
1645 nr_set_flag
($target, NRF_FREEZE
, $val);
1648 notice
($user, "\002$target\002 is now frozen.");
1649 unidentify
($target, "Your nick, \002$target\002, has been frozen and may no longer be used.");
1650 services
::ulog
($nsnick, LOG_INFO
(), "froze \002$target\002", $user);
1652 notice
($user, "\002$target\002 is no longer frozen.");
1653 services
::ulog
($nsnick, LOG_INFO
(), "unfroze \002$target\002", $user);
1659 if($set =~ /^vacation$/i) {
1661 $get_regd_time->execute($target);
1662 my ($regd) = $get_regd_time->fetchrow_array;
1663 $get_regd_time->finish();
1665 if(($regd > (time() - 86400 * int(services_conf_vacationexpire
/ 3))) and !$override) {
1666 notice
($user, "$target is not old enough to use VACATION",
1667 'Minimum age is '.int(services_conf_vacationexpire
/ 3).' days');
1671 $get_vacation_ntf->execute($target);
1672 my ($last_vacation) = $get_vacation_ntf->fetchrow_array();
1673 $get_vacation_ntf->finish();
1674 if(defined($last_vacation)) {
1675 $last_vacation = unpack('N', MIME
::Base64
::decode
($last_vacation));
1676 if ($last_vacation > (time() - 86400 * int(services_conf_vacationexpire
/ 3)) and !$override) {
1677 notice
($user, "I'm sorry, \002$src\002, I'm afraid I can't do that.",
1678 "Last vacation ended ".gmtime2
($last_vacation),
1679 'Minimum time between vacations is '.int(services_conf_vacationexpire
/ 3).' days.');
1685 nr_set_flag
($target, NRF_VACATION
, $val);
1687 services
::ulog
($nsnick, LOG_INFO
(),
1688 ($val ? 'enabled' : 'disabled')." vacation mode for \002$target\002", $user);
1689 notice
($user, "Vacation mode ".($val ? 'enabled' : 'disabled')." for \002$target\002");
1693 if($set =~ /^(email)?reg$/i) {
1694 unless (adminserv
::can_do
($user, 'SERVOP'))
1696 notice
($user, $err_deny);
1700 nr_set_flag
($target, NRF_EMAILREG
, $val);
1703 authcode
($target, 'emailreg');
1704 notice
($user, "\002$target\002 now needs an email validation code.");
1705 unidentify
($target, ["Your nick, \002$target\002, has been flagged for an email validation audit.",
1706 "Your nick will expire within 24 hours if you do not enter the validation code.",
1707 "Check your email for further instructions."]);
1708 services
::ulog
($nsnick, LOG_INFO
(), "requested an email audit for \002$target\002", $user);
1710 $del_nicktext->execute(NTF_AUTHCODE
, $target); $del_nicktext->finish();
1711 notice
($user, "\002$target\002 is now fully registered.");
1712 services
::ulog
($nsnick, LOG_INFO
(), "validated the email for \002$target\002", $user);
1718 if($set =~ /^nohighlight$/i) {
1719 nr_set_flag
($target, NRF_NOHIGHLIGHT
, $val);
1722 notice
($user, "$obj will no longer have alternative highlighting of lists.");
1724 notice
($user, "$obj will have alternative highlighting of lists.");
1732 sub ns_sendpass
($$) {
1733 my ($user, $nick) = @_;
1735 unless(adminserv
::is_svsop
($user, adminserv
::S_HELP
() )) {
1736 notice
($user, $err_deny);
1740 my $email = get_email
($nick);
1743 notice
($user, "\002$nick\002 is not registered or does not have an email address.");
1747 my $pass = get_pass
($nick);
1748 if ($pass and !is_hashed
($pass)) {
1749 send_email
($email, "$nsnick Password Reminder",
1750 "The password for the nick $nick is:\n$pass");
1751 notice
($user, "Password for \002$nick\002 has been sent to \002$email\002.");
1753 authcode
($nick, 'sendpass', $email);
1754 nr_set_flag
($nick, NRF_SENDPASS
);
1755 notice
($user, "Password authentication code for \002$nick\002 has been sent to \002$email\002.");
1758 services
::ulog
($nsnick, LOG_INFO
(), "used SENDPASS on $nick ($email)", $user);
1762 my ($user, @targets) = @_;
1764 foreach my $target (@targets) {
1765 my $root = get_root_nick
($target);
1767 notice
$user, "\002$target\002 is not registered.";
1771 unless(is_identified
($user, $target) or
1772 adminserv
::is_svsop
($user, adminserv
::S_HELP
())
1774 notice
$user, "$target: $err_deny";
1779 $get_glist->execute($root);
1780 while(my ($alias, $protect, $last) = $get_glist->fetchrow_array) {
1783 # This needs a new NS GLIST cmd, like NS GLISTA or something.
1784 # The idea is a command that shows the long version of the time_ago.
1785 $time_ago = time_ago
($last, 1);
1787 $time_ago = time_ago
($last);
1789 push @data, ["\002$alias\002", "Protect: $protect_short[$protect]",
1790 ($last ? "Last used $time_ago ago" : '')
1794 notice
$user, columnar
{TITLE
=> "Group list for \002$root\002 (" . $get_glist->rows . " nicks):",
1795 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
1797 $get_glist->finish();
1802 my ($user, @targets) = @_;
1804 foreach my $target (@targets) {
1805 (adminserv
::is_svsop
($user, adminserv
::S_HELP
()) and (
1806 chk_registered
($user, $target) or next)
1807 ) or chk_identified
($user, $target) or next;
1811 $get_all_access->execute($target);
1812 while(my ($c, $l, $a, $t) = $get_all_access->fetchrow_array) {
1814 push @data, [$c, $chanserv::plevels
[$l+$chanserv::plzero
], ($a ? "($a)" : ''),
1818 notice
$user, columnar
{TITLE
=> "Access listing for \002$target\002 (".scalar(@data)." entries)",
1819 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
1824 my ($user, $mask) = @_;
1826 unless(adminserv
::is_svsop
($user, adminserv
::S_HELP
())) {
1827 notice
($user, $err_deny);
1831 my ($mnick, $mident, $mhost) = glob2sql
(parse_mask
($mask));
1833 $mnick = '%' if($mnick eq '');
1834 $mident = '%' if($mident eq '');
1835 $mhost = '%' if($mhost eq '');
1838 $get_matching_nicks->execute($mnick, $mident, $mhost);
1839 while(my ($rnick, $rroot, $rident, $rhost) = $get_matching_nicks->fetchrow_array) {
1840 push @data, [$rnick, ($rroot ne $rnick ? $rroot : ''), $rident . '@' . $rhost];
1843 notice
$user, columnar
{TITLE
=> "Registered nicks matching \002$mask\002:",
1844 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
1847 sub ns_watch
($$$;$) {
1848 my ($user, $target, $cmd, $mask) = @_;
1849 my $src = get_user_nick
($user);
1851 my $root = get_root_nick
($target);
1853 notice
($user, "\002$target\002 is not registered.");
1856 unless(is_identified
($user, $target)) {
1857 notice
($user, $err_deny);
1861 if ($cmd =~ /^add$/i) {
1862 my $max_watches = $IRCd_capabilities{WATCH
}; # load here for caching.
1863 if ($max_watches eq "") {
1864 notice
($user, "The IRCd is not configured to support WATCH. Please contact your friendly network administrators.");
1867 if(count_watches
($root) >= $max_watches) {
1868 notice
($user, "WATCH list for $target full, there is a limit of $max_watches. Please trim your list.");
1872 if($mask =~ /\!/ or $mask =~ /\@/) {
1873 my ($mnick, $mident, $mhost) = parse_mask
($mask);
1874 if ($mnick =~ /\*/) {
1875 notice
($user, "Invalid mask: \002$mask\002",
1876 'A WATCH mask cannot wildcard the nick.');
1881 $check_watch->execute($root, $mask);
1882 if ($check_watch->fetchrow_array) {
1883 notice
($user, "\002$mask\002 is already in \002$target\002's watch list.");
1887 $set_watch->execute($mask, time(), $root);
1888 ircd
::svswatch
($nsuser, $user, "+$mask");
1889 notice
($user, "\002$mask\002 added to \002$target\002's watch list.");
1892 elsif ($cmd =~ /^del(ete)?$/i) {
1893 $check_watch->execute($root, $mask);
1894 if ($IRCd_capabilities{WATCH
} eq "") {
1895 notice
($user, "The IRCd is not configured to support WATCH. Please contact your friendly network administrators.");
1898 unless ($check_watch->fetchrow_array) {
1899 notice
($user, "\002$mask\002 is not in \002$target\002's watch list.");
1902 $del_watch->execute($root, $mask);
1903 ircd
::svswatch
($nsuser, $user, "-$mask");
1904 notice
($user, "\002$mask\002 removed from \002$target\002's watch list.");
1906 elsif ($cmd =~ /^list$/i) {
1909 $get_watches->execute($root);
1910 while(my ($mask, $time) = $get_watches->fetchrow_array) {
1911 push @data, [$mask, gmtime2
($time)];
1914 notice
$user, columnar
{TITLE
=> "Watch list for \002$target\002:",
1915 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
1918 notice
($user, 'Syntax: WATCH <ADD|DEL|LIST> [nick]');
1922 sub ns_silence
($$$;$@) {
1923 my ($user, $target, $cmd, $mask, @args) = @_;
1924 my ($expiry, $comment);
1925 my $src = get_user_nick
($user);
1927 if(lc(get_user_nick
($user)) eq lc($target)) {
1931 $subj="\002$target\002\'s";
1932 $obj="\002$target\002";
1935 sub get_silence_by_num
($$) {
1936 # This one cannot be converted to SrSv::MySQL::Stub, due to bind_param call
1937 my ($nick, $num) = @_;
1938 $get_silence_by_num->execute($nick, $num-1);
1939 my ($mask) = $get_silence_by_num->fetchrow_array();
1940 $get_silence_by_num->finish();
1944 my $root = get_root_nick
($target);
1946 if(!defined($root)) {
1947 #notice($user, "\002$target\002 is not registered.");
1954 if($isRegistered && !is_identified
($user, $target)) {
1955 notice
($user, $err_deny);
1959 if ($cmd =~ /^add$/i) {
1960 my $max_silences = $IRCd_capabilities{SILENCE
};
1961 if ($max_silences eq "") {
1962 notice
($user, "The IRCd is not configured to support SILENCE. Please contact your friendly network administrators.");
1965 if(count_silences
($root) >= $max_silences) {
1966 notice
($user, "SILENCE list for $target full, there is a limit of $max_silences. Please trim your list.");
1970 if (substr($args[0],0,1) eq '+') {
1971 $expiry = shift @args;
1973 elsif (substr($args[-1],0,1) eq '+') {
1974 $expiry = pop @args;
1976 $comment = join(' ', @args);
1978 if($mask !~ /[!@.]/) {
1979 my $target_user = { NICK
=> $mask };
1980 unless(get_user_id
($target_user)) {
1981 notice
($user, qq{"\002$mask\002" is not a known user, nor a valid hostmask.});
1984 $comment = $mask unless $comment;
1986 my ($ident, $vhost) = get_vhost
($target_user);
1987 my ($nick, $ident, $vhost) = make_hostmask
(10, $mask, $ident, $vhost);
1988 $mask = $nick.'!'.$ident.'@'.$vhost;
1991 $mask = normalize_hostmask
($mask);
1995 if("$nsnick!services\@".main_conf_local
=~ hostmask_to_regexp
($mask)) {
1996 notice
($user, "You shouldn't add NickServ to your SILENCE list.");
2001 if(defined $expiry) {
2002 $expiry = parse_time
($expiry) + time();
2008 $check_silence->execute($root, $mask);
2009 if ($check_silence->fetchrow_array) {
2010 notice
($user, "\002$mask\002 is already in $subj SILENCE list.");
2014 $set_silence->execute($mask, time(), $expiry, $comment, $root);
2016 ircd
::svssilence
($nsuser, $user, "+$mask");
2017 notice
($user, "\002$mask\002 added to $subj SILENCE list.");
2019 elsif ($cmd =~ /^del(ete)?$/i) {
2021 if ($mask =~ /^[0-9\.,-]+$/) {
2022 foreach my $num (makeSeqList
($mask)) {
2023 push @masks, get_silence_by_num
($root, $num) or next;
2025 if(scalar(@masks) == 0) {
2026 notice
($user, "Unable to find any silences matching $mask");
2032 my @reply; my @out_masks;
2033 foreach my $mask (@masks) {
2034 $check_silence->execute($root, $mask);
2035 unless ($check_silence->fetchrow_array) {
2036 $mask = normalize_hostmask
($mask);
2038 $check_silence->execute($root, $mask);
2039 unless ($check_silence->fetchrow_array) {
2040 push @reply, "\002$mask\002 is not in $subj SILENCE list.";
2044 $del_silence->execute($root, $mask);
2045 push @out_masks, "-$mask";
2046 push @reply, "\002$mask\002 removed from $subj SILENCE list.";
2048 ircd
::svssilence
($nsuser, $user, @out_masks);
2049 notice
($user, @reply);
2051 elsif ($cmd =~ /^list$/i) {
2052 $get_silences->execute($root);
2054 my @reply; my $i = 1;
2055 while(my ($mask, $time, $expiry, $comment) = $get_silences->fetchrow_array) {
2056 push @reply, "$i \002[\002 $mask \002]\002 Date added: ".gmtime2
($time),
2057 ' '.($comment ? "\002[\002 $comment \002]\002 " : '').
2058 ($expiry ? 'Expires in '.time_rel
($expiry-time
()) :
2059 "\002[\002 Never expires \002]\002");
2063 notice
($user, "SILENCE list for $obj:", (scalar @reply ? @reply : " list empty"));
2066 notice
($user, 'Syntax: SILENCE [nick] <ADD|DEL|LIST> [mask] [+expiry] [comment]');
2072 my ($user, @targets) = @_;
2075 foreach my $target (@targets) {
2076 unless(is_registered
($target)) {
2077 push @reply, "ACC 0 \002$target\002 is not registered.";
2081 unless(is_online
($target)) {
2082 push @reply, "ACC 1 \002$target\002 is registered and offline.";
2086 unless(is_identified
({NICK
=> $target}, $target)) {
2087 push @reply, "ACC 2 \002$target\002 is online but not identified.";
2091 push @reply, "ACC 3 \002$target\002 is registered and identified.";
2093 notice
($user, @reply);
2097 my ($user, @nicks) = @_;
2099 foreach my $nick (@nicks) {
2100 if(lc $nick eq lc (($user->{AGENT
})->{NICK
})) {
2101 notice
($user, "Oh, a wise guy, eh?");
2104 my ($status, $msg) = do_seen
($nick);
2106 notice
($user, "\002$nick\002 is online now, ".$msg.'.');
2107 } elsif($status == 1) {
2108 notice
($user, "\002$nick\002 was last seen ".$msg.'.');
2110 notice
($user, "The nick \002$nick\002 is not registered.");
2115 sub ns_recover
($$;$) {
2116 my ($user, $nick, $pass) = @_;
2117 my $src = get_user_nick
($user);
2119 if(nr_chk_flag
($nick, NRF_FREEZE
)) {
2120 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
2121 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to recover frozen nick \003\002$nick\002", $user);
2125 unless(is_identified
($user, $nick)) {
2127 my $s = ns_identify
($user, $nick, $pass);
2128 return if($s == 0); #failed to identify
2130 notice
($user, $err_deny);
2135 if(!is_online
($nick)) {
2136 notice
($user, "\002$nick\002 is not online");
2138 } elsif(lc $src eq lc $nick) {
2139 notice
($user, "I'm sorry, $src, I'm afraid I can't do that.");
2144 notice
($user, "User claiming your nick has been collided",
2145 "/msg NickServ RELEASE $nick to get it back before the one-minute timeout.");
2146 services
::ulog
($nsnick, LOG_INFO
(), "used NickServ RECOVER on $nick", $user);
2152 my ($user, @args) = @_;
2155 #These helpers shouldn't be needed anywhere else.
2156 # If they ever are, move them to the helpers section
2157 sub get_auth_num
($$) {
2158 # this cannot be converted to SrSv::MySQL::Stub, due to bind_param
2159 my ($nick, $num) = @_;
2160 $get_auth_num->execute($nick, $num - 1);
2161 my ($cn, $data) = $get_auth_num->fetchrow_array();
2162 $get_auth_num->finish();
2163 return ($data ? ($cn, split(/:/, $data)) : undef);
2165 sub get_auth_chan
($$) {
2166 my ($nick, $cn) = @_;
2167 $get_auth_chan->execute($nick, $cn);
2168 my ($data) = $get_auth_chan->fetchrow_array();
2169 $get_auth_chan->finish();
2170 return (split(/:/, $data));
2173 if ($args[0] =~ /^(list|accept|approve|decline|reject)$/i) {
2174 $target = get_user_nick
($user);
2175 $cmd = lc shift @args;
2178 $target = shift @args;
2179 $cmd = lc shift @args;
2182 unless (is_registered
($target)) {
2183 notice
($user, "The nickname \002$target\002 is not registered");
2186 unless (is_identified
($user, $target)) {
2187 notice
($user, $err_deny);
2191 if ($cmd eq 'list') {
2193 $list_auth->execute($target);
2194 while (my ($cn, $data) = $list_auth->fetchrow_array()) {
2195 my ($adder, $old, $level, $time) = split(':', $data);
2196 push @data, [$cn, $chanserv::levels
[$level], $adder, gmtime2
($time)];
2198 if ($list_auth->rows()) {
2199 notice
$user, columnar
{TITLE
=> "Pending authorizations for \002$target\002:",
2200 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
2203 notice
($user, "There are no pending authorizations for \002$target\002");
2206 elsif ($cmd eq 'accept' or $cmd eq 'approve') {
2207 my $parm = shift @args;
2208 my ($cn, $adder, $old, $level, $time);
2209 if(misc
::isint
($parm) and
2210 ($cn, $adder, $old, $level, $time) = get_auth_num
($target, $parm))
2213 elsif ($parm =~ /^\#/ and
2214 ($adder, $old, $level, $time) = get_auth_chan
($target, $parm))
2219 # This should normally be an 'else' as the elsif above should prove false
2220 # For some reason, it doesn't work. the unless ($cn) fixes it.
2221 # It only doesn't work for numbered entries
2222 notice
($user, "There is no entry for \002$parm\002 in \002$target\002's AUTH list");
2225 my $chan = { CHAN
=> $cn };
2226 my $root = get_root_nick
($target);
2228 # These next 3 lines should use chanserv::set_acc() but it doesn't seem to work.
2229 # It won't let me use a $nick instead of $user
2230 $chanserv::set_acc1-
>execute($cn, $level, $root);
2231 $chanserv::set_acc2-
>execute($level, $adder, $cn, $root);
2232 chanserv
::set_modes_allnick
($root, $chan, $level) unless chanserv
::is_neverop
($root);
2234 my $log_str = ($old?'move':'addition')." \002$root\002"
2235 . ($old ? ' from the '.$chanserv::levels
[$old] : '') .
2236 ' to the '.$chanserv::levels
[$level]." list of \002$cn\002";
2237 services
::ulog
($chanserv::csnick
, LOG_INFO
(), "accepted the $log_str from $adder", $user, $chan);
2238 notice
($user, "You have accepted the $log_str");
2239 $del_auth->execute($target, $cn);
2240 $del_auth->finish();
2241 memoserv
::send_memo
($chanserv::csnick
, $adder, "$target accepted the $log_str");
2243 elsif ($cmd eq 'decline' or $cmd eq 'reject') {
2244 my $parm = shift @args;
2245 my ($cn, $adder, $old, $level, $time);
2246 if(misc
::isint
($parm) and
2247 ($cn, $adder, $old, $level, $time) = get_auth_num
($target, $parm))
2250 elsif ($parm =~ /^\#/ and
2251 ($adder, $old, $level, $time) = get_auth_chan
($target, $parm))
2256 # This should normally be an 'else' as the elsif above should prove false
2257 # For some reason, it doesn't work. the unless ($cn) fixes it.
2258 # It only doesn't work for numbered entries
2259 notice
($user, "There is no entry for \002$parm\002 in \002$target\002's AUTH list");
2262 my $chan = { CHAN
=> $cn };
2264 my $root = get_root_nick
($target);
2265 my $log_str = ($old?'move':'addition')." \002$root\002"
2266 . ($old ? ' from the '.$chanserv::plevels
[$old+$chanserv::plzero
] : '') .
2267 ' to the '.$chanserv::plevels
[$level+$chanserv::plzero
]." list of \002$cn\002";
2268 services
::ulog
($chanserv::csnick
, LOG_INFO
(), "declined the $log_str from $adder", $user, $chan);
2269 notice
($user, "You have declined $log_str");
2270 $del_auth->execute($target, $cn);
2271 $del_auth->finish();
2272 memoserv
::send_memo
($chanserv::csnick
, $adder, "$target declined the $log_str");
2274 #elsif ($cmd eq 'read') {
2277 notice
($user, "Unknown AUTH cmd");
2281 sub ns_authcode
($$$;$) {
2282 my ($user, $target, $code, $pass) = @_;
2284 if ($pass and $pass =~ /pass/i) {
2285 notice
($user, 'Try a more secure password.');
2289 unless(is_registered
($target)) {
2290 notice
($user, "\002$target\002 isn't registered.");
2294 if(authcode
($target, undef, $code)) {
2295 notice
($user, "\002$target\002 authenticated.");
2296 services
::ulog
($nsnick, LOG_INFO
(), "logged in to \002$target\002 using an authcode", $user);
2298 do_identify
($user, $target, $target);
2300 ns_set
($user, $target, 'PASSWD', $pass)
2301 } elsif(nr_chk_flag
($target, NRF_SENDPASS
())) {
2302 notice
($user, "YOU MUST CHANGE YOUR PASSWORD NOW", "/NS SET $target PASSWD <newpassword>");
2306 notice
($user, "\002$target\002 authentication failed. Please verify that you typed or pasted the code correctly.");
2310 sub ns_profile
($@) {
2311 my ($user, $first, @args) = @_;
2313 my %profile_dispatch = (
2314 'read' => \
&ns_profile_read
,
2315 'info' => \
&ns_profile_read
,
2317 'del' => \
&ns_profile_del
,
2318 'delete' => \
&ns_profile_del
,
2320 'set' => \
&ns_profile_update
,
2321 'update' => \
&ns_profile_update
,
2322 'add' => \
&ns_profile_update
,
2324 'wipe' => \
&ns_profile_wipe
,
2328 if(my $sub = $profile_dispatch{$args[0]}) {
2329 # Second command with nick
2331 $sub->($user, $first, @args);
2333 elsif(my $sub = $profile_dispatch{$first}) {
2334 # Second command without nick
2335 $sub->($user, get_user_nick
($user), @args);
2339 ns_profile_read
($user, ($first || get_user_nick
($user)));
2343 "Syntax: PROFILE [nick] [SET|DEL|READ|WIPE ...]",
2344 "For help, type: \002/ns help profile\002";
2348 sub ns_profile_read
($$@) {
2349 my ($user, $target, @args) = @_;
2351 foreach my $nick ((scalar(@args) ? @args : $target)) {
2352 next unless chk_registered
($user, $nick);
2353 my @profile_entries = get_profile_ntf
($nick);
2354 if(scalar(@profile_entries)) {
2355 notice
$user, columnar
({TITLE
=> "Profile information for \002$nick\002:",
2356 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)},
2357 map( ["$_->[0]:", $_->[1]], @profile_entries )
2361 notice
$user, "\002$nick\002 has not created a profile.";
2366 sub ns_profile_update
($$@) {
2367 my ($user, $target, @args) = @_;
2369 return unless chk_registered
($user, $target);
2371 unless(is_identified
($user, $target) or
2372 adminserv
::is_svsop
($user, adminserv
::S_HELP
())
2374 notice
($user, "$target: $err_deny");
2378 my ($key, $data) = (shift @args, join(' ', @args));
2380 unless ($key and $data) {
2381 notice
$user, "Syntax: PROFILE [nick] SET <item> <text>",
2382 "For help, type: \002/ns help profile\002";
2386 if(count_profile_ntf
($target) >= MAX_PROFILE
) {
2387 notice
($user, "You may not have more than ".MAX_PROFILE
." profile items.");
2390 elsif (length($key) > 32) {
2391 notice
($user, "Item name may not be longer than 32 characters.");
2394 elsif (length($data) > MAX_PROFILE_LEN
) {
2395 my $over = length($data) - MAX_PROFILE_LEN
;
2396 notice
($user, "Your entry is $over characters too long. (".MAX_PROFILE_LEN
." max.)");
2399 add_profile_ntf
($key, $data, $target);
2400 notice
($user, "\002$target\002's \002$key\002 is now \002$data\002");
2403 sub ns_profile_del
($$@) {
2404 my ($user, $target, @args) = @_;
2406 return unless chk_registered
($user, $target);
2408 unless(is_identified
($user, $target) or
2409 adminserv
::is_svsop
($user, adminserv
::S_HELP
())
2411 notice
($user, "$target: $err_deny");
2415 my $key = shift @args;
2418 notice
$user, "Syntax: PROFILE [nick] DEL <item>",
2419 "For help, type: \002/ns help profile\002";
2423 if(del_profile_ntf
($target, $key) == 0) {
2424 notice
($user, "There is no profile item \002$key\002 for \002$target\002");
2426 notice
($user, "Profile item \002$key\002 for \002$target\002 deleted.");
2430 sub ns_profile_wipe
($$@) {
2431 my ($user, $target, undef) = @_;
2433 unless (is_registered
($target)) {
2434 notice
($user, "$target is not registered.");
2437 unless(is_identified
($user, $target) or
2438 adminserv
::is_svsop
($user, adminserv
::S_HELP
())
2440 notice
($user, "$target: $err_deny");
2444 wipe_profile_ntf
($target);
2445 notice
($user, "Profile for \002$target\002 wiped.");
2448 sub ns_listemail
($$) {
2449 my ($user, $email) = @_;
2450 unless(adminserv
::is_svsop
($user, adminserv
::S_HELP
())) {
2451 notice
($user, $err_deny);
2454 my $likeemail = glob2sql
($email);
2455 my (@found, $count);
2457 $get_nicks_by_email->execute($likeemail);
2458 while (my ($nick, $ident, $host) = $get_nicks_by_email->fetchrow_array) {
2459 push @found, " $nick ($ident\@$host)";
2461 $email =~ s/\%/\*/g;
2463 notice
($user, "Nicks matching an email address consisting of \002$email\002");
2468 notice
($user, "Found \002$count\002 matching nicks.");
2470 notice
($user, "There were no nicknames registered with an email address consisting of \002$email\002");
2480 $get_seen->execute($nick);
2481 if (my ($alias, $root, $lastseen) = $get_seen->fetchrow_array) {
2482 if(my @usernicks = get_nick_user_nicks
($nick)) {
2484 $msg = "using ".(@usernicks==1 ? 'the nick ' : 'the following nicks: ').join(', ', map "\002$_\002", @usernicks);
2488 $msg = time_ago
($lastseen) . " ago (".gmtime2
($lastseen).")";
2492 $status = 0; $msg = undef();
2495 return ($status, $msg);
2498 # For a whole group:
2499 sub unidentify
($$;$) {
2500 my ($nick, $msg, $src) = @_;
2502 $nick = get_root_nick
($nick);
2504 foreach my $t (get_nick_user_nicks
$nick) {
2505 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2506 get_user_id
($user);
2507 ircd
::notice
($nsuser, $user, (ref $msg ? @$msg : $msg)) unless(lc $t eq lc $src);
2508 if(is_alias_of
($nick, $t)) {
2509 ircd
::setumode
($nsuser, $user, '-r');
2513 $unidentify->execute($nick);
2516 # For a single alias:
2517 sub unidentify_single
($$) {
2518 my ($nick, $msg) = @_;
2519 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2520 get_user_id
($user);
2521 if(is_online
($nick)) {
2522 ircd
::setumode
($nsuser, $user, '-r');
2526 sub kill_clones
($$) {
2527 my ($user, $ip) = @_;
2528 my $uid = get_user_id
($user);
2529 my $src = get_user_nick
($user);
2531 return 0 if $ip == 0;
2533 $chk_clone_except->execute($uid);
2534 my ($lim) = $chk_clone_except->fetchrow_array;
2535 return 0 if $lim == MAX_LIM
();
2536 $lim = services_conf_clone_limit
unless $lim;
2538 $count_clones->execute($ip);
2539 my ($c) = $count_clones->fetchrow_array;
2542 ircd
::irckill
($nsuser, $user, "Session Limit Exceeded");
2548 my ($user, $nick) = @_;
2549 my $src = get_user_nick
($user);
2550 if(my @chans = get_autojoin_ntf
($nick)) {
2551 chanserv
::cs_join
($user, @chans);
2555 sub do_identify
($$$;$$) {
2556 my ($user, $nick, $root, $flags, $svsnick) = @_;
2557 my $uid = get_user_id
($user);
2558 my $src = get_user_nick
($user);
2559 $identify_ign->execute($uid, $root);
2560 $id_update->execute($root, $uid);
2562 notice
($user, 'You are now identified.');
2564 delete($user->{NICKFLAGS
});
2565 if($flags & NRF_VACATION
) {
2566 notice
($user, "Welcome back from your vacation, \002$nick\002.");
2567 my $ts = MIME
::Base64
::encode
(pack('N', time()));
2569 $del_nicktext->execute(NTF_VACATION
, $root); $del_nicktext->finish(); #don't allow dups
2570 $set_vacation_ntf->execute($ts, $root);
2571 $set_vacation_ntf->finish();
2574 $get_umode_ntf->execute($nick);
2575 my ($umodes) = $get_umode_ntf->fetchrow_array();
2576 $get_umode_ntf->finish();
2577 if(adminserv
::get_svs_level
($root)) {
2578 $umodes = modes
::merge_umodes
('+h', $umodes);
2579 ircd
::nolag
($nsuser, '+', $user);
2581 $umodes = modes
::merge_umodes
('+r', $umodes) if(is_identified
($user, $src));
2583 hostserv
::hs_on
($user, $root, 1);
2585 if(my @chans = get_autojoin_ntf
($nick)) {
2586 ircd
::svsjoin
($nsuser, $user, @chans);
2590 if(enforcer_quit
($nick)) {
2591 notice
($user, 'Your nick has been released from custody.');
2595 if (lc($src) eq lc($nick)) {
2596 ircd
::setumode
($nsuser, $user, $umodes);
2597 $update_nickalias_last->execute($nick); $update_nickalias_last->finish();
2600 ircd
::svsnick
($nsuser, $user, $nick);
2601 ircd
::setumode
($nsuser, $user, modes
::merge_umodes
('+r', $umodes) );
2602 # the update _should_ be taken care of in nick_change()
2603 #$update_nickalias_last->execute($nick); $update_nickalias_last->finish();
2605 elsif(defined $umodes) {
2606 ircd
::setumode
($nsuser, $user, $umodes);
2609 do_ajoin
($user, $nick);
2611 nickserv
::do_svssilence
($user, $root);
2612 nickserv
::do_svswatch
($user, $root);
2614 chanserv
::akick_alluser
($user);
2615 chanserv
::set_modes_allchan
($user, $flags & NRF_NEVEROP
);
2616 chanserv
::fix_private_join_before_id
($user);
2618 services
::ulog
($nsnick, LOG_INFO
(), "identified to nick $nick (root: $root)", $user);
2620 memoserv
::notify
($user, $root);
2621 notify_auths
($user, $root) if $flags & NRF_AUTH
;
2622 return ($enforced ? 2 : 1);
2625 sub authcode
($;$$) {
2626 my ($nick, $type, $email) = @_;
2628 unless (defined($email)) {
2629 $email = get_email
($nick);
2632 my $authcode = misc
::gen_uuid
(4, 5);
2633 $set_authcode_ntf->execute($authcode, $nick); $set_authcode_ntf->finish();
2634 send_email
($email, "Nick Authentication Code for $nick",
2637 "You are receiving this message from the automated nickname\n".
2638 "management system of the ".$IRCd_capabilities{NETWORK
}." network.\n\n".
2639 (lc($type) eq 'emailreg' ?
2640 "If you did not try to register your nickname with us, you can\n".
2641 "ignore this message. If you continue getting similar e-mails\n".
2642 "from us, chances are that someone is intentionally abusing your\n".
2643 "e-mail address. Please contact an administrator for help.\n".
2645 "In order to complete your registration, you must follow the\n".
2646 "instructions in this e-mail before ".gmtime2
(time+86400)."\n".
2648 "To complete the registration, the next time you connect, issue the\n".
2649 "following command to NickServ:\n\n".
2651 "After you issue the command, your registration will be complete and\n".
2652 "you will be able to use your nickname.\n\n"
2655 (lc($type) eq 'sendpass' ?
2656 "You requested a password authentication code for the nickname '$nick'\n".
2657 "on the ".$IRCd_capabilities{'NETWORK'}." IRC Network.\n".
2658 "As per our password policies, an authcode has been created for\n".
2659 "you and e-mailed to the address you set in NickServ.\n".
2660 "To complete the process, you need to return to ".$IRCd_capabilities{'NETWORK'}.",\n".
2661 "and execute the following command: \n\n"
2664 "/NS EMAILCODE $nick $authcode\n\n".
2666 (lc($type) eq 'sendpass' ?
2667 "YOU MUST CHANGE YOUR PASSWORD AT THIS POINT.\n".
2668 "You can do so via the following command: \n\n".
2669 "/NS SET $nick PASSWD newpassword\n\n".
2670 "alternately, try this command: \n\n".
2672 "/NS EMAILCODE $nick $authcode <password>\n\n"
2676 "If you feel you have gotten this e-mail in error, please contact\n".
2677 "an administrator.\n\n".
2680 "If this e-mail came to you unsolicited and appears to be spam -\n".
2681 "please e-mail ".main_conf_replyto
." with a copy of this e-mail\n".
2682 "including all headers.\n\n".
2687 $get_authcode_ntf->execute($nick, $email);
2688 my ($passed) = $get_authcode_ntf->fetchrow_array();
2689 $get_authcode_ntf->finish();
2691 nr_set_flag
($nick, NRF_EMAILREG
(), 0);
2692 unless(nr_chk_flag
($nick, NRF_SENDPASS
)) {
2693 $del_nicktext->execute(NTF_AUTHCODE
, $nick); $del_nicktext->finish();
2703 # This is mostly for logging, be careful using it for anything else
2704 sub get_hostmask
($) {
2707 my $src = get_user_nick
($user);
2709 ($ident, $host) = get_host
($user);
2711 return "$src!$ident\@$host";
2716 $set_guest->execute(1, $nick);
2717 my $randnick = 'Guest'.int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10));
2718 #Prevent collisions.
2719 while (is_online
($randnick)) {
2720 $randnick = 'Guest'.int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10));
2722 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2723 get_user_id
($user);
2724 ircd
::svsnick
($nsuser, $user, $randnick);
2730 return if services_conf_noexpire
;
2733 my ($ne, $e, $ve, $eve) = (services_conf_nearexpire
, services_conf_nickexpire
, services_conf_vacationexpire
,
2734 services_conf_validate_expire
);
2737 $get_expired->execute(time() - (86400 * services_conf_nickexpire
),
2738 time() - (86400 * services_conf_vacationexpire
),
2739 time() - (86400 * services_conf_validate_expire
));
2740 while(my ($nick, $email, $ident, $vhost) = $get_expired->fetchrow_array) {
2742 wlog
($nsnick, LOG_INFO
(), "$nick has expired. Email: $email Vhost: $ident\@$vhost");
2747 return unless services_conf_nearexpire
; # if nearexpire is zero, don't.
2748 $get_near_expired->execute(
2749 $time - (86400 * (services_conf_nickexpire
- services_conf_nearexpire
)),
2750 $time - (86400 * (services_conf_vacationexpire
- services_conf_nearexpire
))
2752 while(my ($nick, $email, $flags, $last) = $get_near_expired->fetchrow_array) {
2753 my $expire_days = services_conf_nearexpire
;
2754 if ( ( $flags & NRF_VACATION
) and ( $last < time() - (86400 * services_conf_vacationexpire
) )
2755 or (($last < time() - (86400 * services_conf_nickexpire
)) ) )
2758 } elsif ( ( $flags & NRF_VACATION
) and ( $last > time() - (86400 * services_conf_vacationexpire
) )
2759 or (($last > time() - (86400 * services_conf_nickexpire
)) ) )
2761 # this terrible invention is to determine how many days until their nick will expire.
2762 # this should almost always be ~7, unless something weird happens like
2763 # F_HOLD or svsop status is removed.
2764 # int truncates, so we add 0.5.
2765 $expire_days = -int(($time - ($last + (86400 *
2766 ( ( $flags & NRF_VACATION
) ? services_conf_vacationexpire
: services_conf_nickexpire
) )))
2769 if($expire_days >= 1) {
2771 $get_aliases->execute($nick);
2772 my $aliases = $get_aliases->fetchrow_arrayref();
2774 my $message = "We would like to remind you that your registered nick, $nick, will expire\n".
2775 "in approximately $expire_days days unless you sign on and identify.";
2776 if(scalar(@$aliases) > 1) {
2777 $message .= "\n\nThe following nicks are linked in this group:\n " . join("\n ", @$aliases);
2780 send_email
($email, "$nsnick Expiration Notice", $message);
2783 wlog
($nsnick, LOG_INFO
(), "$nick will expire ".($expire_days <= 0 ? "today" : "in $expire_days days.")." ($email)");
2784 $set_near_expired->execute($nick);
2788 sub expire_silence_timed
{
2790 $time = 60 unless $time;
2791 add_timer
('', $time, __PACKAGE__
, 'nickserv::expire_silence_timed');
2793 find_expired_silences
();
2796 # This code is a mess b/c we can only pull one entry at a time
2797 # and we want to batch the list to the user and to the ircd.
2798 # our SQL statement explicitly orders the silence entries by nickreg.nick
2799 sub find_expired_silences
() {
2800 $get_expired_silences->execute();
2801 my ($lastnick, @entries);
2802 while(my ($nick, $mask, $comment) = $get_expired_silences->fetchrow_array()) {
2803 if ($nick eq $lastnick) {
2805 do_expired_silences
($lastnick, \
@entries);
2809 push @entries, [$mask, $comment];
2812 do_expired_silences
($lastnick, \
@entries);
2814 $get_expired_silences->finish();
2815 $del_expired_silences->execute(); $del_expired_silences->finish();
2819 sub do_expired_silences
($$) {
2821 my (@entries) = @{$_[1]};
2823 foreach my $user (get_nick_users
$nick) {
2824 $user->{AGENT
} = $nsnick;
2825 get_user_id
($user);
2826 ircd
::svssilence
($nsuser, $user, map ( { '-'.$_->[0] } @entries) );
2827 #notice($user, "The following SILENCE entries have expired: ".
2828 # join(', ', map ( { $_->[0] } @entries) ));
2829 notice
($user, map( { "The following SILENCE entry has expired: \002".$_->[0]."\002 ".$_->[1] } @entries ) );
2832 sub do_svssilence
($$) {
2833 my ($user, $rootnick) = @_;
2834 if ($IRCd_capabilities{SILENCE
} eq "") {
2835 notice
($user, "The IRCd is not configured to support SILENCE. Please contact your friendly network administrators.");
2838 my $target = get_user_nick
($user);
2840 $get_silences->execute($rootnick);
2841 my $count = $get_silences->rows;
2842 unless ($get_silences->rows) {
2843 $get_silences->finish;
2847 for(my $i = 1; $i <= $count; $i++) {
2848 my ($mask, $time, $expiry) = $get_silences->fetchrow_array;
2849 push @silences, "+$mask";
2851 $get_silences->finish;
2852 ircd
::svssilence
($nsuser, $user, @silences);
2856 sub do_svswatch
($$) {
2857 my ($user, $rootnick) = @_;
2858 if ($IRCd_capabilities{WATCH
} eq "") {
2859 notice
($user, "The IRCd is not configured to support WATCH. Please contact your friendly network administrators.");
2862 my $target = get_user_nick
($user);
2864 $get_watches->execute($rootnick);
2865 my $count = $get_watches->rows;
2866 unless ($get_watches->rows) {
2867 $get_watches->finish;
2871 for(my $i = 1; $i <= $count; $i++) {
2872 my ($mask, $time, $expiry) = $get_watches->fetchrow_array;
2873 push @watches, "+$mask";
2875 $get_watches->finish;
2876 ircd
::svswatch
($nsuser, $user, @watches);
2881 my ($user, $rootnick) = @_;
2882 my $target = get_user_nick
($user);
2884 $get_umode_ntf->execute($rootnick);
2885 my ($umodes) = $get_umode_ntf->fetchrow_array; $get_umode_ntf->finish();
2887 ircd
::setumode
($nsuser, $user, $umodes) if $umodes;
2891 sub notify_auths
($$) {
2892 my ($user, $nick) = @_;
2893 $get_num_nicktext_type->execute($nick, NTF_AUTH
);
2894 my ($count) = $get_num_nicktext_type->fetchrow_array(); $get_num_nicktext_type->finish();
2895 notice
($user, "$nick has $count channel authorizations awaiting action.",
2896 "To list them, type /ns auth $nick list") if $count;
2899 ### PROTECTION AND ENFORCEMENT ###
2904 return if nr_chk_flag
($nick, NRF_EMAILREG
());
2905 my $lev = protect_level
($nick);
2906 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2907 get_user_id
($user);
2909 "This nickname is registered and protected. If it is your",
2910 "nick, type \002/msg NickServ IDENTIFY <password>\002. Otherwise,",
2911 "please choose a different nick."
2915 warn_countdown
("$nick 60");
2921 ircd
::svshold
($nick, 60, "If this is your nick, type /NS SIDENTIFY $nick \002password\002");
2922 kill_user
($user, "Unauthorized nick use with KILL protection enabled.");
2923 $enforcers{lc $nick} = 1;
2924 add_timer
($nick, 60, __PACKAGE__
, "nickserv::enforcer_delete");
2930 sub warn_countdown
($) {
2932 my ($nick, $rem) = split(/ /, $cookie);
2933 $nsuser = { NICK
=> $nsnick, ID
=> ircd
::getAgentUuid
($nsnick) };
2934 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2936 if (is_identified
($user, $nick)) {
2937 print "Line 2778\n";
2938 $update_nickalias_last->execute($nick); $update_nickalias_last->finish();
2941 elsif(!(is_online
($nick)) or !(is_registered
($nick))) { print "Line 2782\n"; return; }
2944 notice
($user, 'Your nick is now being changed.');
2948 "If you do not identify or change your nick in $rem seconds, your nick will be changed.");
2950 add_timer
("$nick $rem", 20, __PACKAGE__
, "nickserv::warn_countdown");
2956 my $newnick = guestnick
($nick);
2957 ircd
::svshold
($nick, 60, "If this is your nick, type /NS SIDENTIFY $nick \002password\002");
2958 $enforcers{lc $nick} = 1;
2959 add_timer
($nick, 60, __PACKAGE__
, "nickserv::enforcer_delete");
2963 sub enforcer_delete
($) {
2965 delete($enforcers{lc $nick});
2968 sub enforcer_quit
($) {
2970 if($enforcers{lc $nick}) {
2971 enforcer_delete
($nick);
2972 ircd
::svsunhold
($nick);
2978 ### DATABASE UTILITY FUNCTIONS ###
2986 if($cur_lock ne $nick) {
2987 really_release_lock
($nick);
2988 die("Tried to get two locks at the same time");
2993 $get_lock->execute(sql_conf_mysql_db
.".user.$nick");
2998 sub release_lock
($) {
3003 if($cur_lock and $cur_lock ne $nick) {
3004 really_release_lock
($cur_lock);
3006 die("Tried to release the wrong lock");
3012 really_release_lock
($nick);
3016 sub really_release_lock
($) {
3020 $release_lock->execute(sql_conf_mysql_db
.".user.$nick");
3021 $release_lock->finish;
3025 sub get_user_modes
($) {
3028 my $uid = get_user_id
($user);
3029 $get_umodes->execute($uid);
3030 my ($umodes) = $get_umodes->fetchrow_array;
3031 $get_umodes->finish();
3032 print "UMODES $umodes\n";
3037 my ($user, $vhost) = @_;
3038 my $id = get_user_id
($user);
3040 return $set_vhost->execute($vhost, $id);
3044 my ($user, $ident) = @_;
3045 my $id = get_user_id
($user);
3047 return $set_ident->execute($ident, $id);
3051 my ($user, $ip, $ipv6) = @_;
3052 my $id = get_user_id
($user);
3054 return $set_ip->execute($ip, $ipv6, $id);
3057 my ($user, $ip) = @_;
3058 my $id = get_user_id
($user);
3060 return $set_ip->execute($ip, undef, $id);
3063 sub get_root_nick
($) {
3066 $get_root_nick->execute($nick);
3067 my ($root) = $get_root_nick->fetchrow_array;
3072 sub get_id_nick
($) {
3075 $get_id_nick->execute($id);
3076 my ($root) = $get_id_nick->fetchrow_array;
3084 my $ret = $drop->execute($nick);
3089 sub changeroot
($$) {
3090 my ($old, $new) = @_;
3092 return if(lc $old eq lc $new);
3094 $change_root->execute($new, $old);
3100 $del_all_access->execute($root);
3101 $memoserv::delete_all_memos-
>execute($root);
3102 $memoserv::wipe_ignore-
>execute($root);
3103 $memoserv::purge_ignore-
>execute($root);
3104 chanserv
::drop_nick_chans
($root);
3105 hostserv
::del_vhost
($root);
3106 $drop_watch->execute($root);
3107 $drop_silence->execute($root);
3108 $drop_nicktext->execute($root);
3109 $delete_aliases->execute($root);
3110 $chanserv::drop_nick_akick-
>execute($root);
3117 return (get_root_nick
($nick) eq $nick);
3120 sub delete_alias
($) {
3122 return $delete_alias->execute($nick);
3125 sub delete_aliases
($) {
3127 return $delete_aliases->execute($root);
3130 sub get_all_access
($) {
3133 $get_all_access->execute($nick);
3134 return $get_all_access->fetchrow_array;
3137 sub del_all_access
($) {
3140 return $del_all_access->execute($root);
3144 my ($nick, $pass, $user) = @_;
3146 if(lc($pass) eq 'force' and adminserv
::can_do
($user, 'SERVOP')) {
3147 if(adminserv
::get_best_svs_level
($user) > adminserv
::get_svs_level
($nick)) {
3152 return validate_pass
(get_pass
($nick), $pass);
3155 sub inc_nick_inval
($) {
3157 my $id = get_user_id
($user);
3159 $inc_nick_inval->execute($id);
3160 $get_nick_inval->execute($id);
3161 my ($nick, $inval) = $get_nick_inval->fetchrow_array;
3163 ircd
::irckill
($nsuser, $user, 'Too many invalid passwords.');
3164 # unnecessary as irckill calls the quit handler.
3165 #nick_delete($nick);
3172 sub is_registered
($) {
3175 $is_registered->execute($nick);
3176 if($is_registered->fetchrow_array) {
3183 sub chk_registered
($;$) {
3184 my ($user, $nick) = @_;
3185 my $src = get_user_nick
($user);
3189 if(lc $src eq lc $nick) {
3190 $what = "Your nick";
3192 $what = "The nick \002$nick\002";
3195 $nick = get_user_nick
($user) unless $nick;
3196 $what = "Your nick";
3199 unless(is_registered
($nick)) {
3200 notice
($user, "$what is not registered.");
3207 sub is_alias_of
($$) {
3208 $is_alias_of->execute($_[0], $_[1]);
3209 return ($is_alias_of->fetchrow_array ? 1 : 0);
3212 sub check_identify
($) {
3214 my $nick = get_user_nick
($user);
3215 if(is_registered
($nick)) {
3216 if(is_identified
($user, $nick)) {
3217 ircd
::setumode
($nsuser, $user, '+r');
3218 $update_nickalias_last->execute($nick); $update_nickalias_last->finish();
3227 sub cleanup_users
() {
3228 add_timer
('', services_conf_old_user_age
, __PACKAGE__
, 'nickserv::cleanup_users');
3230 ircd
::privmsg
('ServServ', main_conf_diag
, "Starting cleanup_users()");
3233 my $time = (time() - (services_conf_old_user_age
* 2));
3235 $get_dead_users->execute($time);
3236 my $arrayRef = $get_dead_users->fetchall_arrayref();
3237 if($arrayRef && scalar(@$arrayRef)) {
3238 ircd
::privmsg
('ServServ', main_conf_diag
, columnar
( { BORDER
=> 1, NOHIGHLIGHT
=> 1 }, @$arrayRef ) );
3240 $get_dead_users->finish();
3242 my $rows = $cleanup_users->execute($time) + 0;
3243 $cleanup_nickid->execute();
3244 $cleanup_chanuser->execute();
3246 ircd
::privmsg
('ServServ', main_conf_diag
, "Deleted $rows dead users\n");
3247 ircd
::privmsg
('ServServ', main_conf_diag
, "Ending cleanup_users()");
3253 add_timer
('fix_vhosts', 5, __PACKAGE__
, 'nickserv::fix_vhosts');
3254 $get_hostless_nicks->execute();
3255 while (my ($nick) = $get_hostless_nicks->fetchrow_array) {
3256 ircd
::notice
($nsuser, main_conf_diag
, "HOSTLESS NICK $nick");
3257 ircd
::userhost
($nick);
3258 ircd
::userip
($nick);
3260 $get_hostless_nicks->finish();
3267 $get_user_id->execute($nick);
3268 if($id = $get_user_id->fetchrow_array) {
3269 $nick_id_delete->execute($id);
3270 $nick_delete->execute($nick);
3277 my ($user, $time, $ident, $host, $vhost, $server, $svsstamp, $modes, $gecos, $ip, $cloakhost) = @_;
3278 my $nick = get_user_nick
($user);
3280 if ($vhost eq '*') {
3281 if ({modes
::splitumodes
($modes)}->{x
} eq '+') {
3282 if(defined($cloakhost)) {
3283 $vhost = $cloakhost;
3285 else { # This should never happen with CLK or VHP
3286 ircd
::userhost
($nick);
3294 if ($id = get_user_id
( $user )) {
3295 #$id = decodeUUID ($id);
3296 $nick_checkExists->execute ($id, $time);
3297 my $exists = $nick_checkExists -> fetchrow_array
();
3298 my $flags = (synced
() ? UF_FINISHED
() : 0);
3299 unless (defined($exists)) {
3300 $nick_deleteChanUser -> execute
($id);
3301 $nick_deleteNickCh -> execute
($id);
3302 $nick_deleteNickId -> execute
($id);
3303 $id_delUser -> execute
($id);
3304 $nick_delUser -> execute
($nick);
3305 $nick_create2 -> execute
($id, $nick, $time, $ident, $host, $vhost, $server, $modes, $gecos, $flags, $cloakhost);
3308 $nick_create_old->execute ($nick, $ident, $host, $vhost, $server, $modes, $gecos, $flags, $cloakhost, $id);
3310 $add_nickchg->execute($ircline, $nick, $nick);
3311 release_lock
($nick);
3312 check_identify
($user);
3316 $get_user_nick->execute($svsstamp);
3317 my ($oldnick) = $get_user_nick->fetchrow_array();
3318 $id = $svsstamp if defined($oldnick);
3321 $nick_check->execute($nick, $time);
3322 ($id) = $nick_check->fetchrow_array;
3326 $olduser{lc $nick} = 1;
3327 $nick_create_old->execute($nick, $ident, $host, $vhost, $server, $modes, $gecos, UF_FINISHED
(), $cloakhost, $id);
3331 my $flags = (synced
() ? UF_FINISHED
() : 0);
3333 while($i < 10 and !$nick_create->execute($nick, $time, $ident, $host, $vhost, $server, $modes, $gecos, $flags, $cloakhost)) { $i++ }
3334 $id = get_user_id
( { NICK
=> $nick } ); # There needs to be a better way to do this
3336 ircd
::setsvsstamp
($nsuser, $user, $id) unless $svsstamp == $id;
3338 $add_nickchg->execute($ircline, $nick, $nick);
3340 release_lock
($nick);
3342 $newuser{lc $nick} = 1;
3345 nickserv
::userip
(undef, $nick, $ip);
3347 else { # This should never happen with NICKIP
3348 ircd
::userip
($nick);
3354 sub nick_create_post
($) {
3356 my $user = { NICK
=> $nick };
3357 my $old = $olduser{lc $nick};
3358 delete $olduser{lc $nick};
3360 operserv
::do_news
($nick, 'u') unless($old);
3364 check_identify
($user);
3366 release_lock
($nick);
3369 sub nick_delete
($$) {
3370 my ($user, $quit) = @_;
3371 my $nick = $user->{NICK
};
3373 my $id = get_user_id
($user);
3374 print "DELETE: $nick, $id\n";
3375 $del_nickchg_id->execute($id); $del_nickchg_id->finish();
3376 $quit_update->execute($quit, $id); $quit_update->finish();
3377 $update_lastseen->execute($id); $update_lastseen->finish();
3378 $get_quit_empty_chans->execute($id);
3379 $chan_user_partall->execute($id); $chan_user_partall->finish();
3380 #$nick_chan_delete->execute($id); $nick_chan_delete->finish();
3381 $nick_quit->execute($nick); $nick_quit->finish();
3382 release_lock
($nick);
3383 while(my ($cn) = $get_quit_empty_chans->fetchrow_array) {
3384 chanserv
::channel_emptied
({CHAN
=> $cn});
3386 $get_quit_empty_chans->finish();
3390 my (undef, $servers, $reason) = @_;
3392 $get_squit_lock->execute; $get_squit_lock->finish;
3394 foreach my $server (@$servers) {
3395 $get_squit_empty_chans->execute($server);
3397 $squit_nickreg->execute($server);
3398 $squit_nickreg->finish;
3400 $squit_lastquit->execute("Netsplit from $server", $server);
3401 $squit_lastquit->finish;
3403 $squit_users->execute($server);
3404 $squit_users->finish;
3406 while(my ($cn) = $get_squit_empty_chans->fetchrow_array) {
3407 chanserv
::channel_emptied
({CHAN
=> $cn});
3409 $get_squit_empty_chans->finish;
3412 $unlock_tables->execute; $unlock_tables->finish;
3415 sub nick_change
($$$) {
3416 my ($user, $new, $time) = @_;
3417 my $old = $user->{NICK
};
3418 return if(lc $old eq lc $new);
3419 print "NICK CHANGE: $old -> $new ($time)\n";
3422 $nick_change->execute($new, $old);
3423 $add_nickchg->execute($ircline, $new, $new);
3425 if($new =~ /^guest/i) {
3426 $get_guest->execute($new);
3427 my ($guest) = $get_guest->fetchrow_array();
3429 $set_guest->execute(0, $new);
3435 my $user = { NICK
=> $new, AGENT
=> $nsuser };
3437 ircd
::setumode
($nsuser, $user, '-r')
3438 unless check_identify
({ NICK
=> $new });
3440 sub handle_oper
($) {
3442 my $nick = $user->{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
3450 release_lock
($nick);
3453 my ($user, $modes) = @_;
3454 my $nick = $user->{NICK
};
3457 my $id = get_user_id
($user);
3459 $get_umodes->execute($id);
3460 my ($omodes) = $get_umodes->fetchrow_array;
3461 $set_umodes->execute(modes
::add
($omodes, $modes, 0), $id);
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);
3470 elsif(($modelist{x
} eq '+') and !defined($modelist{t
}) ) {
3471 my (undef, $cloakhost) = get_cloakhost
($user);
3473 do_chghost
(undef, $nick, $cloakhost, 1);
3475 ircd
::userhost
($nick);
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);
3486 do_chghost
(undef, $nick, $cloakhost, 1);
3488 ircd
::userhost
($nick);
3493 release_lock
($nick);
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()
3501 sub killhandle
($$$$) {
3502 my ($srcUser, $dstUser, $path, $reason) = @_;
3503 my $dst = $dstUser->{NICK
};
3504 my $src = $srcUser->{NICK
};
3505 print "KILL $src $dst\n";
3506 unless (is_agent
($dst)) {
3507 nick_delete
($dstUser, "Killed ($src ($reason))");
3512 my($src, $nick, $ip) = @_;
3514 ($is_ipv6, $ip) = is_ipv6
($ip);
3515 my $user = { 'NICK' => $nick };
3516 my $new = $newuser{lc $nick};
3517 delete $newuser{lc $nick};
3518 #my $targetid = get_nick_id($target);
3521 my @ips = split(/\./, $ip);
3522 for(my $i; $i < 4; $i++) {
3523 $iip += $ips[$i] * (2 ** ((3 - $i) * 8));
3526 $iip = Socket6
::inet_pton
(&AF_INET6
, $ip);
3531 my $id = get_user_id
($user);
3533 set_ip
($user, $iip);
3535 $iip = get_ipv6_net
($ip);
3536 set_ipv6
($user, $iip, $ip);
3538 my $killed = kill_clones
($user, $iip);
3540 release_lock
($nick);
3542 nick_create_post
($nick) if(!$killed and $new);
3546 my ($src, $dst, $vhost) = @_;
3547 my $user = { NICK
=> $dst };
3548 my $uid = get_user_id
($user);
3551 do_chghost
($src, $dst, $vhost, 1);
3553 $get_umodes->execute($uid);
3554 my ($omodes) = $get_umodes->fetchrow_array;
3555 # I'm told that this is only valid if CLK is set, and
3556 # there is no good way yet to get info from the ircd/net
3557 # module to this code. it stinks of ircd-specific too
3558 # Also, we currently do any USERHOST replies as CHGHOST events
3559 # However, that is no longer necessary with CLK
3560 $set_umodes->execute(modes
::add
($omodes, '+xt', 0), $uid);
3564 sub do_chghost
($$$;$) {
3565 # Don't use this for the handler,
3566 # this is only for internal use
3567 # where we don't want full loopback semantics.
3568 # We call it from the normal handler.
3569 my ($src, $dst, $vhost, $no_lock) = @_;
3570 # $no_lock is for where we already took the lock in the caller
3571 # MySQL's GET LOCK doesn't allow recursive locks
3572 my $user = { NICK
=> $dst };
3573 my $uid = get_user_id
($user);
3575 $update_regnick_vhost->execute($vhost, $uid);
3576 $update_regnick_vhost->finish();
3578 get_lock
($dst) unless $no_lock;
3580 set_vhost
($user, $vhost);
3581 chanserv
::akick_alluser
($user);
3583 release_lock
($dst) unless $no_lock;
3587 my ($src, $dst, $ident) = @_;
3588 my $user = { NICK
=> $dst };
3590 set_ident
($user, $ident);
3591 chanserv
::akick_alluser
($user);