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 $nsuser = { NICK
=> $nsnick, ID
=> ircd
::getAgentUuid
($nsnick) };
188 $nick_check = $dbh->prepare("SELECT id FROM user WHERE nick=? AND online=0 AND time=?");
189 $nick_checkExists = $dbh -> prepare
("SELECT nick FROM user WHERE id=? AND time=?");
190 $nick_deleteChanUser = $dbh -> prepare
("DELETE FROM chanuser WHERE nickid=?");
191 $nick_deleteNickCh = $dbh -> prepare
("DELETE FROM nickchg WHERE nickid=?");
192 $nick_deleteNickId = $dbh -> prepare
("DELETE FROM nickid WHERE id=?");
193 $id_delUser = $dbh->prepare ("DELETE FROM user WHERE id=?");
194 $nick_delUser = $dbh->prepare ("DELETE FROM user WHERE nick=?");
195 $nick_create = $dbh->prepare("INSERT INTO user SET nick=?, time=?, inval=0, ident=?, host=?, vhost=?, server=?, modes=?,
196 gecos=?, flags=?, cloakhost=?, online=1");
197 $nick_create2 = $dbh->prepare("INSERT INTO user SET id=?, nick=?, time=?, inval=0, ident=?, host=?, vhost=?, server=?, modes=?,
198 gecos=?, flags=?, cloakhost=?, online=1");
199 # $nick_create = $dbh->prepare("INSERT INTO user SET id=(RAND()*294967293)+1, nick=?, time=?, inval=0, ident=?, host=?, vhost=?, server=?, modes=?, gecos=?, flags=?, cloakhost=?, online=1");
200 $nick_create_old = $dbh->prepare("UPDATE user SET nick=?, ident=?, host=?, vhost=?, server=?, modes=?, gecos=?,
201 flags=?, cloakhost=?, online=1 WHERE id=?");
202 $nick_change = $dbh->prepare("UPDATE user SET nick=? WHERE nick=?");
203 $nick_quit = $dbh->prepare("UPDATE user SET online=0, quittime=UNIX_TIMESTAMP() WHERE nick=?");
204 $nick_delete = $dbh->prepare("DELETE FROM user WHERE nick=?");
205 $nick_id_delete = $dbh->prepare("DELETE FROM nickid WHERE id=?");
206 $get_quit_empty_chans = $dbh->prepare("SELECT cu2.chan, COUNT(*) AS c
207 FROM chanuser AS cu1, chanuser AS cu2
209 AND cu1.chan=cu2.chan AND cu1.joined=1 AND cu2.joined=1
210 GROUP BY cu2.chan HAVING c=1 ORDER BY NULL");
211 $nick_chan_delete = $dbh->prepare("DELETE FROM chanuser WHERE nickid=?");
212 $chan_user_partall = $dbh->prepare("UPDATE chanuser SET joined=0 WHERE nickid=?");
213 $get_hostless_nicks = $dbh->prepare("SELECT nick FROM user WHERE vhost='*'");
215 $get_squit_lock = $dbh->prepare("LOCK TABLES chanuser WRITE, chanuser AS cu1 READ LOCAL, chanuser AS cu2 READ LOCAL, user WRITE, nickreg WRITE, nickid WRITE, chanban WRITE, chan WRITE, chanreg READ LOCAL, nicktext WRITE");
216 $squit_users = $dbh->prepare("UPDATE chanuser, user
217 SET chanuser.joined=0, user.online=0, user.quittime=UNIX_TIMESTAMP()
218 WHERE user.id=chanuser.nickid AND user.server=?");
219 # Must call squit_nickreg and squit_lastquit before squit_users as it modifies user.online
220 $squit_nickreg = $dbh->prepare("UPDATE nickreg, nickid, user
221 SET nickreg.last=UNIX_TIMESTAMP()
222 WHERE nickreg.id=nickid.nrid AND nickid.id=user.id
223 AND user.online=1 AND user.server=?");
225 $squit_lastquit = $dbh->prepare("UPDATE nickid, user, nicktext
227 WHERE nicktext.nrid=nickid.nrid AND nickid.id=user.id
228 AND user.online=1 AND user.server=?");
230 $squit_lastquit = $dbh->prepare("REPLACE INTO nicktext ".
231 "SELECT nickid.nrid, ".NTF_QUIT
.", 0, '', ? ".
232 "FROM nickid JOIN user ON (nickid.id=user.id) ".
233 "WHERE user.online=1 AND user.server=?");
234 $get_squit_empty_chans = $dbh->prepare("SELECT cu2.chan, COUNT(*) AS c
235 FROM user, chanuser AS cu1, chanuser AS cu2
236 WHERE user.server=? AND cu1.nickid=user.id
237 AND cu1.chan=cu2.chan AND cu1.joined=1 AND cu2.joined=1
238 GROUP BY cu2.chan HAVING c=1 ORDER BY NULL");
240 $del_nickchg_id = $dbh->prepare("DELETE FROM nickchg WHERE nickid=?");
241 $add_nickchg = $dbh->prepare("REPLACE INTO nickchg SELECT ?, id, ? FROM user WHERE nick=?");
242 $reap_nickchg = $dbh->prepare("DELETE FROM nickchg WHERE seq<?");
244 $get_nick_inval = $dbh->prepare("SELECT nick, inval FROM user WHERE id=?");
245 $inc_nick_inval = $dbh->prepare("UPDATE user SET inval=inval+1 WHERE id=?");
247 $is_registered = $dbh->prepare("SELECT 1 FROM nickalias WHERE alias=?");
248 $is_alias_of = $dbh->prepare("SELECT 1 FROM nickalias AS n1 LEFT JOIN nickalias AS n2 ON n1.nrid=n2.nrid
249 WHERE n1.alias=? AND n2.alias=? LIMIT 1");
251 $get_guest = $dbh->prepare("SELECT flags & @{[UF_GUEST]} FROM user WHERE nick=?");
252 $set_guest = $dbh->prepare("UPDATE user SET flags = IF(?, flags | @{[UF_GUEST]}, flags & ~@{[UF_GUEST]})
255 $get_lock = $dbh->prepare("SELECT GET_LOCK(?, 10)");
256 $release_lock = $dbh->prepare("SELECT RELEASE_LOCK(?)");
258 $get_umodes = $dbh->prepare("SELECT modes FROM user WHERE id=?");
259 $set_umodes = $dbh->prepare("UPDATE user SET modes=? WHERE id=?");
261 $get_info = $dbh->prepare("SELECT nickreg.email, nickreg.regd, nickreg.last, nickreg.flags, nickreg.ident,
262 nickreg.vhost, nickreg.gecos, nickalias.last
263 FROM nickreg, nickalias WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
264 $get_nickreg_quit = $dbh->prepare("SELECT nicktext.data FROM nickreg, nicktext, nickalias
265 WHERE nickalias.nrid=nickreg.id AND nickalias.alias=? AND
266 (nicktext.nrid=nickreg.id AND nicktext.type=".NTF_QUIT
.")");
267 $set_ident = $dbh->prepare("UPDATE user SET ident=? WHERE id=?");
268 $set_vhost = $dbh->prepare("UPDATE user SET vhost=? WHERE id=?");
269 $set_ip = $dbh->prepare("UPDATE user SET ip=?, ipv6=? WHERE id=?");
270 $update_regnick_vhost = $dbh->prepare("UPDATE nickreg,nickid SET nickreg.vhost=?
271 WHERE nickreg.id=nickid.nrid AND nickid.id=?");
272 $get_regd_time = $dbh->prepare("SELECT nickreg.regd FROM nickreg, nickalias
273 WHERE nickalias.nrid=nickreg.id and nickalias.alias=?");
275 $chk_clone_except = $dbh->prepare("SELECT
276 GREATEST(IF((user.ip >> (32 - sesexip.mask)) = (sesexip.ip >> (32 - sesexip.mask)), sesexip.lim, 0),
277 IF(IF(sesexname.serv, user.server, user.host) LIKE sesexname.host, sesexname.lim, 0)) AS n
278 FROM user, sesexip, sesexname WHERE user.id=? ORDER BY n DESC LIMIT 1");
279 $count_clones = $dbh->prepare("SELECT COUNT(*) FROM user WHERE ip=? AND online=1");
281 $get_root_nick = $dbh->prepare("SELECT nickreg.nick FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
282 $get_id_nick = $dbh->prepare("SELECT nickreg.nick FROM nickreg WHERE nickreg.id=?");
283 $identify = $dbh->prepare("INSERT INTO nickid SELECT ?, nickalias.nrid FROM nickalias WHERE alias=?");
284 $identify_ign = $dbh->prepare("INSERT IGNORE INTO nickid SELECT ?, nickalias.nrid FROM nickalias WHERE alias=?");
285 $id_update = $dbh->prepare("UPDATE nickreg, user SET
286 nickreg.last=UNIX_TIMESTAMP(), nickreg.ident=user.ident,
287 nickreg.vhost=user.vhost, nickreg.gecos=user.gecos,
288 nickreg.nearexp=0, nickreg.flags = (nickreg.flags & ~". NRF_VACATION
.")
289 WHERE nickreg.nick=? AND user.id=?");
290 $logout = $dbh->prepare("DELETE FROM nickid WHERE id=?");
291 $unidentify = $dbh->prepare("DELETE FROM nickid USING nickreg, nickid WHERE nickreg.nick=? AND nickid.nrid=nickreg.id");
293 $update_lastseen = $dbh->prepare("UPDATE nickreg,nickid SET nickreg.last=UNIX_TIMESTAMP()
294 WHERE nickreg.id=nickid.nrid AND nickid.id=?");
295 $update_nickalias_last = $dbh->prepare("UPDATE nickalias SET last=UNIX_TIMESTAMP() WHERE alias=?");
296 $quit_update = $dbh->prepare("REPLACE INTO nicktext
297 SELECT nickreg.id, ".NTF_QUIT
().", 0, NULL, ? FROM nickreg, nickid
298 WHERE nickreg.id=nickid.nrid AND nickid.id=?");
300 $set_protect_level = $dbh->prepare("UPDATE nickalias SET protect=? WHERE alias=?");
303 $set_email = $dbh->prepare("UPDATE nickreg, nickalias SET nickreg.email=? WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
305 $set_pass = $dbh->prepare("UPDATE nickreg, nickalias SET nickreg.pass=? WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
307 $get_register_lock = $dbh->prepare("LOCK TABLES nickalias WRITE, nickreg WRITE");
308 $register = $dbh->prepare("INSERT INTO nickreg SET nick=?, pass=?, email=?, flags=".NRF_HIDEMAIL
().", regd=UNIX_TIMESTAMP(), last=UNIX_TIMESTAMP()");
309 $create_alias = $dbh->prepare("INSERT INTO nickalias SELECT id, ?, NULL, NULL FROM nickreg WHERE nick=?");
311 $drop = $dbh->prepare("DELETE FROM nickreg WHERE nick=?");
313 $get_aliases = $dbh->prepare("SELECT nickalias.alias FROM nickalias, nickreg WHERE
314 nickalias.nrid=nickreg.id AND nickreg.nick=? ORDER BY nickalias.alias");
315 $get_glist = $dbh->prepare("SELECT nickalias.alias, nickalias.protect, nickalias.last
316 FROM nickalias, nickreg WHERE
317 nickalias.nrid=nickreg.id AND nickreg.nick=? ORDER BY nickalias.alias");
318 $count_aliases = $dbh->prepare("SELECT COUNT(*) FROM nickalias, nickreg WHERE
319 nickalias.nrid=nickreg.id AND nickreg.nick=?");
320 $get_random_alias = $dbh->prepare("SELECT nickalias.alias FROM nickalias, nickreg WHERE
321 nickalias.nrid=nickreg.id AND nickreg.nick=? AND nickalias.alias != nickreg.nick LIMIT 1");
322 $delete_alias = $dbh->prepare("DELETE FROM nickalias WHERE alias=?");
323 $delete_aliases = $dbh->prepare("DELETE FROM nickalias USING nickreg, nickalias WHERE
324 nickalias.nrid=nickreg.id AND nickreg.nick=?");
326 $get_all_access = $dbh->prepare("SELECT chanacc.chan, chanacc.level, chanacc.adder, chanacc.time FROM nickalias, chanacc WHERE chanacc.nrid=nickalias.nrid AND nickalias.alias=? ORDER BY chanacc.chan");
327 $del_all_access = $dbh->prepare("DELETE FROM chanacc USING chanacc, nickreg WHERE chanacc.nrid=nickreg.id AND nickreg.nick=?");
329 $change_root = $dbh->prepare("UPDATE nickreg SET nick=? WHERE nick=?");
331 $unlock_tables = $dbh->prepare("UNLOCK TABLES");
333 $get_matching_nicks = $dbh->prepare("SELECT nickalias.alias, nickreg.nick, nickreg.ident, nickreg.vhost FROM nickalias, nickreg WHERE nickalias.nrid=nickreg.id AND nickalias.alias LIKE ? AND nickreg.ident LIKE ? AND nickreg.vhost LIKE ? LIMIT 50");
335 $cleanup_chanuser = $dbh->prepare("DELETE FROM chanuser USING chanuser
336 LEFT JOIN user ON (chanuser.nickid=user.id) WHERE user.id IS NULL;");
337 $cleanup_nickid = $dbh->prepare("DELETE FROM nickid USING nickid
338 LEFT JOIN user ON(nickid.id=user.id)
339 WHERE user.id IS NULL");
340 $cleanup_users = $dbh->prepare("DELETE FROM user WHERE online=0 AND quittime>0 AND quittime<?");
341 $get_dead_users = $dbh->prepare("SELECT id,nick,time,online,quittime FROM user
342 WHERE online=0 AND quittime>0 AND quittime<?");
344 $get_expired = $dbh->prepare("SELECT nickreg.nick, nickreg.email, nickreg.ident, nickreg.vhost
345 FROM nickreg LEFT JOIN nickid ON(nickreg.id=nickid.nrid)
346 LEFT JOIN svsop ON(nickreg.id=svsop.nrid)
347 WHERE nickid.nrid IS NULL AND svsop.nrid IS NULL ".
348 'AND ('.(services_conf_nearexpire
? 'nickreg.nearexp!=0 AND' : '').
349 " ( !(nickreg.flags & " . NRF_HOLD
. ") AND !(nickreg.flags & " . NRF_VACATION
. ") AND nickreg.last<? ) OR
350 ( (nickreg.flags & " . NRF_VACATION
. ") AND nickreg.last<? ) ) OR
351 ( (nickreg.flags & ". NRF_EMAILREG
.") AND nickreg.last<?)");
352 $get_near_expired = $dbh->prepare("SELECT nickreg.nick, nickreg.email, nickreg.flags, nickreg.last
353 FROM nickreg LEFT JOIN nickid ON(nickreg.id=nickid.nrid)
354 LEFT JOIN svsop ON(nickreg.id=svsop.nrid)
355 WHERE nickid.nrid IS NULL AND svsop.nrid IS NULL AND nickreg.nearexp=0 AND
356 ( ( !(nickreg.flags & " . NRF_HOLD
. ") AND !(nickreg.flags & " . NRF_VACATION
. ") AND nickreg.last<? ) OR
357 ( (nickreg.flags & " . NRF_VACATION
. ") AND nickreg.last<? )
359 $set_near_expired = $dbh->prepare("UPDATE nickreg SET nearexp=1 WHERE nick=?");
361 $get_watches = $dbh->prepare("SELECT watch.mask, watch.time
363 JOIN nickalias ON (watch.nrid=nickalias.nrid)
364 WHERE nickalias.alias=?");
365 $check_watch = $dbh->prepare("SELECT 1
367 JOIN nickalias ON (watch.nrid=nickalias.nrid)
368 WHERE nickalias.alias=? AND watch.mask=?");
369 $set_watch = $dbh->prepare("INSERT INTO watch SELECT nrid, ?, ? FROM nickalias WHERE alias=?");
370 $del_watch = $dbh->prepare("DELETE FROM watch USING watch
371 JOIN nickalias ON (watch.nrid=nickalias.nrid)
372 WHERE nickalias.alias=? AND watch.mask=?");
373 $drop_watch = $dbh->prepare("DELETE FROM watch
374 USING nickreg JOIN watch ON (watch.nrid=nickreg.id)
375 WHERE nickreg.nick=?");
376 $get_silences = $dbh->prepare("SELECT silence.mask, silence.time, silence.expiry, silence.comment
378 JOIN nickalias ON (silence.nrid=nickalias.nrid)
379 WHERE nickalias.alias=? ORDER BY silence.time");
380 $check_silence = $dbh->prepare("SELECT 1 FROM silence
381 JOIN nickalias ON (silence.nrid=nickalias.nrid)
382 WHERE nickalias.alias=? AND silence.mask=?");
383 $set_silence = $dbh->prepare("INSERT INTO silence SELECT nrid, ?, ?, ?, ? FROM nickalias WHERE alias=?");
384 $del_silence = $dbh->prepare("DELETE FROM silence USING silence, nickalias
385 WHERE silence.nrid=nickalias.nrid AND nickalias.alias=? AND silence.mask=?");
386 $drop_silence = $dbh->prepare("DELETE FROM silence USING nickreg, silence
387 WHERE silence.nrid=nickreg.id AND nickreg.nick=?");
388 $get_expired_silences = $dbh->prepare("SELECT nickreg.nick, silence.mask, silence.comment
390 JOIN silence ON (nickreg.id=silence.nrid)
391 WHERE silence.expiry < UNIX_TIMESTAMP() AND silence.expiry!=0 ORDER BY nickreg.nick");
392 $del_expired_silences = $dbh->prepare("DELETE silence.* FROM silence
393 WHERE silence.expiry < UNIX_TIMESTAMP() AND silence.expiry!=0");
394 $get_silence_by_num = $dbh->prepare("SELECT silence.mask, silence.time, silence.expiry, silence.comment
396 JOIN nickalias ON (silence.nrid=nickalias.nrid)
397 WHERE nickalias.alias=? ORDER BY silence.time LIMIT 1 OFFSET ?");
398 $get_silence_by_num->bind_param(2, 0, SQL_INTEGER
);
400 $get_seen = $dbh->prepare("SELECT nickalias.alias, nickreg.nick, nickreg.last FROM nickreg, nickalias
401 WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
403 $set_greet = $dbh->prepare("REPLACE INTO nicktext SELECT nickreg.id, ".NTF_GREET
.", 0, NULL, ?
404 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
405 $get_greet = $dbh->prepare("SELECT nicktext.data FROM nicktext, nickid
406 WHERE nicktext.nrid=nickid.nrid AND nicktext.type=".NTF_GREET
." AND nickid.id=?
408 $get_greet_nick = $dbh->prepare("SELECT nicktext.data FROM nicktext, nickalias
409 WHERE nicktext.nrid=nickalias.nrid AND nicktext.type=".NTF_GREET
." AND nickalias.alias=?");
410 $del_greet = $dbh->prepare("DELETE nicktext.* FROM nicktext, nickreg, nickalias WHERE
411 nicktext.type=".NTF_GREET
." AND nickreg.id=nickalias.nrid AND nickalias.alias=?");
413 $get_num_nicktext_type = $dbh->prepare("SELECT COUNT(nicktext.id) FROM nicktext, nickalias
414 WHERE nicktext.nrid=nickalias.nrid AND nickalias.alias=? AND nicktext.type=?");
415 $drop_nicktext = $dbh->prepare("DELETE FROM nicktext USING nickreg
416 JOIN nicktext ON (nicktext.nrid=nickreg.id)
417 WHERE nickreg.nick=?");
419 $get_auth_chan = $dbh->prepare("SELECT nicktext.data FROM nicktext, nickalias WHERE
420 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH
().") AND nickalias.alias=? AND nicktext.chan=?");
421 $get_auth_num = $dbh->prepare("SELECT nicktext.chan, nicktext.data FROM nicktext, nickalias WHERE
422 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH
().") AND nickalias.alias=? LIMIT 1 OFFSET ?");
423 $get_auth_num->bind_param(2, 0, SQL_INTEGER
);
424 $del_auth = $dbh->prepare("DELETE nicktext.* FROM nicktext, nickalias WHERE
425 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH
().") AND nickalias.alias=? AND nicktext.chan=?");;
426 $list_auth = $dbh->prepare("SELECT nicktext.chan, nicktext.data FROM nicktext, nickalias WHERE
427 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH
().") AND nickalias.alias=?");
429 $del_nicktext = $dbh->prepare("DELETE nicktext.* FROM nickreg
430 JOIN nickalias ON (nickalias.nrid=nickreg.id)
431 JOIN nicktext ON (nicktext.nrid=nickreg.id)
432 WHERE nicktext.type=? AND nickalias.alias=?");
434 $set_umode_ntf = $dbh->prepare("REPLACE INTO nicktext SELECT nickreg.id, ".NTF_UMODE
().", 1, ?, NULL
435 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
436 $get_umode_ntf = $dbh->prepare("SELECT nicktext.chan FROM nickreg, nickalias, nicktext
437 WHERE nicktext.type=(".NTF_UMODE
().") AND nicktext.nrid=nickalias.nrid AND nickalias.alias=?");
439 $set_vacation_ntf = $dbh->prepare("INSERT INTO nicktext SELECT nickreg.id, ".NTF_VACATION
().", 0, ?, NULL
440 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
441 $get_vacation_ntf = $dbh->prepare("SELECT nicktext.chan FROM nickalias, nicktext
442 WHERE nicktext.nrid=nickalias.nrid AND nicktext.type=".NTF_VACATION
()." AND nickalias.alias=?");
444 $set_authcode_ntf = $dbh->prepare("REPLACE INTO nicktext SELECT nickreg.id, ".NTF_AUTHCODE
().", 0, '', ?
445 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
446 $get_authcode_ntf = $dbh->prepare("SELECT 1 FROM nickalias, nicktext
447 WHERE nicktext.nrid=nickalias.nrid AND nicktext.type=".NTF_AUTHCODE
()." AND nickalias.alias=? AND nicktext.data=?");
449 $get_nicks_by_email = $dbh->prepare("SELECT nickreg.nick, nickreg.ident, nickreg.vhost FROM nickreg
450 WHERE nickreg.email LIKE ? GROUP BY nickreg.nick");
453 import SrSv
::MySQL
::Stub
{
454 add_profile_ntf
=> ['INSERT', "REPLACE INTO nicktext SELECT nickreg.id, @{[NTF_PROFILE]}, 0, ?, ?
455 FROM nickreg JOIN nickalias ON (nickreg.id=nickalias.nrid) WHERE nickalias.alias=?"],
456 get_profile_ntf
=> ['ARRAY', "SELECT chan, data FROM nicktext
457 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
458 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=?"],
459 del_profile_ntf
=> ['NULL', "DELETE nicktext.* FROM nicktext
460 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
461 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=? AND nicktext.chan=?"],
462 wipe_profile_ntf
=> ['NULL', "DELETE nicktext.* FROM nicktext
463 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
464 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=?"],
465 count_profile_ntf
=> ['SCALAR', "SELECT COUNT(chan) FROM nicktext
466 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
467 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=?"],
469 protect_level
=> ['SCALAR', 'SELECT protect FROM nickalias WHERE alias=?'],
470 get_pass
=> ['SCALAR', "SELECT nickreg.pass
471 FROM nickreg JOIN nickalias ON (nickreg.id=nickalias.nrid)
472 WHERE nickalias.alias=?"],
473 get_email
=> ['SCALAR', "SELECT nickreg.email
474 FROM nickalias JOIN nickreg ON (nickreg.id=nickalias.nrid)
475 WHERE nickalias.alias=?"],
476 count_silences
=> ['SCALAR', "SELECT COUNT(silence.nrid) FROM silence
477 JOIN nickalias ON (silence.nrid=nickalias.nrid)
478 WHERE nickalias.alias=?"],
479 count_watches
=> ['SCALAR', "SELECT COUNT(watch.nrid) FROM watch
480 JOIN nickalias ON (watch.nrid=nickalias.nrid)
481 WHERE nickalias.alias=?"],
483 add_autojoin_ntf
=> ['INSERT', "INSERT INTO nicktext
484 SELECT nickreg.id, @{[NTF_JOIN]}, 0, ?, NULL
485 FROM nickreg JOIN nickalias ON (nickreg.id=nickalias.nrid)
486 WHERE nickalias.alias=?"],
487 get_autojoin_ntf
=> ['COLUMN', "SELECT chan
489 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
490 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=?"],
491 wipe_autojoin_ntf
=> ['NULL', "DELETE nicktext.* FROM nickreg
492 JOIN nickalias ON (nickalias.nrid=nickreg.id)
493 JOIN nicktext ON (nicktext.nrid=nickreg.id)
494 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=?"],
495 del_autojoin_ntf
=> ['NULL', "DELETE nicktext.* FROM nickreg
496 JOIN nickalias ON (nickalias.nrid=nickreg.id)
497 JOIN nicktext ON (nicktext.nrid=nickreg.id)
498 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=? AND nicktext.chan=?"],
499 check_autojoin_ntf
=> ['SCALAR', "SELECT 1 FROM nicktext
500 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
501 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=? AND nicktext.chan=?"],
502 get_autojoin_by_num
=> ['SCALAR', "SELECT nicktext.chan
504 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
505 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=? LIMIT 1 OFFSET ?"],
509 ### NICKSERV COMMANDS ###
511 sub ns_ajoin_list
($$) {
512 my ($user, $nick) = @_;
515 foreach my $chan (get_autojoin_ntf
($nick)) {
516 push @data, [++$i, $chan];
519 notice
( $user, columnar
( {TITLE
=> "Channels in \002$nick\002's ajoin",
520 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data ) );
522 sub ns_ajoin_del
($$@) {
523 my ($user, $nick, @args) = @_;
525 if(lc(get_user_nick
($user)) eq lc($nick)) {
529 $subj="\002$nick\002\'s";
530 $obj="\002$nick\002";
533 foreach my $arg (@args) {
534 if ($arg =~ /^[0-9\.,-]+$/) {
535 foreach my $num (makeSeqList
($arg)) {
536 if(my $chan = get_autojoin_by_num
($nick, $num - 1)) {
537 push @entries, $chan;
539 notice
($user, "No entry \002#$num\002 was found in $subj ajoin list");
542 } elsif($arg =~ /^#.*?,#/) {
543 push @entries, split(',', $arg);
548 foreach my $entry (@entries) {
549 if(check_autojoin_ntf
($nick, $entry)) {
550 del_autojoin_ntf
($nick, $entry);
551 notice
($user,"Successfully removed \002$entry\002 from $subj ajoin list.");
554 notice
($user, "\002$entry\002 was not in $subj ajoin!");
558 sub ns_ajoin_wipe
($$) {
559 my ($user, $nick) = @_;
561 if(lc(get_user_nick
($user)) eq lc($nick)) {
565 $subj="\002$nick\002\'s";
566 $obj="\002$nick\002";
568 my $count = wipe_autojoin_ntf
($nick);
570 notice
($user,"Successfully wiped \002$count\002 entries from $subj ajoin list.");
572 notice
($user,"No entries deleted.");
576 sub ns_ajoin_join
($$) {
577 my ($user, $nick) = @_;
578 #ns_ajoin_list($user, $nick);
579 do_ajoin
($user, $nick);
583 my ($user, @args) = @_;
585 my $src = get_user_nick
($user);
586 my @chans = grep(/^(#|\d)/, @args);
587 my @parms = grep(!/^(#|\d)/, @args);
588 if(scalar(@parms) > 1) {
589 $nick = shift @parms;
593 my $cmd = shift @parms;
595 if(lc($src) eq lc($nick)) {
599 $subj="\002$nick\002\'s";
600 $obj="\002$nick\002";
603 my $override = adminserv
::can_do
($user, 'SERVOP');
604 if(is_identified
($user, $nick) || $override) {
605 if(!is_registered
($src)) {
606 notice
($user, "\002$nick\002 is not registered.");
610 notice
($user, "Permission denied for \002$nick\002");
613 if ($cmd =~ /^add$/i) {
614 if(!scalar(@chans)) {
615 notice
($user, "Syntax: \002AJOIN ADD #channel\002");
616 notice
($user, "Type \002/msg NickServ HELP AJOIN\002 for more help");
618 foreach my $chanlist (@chans) {
619 if (defined($chanlist) && $chanlist !~ /^#/) {
620 $chanlist = "#" . $chanlist;
622 foreach my $chan (split(',', $chanlist)) {
623 if(check_autojoin_ntf
($nick, $chan)) {
624 notice
($user, $chan . " is already in $subj ajoin list! ");
627 add_autojoin_ntf
($chan, $nick);
628 notice
($user, "\002$chan\002 added to $subj ajoin.");
633 elsif ($cmd =~ /^list$/i) {
634 ns_ajoin_list
($user, $nick);
636 elsif ($cmd =~ /^join$/i) {
637 ns_ajoin_join
($user, $nick);
639 elsif ($cmd =~ /^del(ete)?$/i) {
640 ns_ajoin_del
($user, $nick, @chans);
642 elsif ($cmd =~ /^(clear|wipe)$/i) {
643 ns_ajoin_wipe
($user, $nick);
646 notice
($user,"Syntax: AJOIN ADD/DEL/LIST/WIPE");
647 notice
($user,"Type \002/msg NickServ HELP AJOIN\002 for more help!");
651 our %high_priority_cmds = (
661 $nsuser = { NICK
=> $nsnick, ID
=> ircd
::getAgentUuid
($nsnick) };
662 my ($user, $dstUser, $msg) = @_;
663 return unless (lc $dstUser->{NICK
} eq lc $nsnick);
665 my @args = split(/\s+/, $msg);
666 my $cmd = shift @args;
668 my $src = $user->{NICK
};
669 $user->{AGENT
} = $nsuser;
670 return if flood_check
($user);
671 if(!defined($high_priority_cmds{lc $cmd}) &&
672 !adminserv
::is_svsop
($user) &&
673 $SrSv::IRCd
::State
::queue_depth
> main_conf_highqueue
)
675 notice
($user, get_user_agent
($user)." is too busy right now. Please try your command again later.");
679 if($cmd =~ /^help$/i) {
680 sendhelp
($user, 'nickserv', @args)
682 elsif ($cmd =~ /^ajoin$/i) {
683 ns_ajoin
($user, shift @args, @args);
685 elsif($cmd =~ /^id(entify)?$/i) {
687 ns_identify
($user, $src, $args[0]);
688 } elsif(@args == 2) {
689 ns_identify
($user, $args[0], $args[1]);
691 notice
($user, 'Syntax: IDENTIFY [nick] <password>');
694 elsif($cmd =~ /^sid(entify)?$/i) {
696 ns_identify
($user, $args[0], $args[1], 1);
698 notice
($user, 'Syntax: SIDENTIFY <nick> <password>');
701 elsif($cmd =~ /^gid(entify)?$/i) {
703 ns_identify
($user, $args[0], $args[1], 2);
705 notice
($user, 'Syntax: GIDENTIFY <nick> <password>');
708 elsif($cmd =~ /^logout$/i) {
711 elsif($cmd =~ /^release$/i) {
713 ns_release
($user, $args[0]);
714 } elsif(@args == 2) {
715 ns_release
($user, $args[0], $args[1]);
717 notice
($user, 'Syntax: RELEASE <nick> [password]');
720 elsif($cmd =~ /^ghost$/i) {
722 ns_ghost
($user, $args[0]);
723 } elsif(@args == 2) {
724 ns_ghost
($user, $args[0], $args[1]);
726 notice
($user, 'Syntax: GHOST <nick> [password]');
729 elsif($cmd =~ /^register$/i) {
731 ns_register
($user, $args[0], $args[1]);
733 notice
($user, 'Syntax: REGISTER <password> <email>');
736 elsif($cmd =~ /^(?:link|group)$/i) {
738 ns_link
($user, $args[0], $args[1]);
740 notice
($user, 'Syntax: LINK <nick> <password>');
743 elsif($cmd =~ /^info$/i) {
745 ns_info
($user, @args);
747 notice
($user, 'Syntax: INFO <nick> [nick ...]');
750 elsif($cmd =~ /^set$/i) {
751 ns_set_parse
($user, @args);
753 elsif($cmd =~ /^(drop|unlink)$/i) {
755 ns_unlink
($user, $src, $args[0]);
758 ns_unlink
($user, $args[0], $args[1]);
761 notice
($user, 'Syntax: UNLINK [nick] <password>');
764 elsif($cmd =~ /^dropgroup$/i) {
766 ns_dropgroup
($user, $src, $args[0]);
769 ns_dropgroup
($user, $args[0], $args[1]);
772 notice
($user, 'Syntax: DROPGROUP [nick] <password>');
775 elsif($cmd =~ /^chgroot$/i) {
777 ns_changeroot
($user, $src, $args[0]);
780 ns_changeroot
($user, $args[0], $args[1]);
783 notice
($user, 'Syntax: CHGROOT [oldroot] <newroot>');
786 elsif($cmd =~ /^sendpass$/i) {
788 ns_sendpass
($user, $args[0]);
790 notice
($user, 'Syntax: SENDPASS <nick>');
793 elsif($cmd =~ /^(?:glist|links)$/i) {
795 ns_glist
($user, $src);
798 ns_glist
($user, @args);
801 notice
($user, 'Syntax: GLIST [nick] [nick ...]');
804 elsif($cmd =~ /^(?:alist|listchans)$/i) {
806 ns_alist
($user, $src);
809 ns_alist
($user, @args);
812 notice
($user, 'Syntax: ALIST [nick] [nick ...]');
815 elsif($cmd =~ /^list$/i) {
817 ns_list
($user, $args[0]);
819 notice
($user, 'Syntax: LIST <mask>');
822 elsif($cmd =~ /^watch$/i) {
823 if ($args[0] =~ /^(add|del|list)$/i) {
824 ns_watch
($user, $src, @args);
826 elsif ($args[1] =~ /^(add|del|list)$/i) {
827 ns_watch
($user, @args);
830 notice
($user, 'Syntax: WATCH <ADD|DEL|LIST> [nick]');
833 elsif($cmd =~ /^silence$/i) {
834 if ($args[0] =~ /^(add|del|list)$/i) {
835 ns_silence
($user, $src, @args);
837 elsif ($args[1] =~ /^(add|del|list)$/i) {
838 ns_silence
($user, @args);
841 notice
($user, 'Syntax: SILENCE [nick] <ADD|DEL|LIST> [mask] [+expiry] [comment]');
844 elsif($cmd =~ /^(acc(ess)?|stat(us)?)$/i) {
846 ns_acc
($user, @args);
849 notice
($user, 'Syntax: ACC <nick> [nick ...]');
852 elsif($cmd =~ /^seen$/i) {
854 ns_seen
($user, @args);
857 notice
($user, 'Syntax: SEEN <nick> [nick ...]');
860 elsif($cmd =~ /^recover$/i) {
862 ns_recover
($user, $args[0]);
863 } elsif(@args == 2) {
864 ns_recover
($user, $args[0], $args[1]);
866 notice
($user, 'Syntax: RECOVER <nick> [password]');
869 elsif($cmd =~ /^auth$/i) {
871 ns_auth
($user, @args);
874 notice
($user, 'Syntax: AUTH [nick] <LIST|ACCEPT|DECLINE> [num|chan]');
877 elsif($cmd =~ /^(?:emailreg|(?:auth|email)code)$/i) {
878 if(scalar(@args) >= 2 and scalar(@args) <= 3) {
879 ns_authcode
($user, @args);
881 notice
($user, 'Syntax: AUTHCODE <nick> <code> [newpassword]');
884 elsif($cmd =~ /^profile$/i) {
885 ns_profile
($user, @args);
887 elsif($cmd =~ /^liste?mail/i) {
889 ns_listemail
($user, $args[0]);
891 notice
($user, 'Syntax: LISTEMAIL <email@domain.tld>');
895 notice
($user, "Unrecognized command.", "For help, type: \002/msg nickserv help\002");
896 wlog
($nsnick, LOG_DEBUG
(), "$src tried to use NickServ $msg");
900 sub ns_identify
($$$;$) {
901 my ($user, $nick, $pass, $svsnick) = @_;
902 my $src = get_user_nick
($user);
904 my $root = get_root_nick
($nick);
906 notice
($user, 'Your nick is not registered.');
911 if(lc($src) ne lc($nick) and is_online
($nick)) {
913 ns_ghost
($user, $nick, $pass) or return;
915 notice
($user, $nick.' is already in use. Please use GHOST, GIDENTIFY or RECOVER');
919 if (is_identified
($user, $nick)) {
920 if(lc $src eq lc $nick) {
921 notice
($user, "Cannot only change case of nick");
924 ircd
::svsnick
($nsuser, $user, $nick);
925 ircd
::setumode
($nsuser, $user, '+r');
929 # cannot be an else, note change of $svsnick above.
930 if (!$svsnick and is_identified
($user, $nick)) {
931 notice
($user, 'You are already identified for nick '.$nick.'.');
935 my $flags = nr_get_flags
($root);
937 if($flags & NRF_FREEZE
) {
938 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
939 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to identify to frozen nick \003\002$nick\002", $user);
943 if($flags & NRF_EMAILREG
) {
944 notice
($user, "This nick is awaiting an email validation code. Please check your email for instructions.");
948 elsif($flags & NRF_SENDPASS
) {
949 notice
($user, "This nick is awaiting a SENDPASS authentication code. Please check your email for instructions.");
953 my $uid = get_user_id
($user);
954 unless(chk_pass
($root, $pass, $user)) {
955 if(inc_nick_inval
($user)) {
956 notice
($user, $err_pass);
958 services
::ulog
($nsnick, LOG_INFO
(), "failed to identify to nick $nick (root: $root)", $user);
962 return do_identify
($user, $nick, $root, $flags, $svsnick);
967 my $uid = get_user_id
($user);
969 $update_lastseen->execute($uid);
970 $logout->execute($uid);
971 delete($user->{NICKFLAGS
});
972 ircd
::nolag
($nsnick, '-', $user);
973 notice
($user, 'You are now logged out');
974 services
::ulog
($nsnick, LOG_INFO
(), "used NickServ LOGOUT", $user);
977 sub ns_release
($$;$) {
978 my ($user, $nick, $pass) = @_;
980 if(nr_chk_flag
($nick, NRF_FREEZE
)) {
981 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
982 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to release frozen nick \003\002$nick\002", $user);
986 unless(is_identified
($user, $nick)) {
988 my $s = ns_identify
($user, $nick, $pass);
989 return if($s == 0); #failed to identify
991 notice
($user, "Nick $nick is not being held.");
995 notice
($user, $err_deny);
999 elsif(enforcer_quit
($nick)) {
1000 notice
($user, 'Your nick has been released from custody.');
1002 notice
($user, "Nick $nick is not being held.");
1006 sub ns_ghost
($$;$) {
1008 my @ghostbusters_quotes = (
1009 'Ray. If someone asks if you are a god, you say, "yes!"',
1010 'I feel like the floor of a taxicab.',
1011 'I don\'t have to take this abuse from you, I\'ve got hundreds of people dying to abuse me.',
1013 'This chick is *toast*.',
1014 '"Where do these stairs go?" "They go up."',
1015 '"That\'s the bedroom, but nothing ever happened in there." "What a crime."',
1016 'NOBODY steps on a church in my town.',
1017 'Whoa, whoa, whoa! Nice shootin\', Tex!',
1018 'It\'s the Stay Puft Marshmallow Man.',
1019 '"Symmetrical book stacking. Just like the Philadelphia mass turbulence of 1947." "You\'re right, no human being would stack books like this."',
1020 '"Egon, this reminds me of the time you tried to drill a hole through your head. Remember that?" "That would have worked if you hadn\'t stopped me."',
1021 '"Ray has gone bye-bye, Egon... what\'ve you got left?" "Sorry, Venkman, I\'m terrified beyond the capacity for rational thought."',
1022 'Listen! Do you smell something?',
1023 'As they say in T.V., I\'m sure there\'s one big question on everybody\'s mind, and I imagine you are the man to answer that. How is Elvis, and have you seen him lately?',
1024 '"You know, you don\'t act like a scientist." "They\'re usually pretty stiff." "You\'re more like a game show host."',
1026 my ($user, $nick, $pass) = @_;
1027 my $src = get_user_nick
($user);
1029 if(nr_chk_flag
($nick, NRF_FREEZE
)) {
1030 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
1031 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to ghost frozen nick \003\002$nick\002", $user);
1035 unless(is_identified
($user, $nick)) {
1037 my $s = ns_identify
($user, $nick, $pass);
1038 return 0 if($s == 0); #failed to identify
1040 notice
($user, $err_deny);
1045 if(!is_online
($nick)) {
1046 notice
($user, "\002$nick\002 is not online");
1048 } elsif(lc $src eq lc $nick) {
1049 notice
($user, "I'm sorry, $src, I'm afraid I can't do that.");
1053 my $ghostbusters = @ghostbusters_quotes[int rand(scalar(@ghostbusters_quotes))];
1054 my $baduser = {NICK
=> $nick};
1055 get_user_id
($baduser);
1056 ircd
::irckill
($nsuser, $baduser, "GHOST command used by $src ($ghostbusters)");
1057 notice
($user, "Your ghost has been disconnected");
1058 services
::ulog
($nsnick, LOG_INFO
(), "used NickServ GHOST on $nick", $user);
1059 #nick_delete($nick);
1064 sub ns_register
($$$) {
1065 my ($user, $pass, $email) = @_;
1066 my $src = get_user_nick
($user);
1068 if($src =~ /^guest/i) {
1069 notice
($user, $err_deny);
1073 unless(validate_email
($email)) {
1074 notice
($user, $err_email);
1078 if ($pass =~ /pass/i) {
1079 notice
($user, 'Try a more secure password.');
1083 my $uid = get_user_id
($user);
1085 $get_register_lock->execute; $get_register_lock->finish;
1087 if(not is_registered
($src)) {
1088 $register->execute($src, hash_pass
($pass), $email); $register->finish();
1089 $create_alias->execute($src, $src); $create_alias->finish;
1090 if (defined(services_conf_default_protect
)) {
1091 $set_protect_level->execute((defined(services_conf_default_protect
) ?
1092 $protect_level{lc services_conf_default_protect
} : 1), $src);
1093 $set_protect_level->finish();
1095 $unlock_tables->execute; $unlock_tables->finish;
1097 if(services_conf_validate_email
) {
1098 nr_set_flag
($src, NRF_EMAILREG
());
1099 authcode
($src, 'emailreg', $email);
1100 notice
($user, "Your registration is not yet complete.",
1101 "Your nick will expire within ".
1102 (services_conf_validate_expire
== 1 ? '24 hours' : services_conf_validate_expire
.' days').
1103 " if you do not enter the validation code.",
1104 "Check your email for further instructions.");
1107 $identify->execute($uid, $src); $identify->finish();
1108 notice
($user, 'You are now registered and identified.');
1109 ircd
::setumode
($nsuser, $user, '+r');
1112 $id_update->execute($src, $uid); $id_update->finish();
1113 services
::ulog
($nsnick, LOG_INFO
(), "registered $src (email: $email)".
1114 (services_conf_validate_email
? ' requires email validation code' : ''),
1117 $unlock_tables->execute; $unlock_tables->finish;
1118 notice
($user, 'Your nickname has already been registered.');
1123 my ($user, $nick, $pass) = @_;
1125 my $root = get_root_nick
($nick);
1126 my $src = get_user_nick
($user);
1127 my $uid = get_user_id
($user);
1129 if($src =~ /^guest/i) {
1130 notice
($user, $err_deny);
1134 unless (is_registered
($nick)) {
1135 if(is_registered
($src)) {
1136 notice
($user, "The nick \002$nick\002 is not registered. You need to change your nick to \002$nick\002 and then link to \002$src\002.");
1137 } else { # if neither $nick nor $src are registered
1138 notice
($user, "You need to register your nick first. For help, type \002/ns help register");
1143 unless(chk_pass
($root, $pass, $user)) {
1144 notice
($user, $err_pass);
1148 if(nr_chk_flag
($nick, NRF_FREEZE
) and (lc $pass ne 'force')) {
1149 notice
($user, "\002$root\002 has been frozen and may not be used.");
1153 if(is_alias_of
($src, $nick)) {
1154 notice
($user, "\002$nick\002 is already linked to \002$src\002.");
1158 $get_register_lock->execute; $get_register_lock->finish;
1160 if(is_registered
($src)) {
1161 $unlock_tables->execute; $unlock_tables->finish;
1163 if(is_identified
($user, $src)) {
1164 notice
($user, "You cannot link an already registered nick. Type this and try again: \002/ns drop $src <password>");
1167 notice
($user, 'Your nickname has already been registered.');
1171 $create_alias->execute($src, $root); $create_alias->finish();
1172 if (defined(services_conf_default_protect
)) {
1173 $set_protect_level->execute((defined(services_conf_default_protect
) ?
1174 $protect_level{lc services_conf_default_protect
} : 1), $src);
1175 $set_protect_level->finish();
1177 $unlock_tables->execute; $unlock_tables->finish;
1179 if(is_identified
($user, $root)) {
1180 $identify_ign->execute($uid, $root); $identify_ign->finish();
1181 $id_update->execute($root, $uid); $id_update->finish();
1183 ns_identify
($user, $root, $pass);
1187 notice
($user, "\002$src\002 is now linked to \002$root\002.");
1188 services
::ulog
($nsnick, LOG_INFO
(), "made $src an alias of $root.", $user);
1190 check_identify
($user);
1193 sub ns_unlink
($$$) {
1194 my ($user, $nick, $pass) = @_;
1195 my $uid = get_user_id
($user);
1196 my $src = get_user_nick
($user);
1198 my $root = get_root_nick
($nick);
1199 unless(chk_pass
($root, $pass, $user)) {
1200 notice
($user, $err_pass);
1204 if(nr_chk_flag
($nick, NRF_FREEZE
) and (lc $pass ne 'force')) {
1205 notice
($user, "\002$root\002 has been frozen and may not be used.", $err_deny);
1206 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to unlink \002$nick\002 from frozen nick \002$root\002", $user);
1210 if(lc $root eq lc $nick) {
1211 $count_aliases->execute($root);
1212 my ($count) = $count_aliases->fetchrow_array;
1214 ns_dropgroup_real
($user, $root);
1218 $get_random_alias->execute($root);
1219 my ($new) = $get_random_alias->fetchrow_array;
1220 ns_changeroot
($user, $root, $new, 1);
1225 unidentify_single
($nick);
1226 delete_alias
($nick);
1227 enforcer_quit
($nick);
1229 notice
($user, "\002$nick\002 has been unlinked from \002$root\002.");
1230 services
::ulog
($nsnick, LOG_INFO
(), "removed alias $nick from $root.", $user);
1233 sub ns_dropgroup
($$$) {
1234 my ($user, $nick, $pass) = @_;
1235 my $uid = get_user_id
($user);
1236 my $src = get_user_nick
($user);
1237 my $root = get_root_nick
($nick);
1239 if(adminserv
::get_svs_level
($root)) {
1240 notice
($user, "A nick with services access may not be dropped.");
1244 unless(chk_pass
($root, $pass, $user)) {
1245 notice
($user, $err_pass);
1249 if(nr_chk_flag
($nick, NRF_FREEZE
) and (lc $pass ne 'force')) {
1250 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
1251 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to dropgroup frozen nick \002$root\002", $user);
1255 ns_dropgroup_real
($user, $root);
1258 sub ns_dropgroup_real
($$) {
1259 my ($user, $root) = @_;
1260 my $src = get_user_nick
($user);
1262 unidentify
($root, "Your nick, \002$root\002, was dropped by \002$src\002.", $src);
1264 #enforcer_quit($nick);
1265 notice
($user, "Your nick(s) have been dropped. Thanks for playing.");
1267 services
::ulog
($nsnick, LOG_INFO
(), "dropped group $root.", $user);
1270 sub ns_changeroot
($$$;$) {
1271 my ($user, $old, $new, $force) = @_;
1273 $force or chk_identified
($user, $old) or return;
1275 my $root = get_root_nick
($old);
1277 if(lc($new) eq lc($root)) {
1278 notice
($user, "\002$root\002 is already your root nick.");
1282 unless(get_root_nick
($new) eq $root) {
1283 notice
($user, "\002$new\002 is not an alias of your nick. Type \002/msg nickserv help link\002 for information about creating aliases.");
1287 changeroot
($root, $new);
1289 notice
($user, "Your root nick is now \002$new\002.");
1290 services
::ulog
($nsnick, LOG_INFO
(), "changed root $root to $new.", $user);
1294 my ($user, @nicks) = @_;
1296 foreach my $nick (@nicks) {
1297 my $root = get_root_nick
($nick);
1299 $get_info->execute($nick);
1300 my @result = $get_info->fetchrow_array;
1301 $get_info->finish();
1304 notice
($user, "The nick \002$nick\002 is not registered.");
1308 my ($email, $regd, $last, $flags, $ident, $vhost, $gecos, $alias_used) = @result;
1309 # the quit entry might not exist if the user hasn't quit yet.
1310 $get_nickreg_quit->execute($nick);
1311 my ($quit) = $get_nickreg_quit->fetchrow_array(); $get_nickreg_quit->finish();
1312 my $hidemail = $flags & NRF_HIDEMAIL
;
1314 $get_greet_nick->execute($nick);
1315 my ($greet) = $get_greet_nick->fetchrow_array(); $get_greet_nick->finish();
1316 $get_umode_ntf->execute($nick);
1317 my ($umode) = $get_umode_ntf->fetchrow_array(); $get_umode_ntf->finish();
1319 my $svslev = adminserv
::get_svs_level
($root);
1320 my $protect = protect_level
($nick);
1321 my $showprivate = (is_identified
($user, $nick) or
1322 adminserv
::is_svsop
($user, adminserv
::S_HELP
()));
1324 my ($seens, $seenm) = do_seen
($nick);
1328 push @data, {FULLROW
=>"(Online now, $seenm.)"} if $seens == 2;
1329 push @data, ["Last seen:", "$seenm."] if $seens == 1;
1332 ["Last seen address:", "$ident\@$vhost"],
1333 ["Registered:", gmtime2
($regd)];
1334 push @data, ["Last used:", ($alias_used ? gmtime2
($alias_used) : 'Unknown')] if $showprivate;
1335 push @data, ["Last real name:", $gecos];
1337 push @data, ["Services Rank:", $adminserv::levels
[$svslev]]
1339 push @data, ["E-mail:", $email] unless $hidemail;
1340 push @data, ["E-mail:", "$email (Hidden)"]
1341 if($hidemail and $showprivate);
1342 push @data, ["Alias of:", $root]
1343 if ((lc $root ne lc $nick) and $showprivate);
1347 push @extra, "Last quit: $quit" if $quit;
1348 push @extra, $protect_long[$protect] if $protect;
1349 push @extra, "Does not accept memos." if($flags & NRF_NOMEMO
);
1350 push @extra, "Cannot be added to channel access lists." if($flags & NRF_NOACC
);
1351 push @extra, "Will not be automatically opped in channels." if($flags & NRF_NEVEROP
);
1352 push @extra, "Requires authorization to be added to channel access lists."
1353 if($flags & NRF_AUTH
);
1354 push @extra, "Is frozen and may not be used." if($flags & NRF_FREEZE
);
1355 push @extra, "Will not expire." if($flags & NRF_HOLD
);
1356 push @extra, "Is currently on vacation." if($flags & NRF_VACATION
);
1357 push @extra, "Registration pending email-code verification." if($flags & NRF_EMAILREG
);
1358 push @extra, "UModes on Identify: ".$umode if ($umode and $showprivate);
1359 push @extra, "Greeting: ".$greet if ($greet and $showprivate);
1360 push @extra, "Disabled highlighting of alternating lines." if ($flags & NRF_NOHIGHLIGHT
);
1362 notice
($user, columnar
({TITLE
=> "NickServ info for \002$nick\002:",
1363 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)},
1364 @data, {COLLAPSE
=> \
@extra, BULLET
=> 1}));
1368 sub ns_set_parse
($@) {
1369 my ($user, @parms) = @_;
1370 my $src = get_user_nick
($user);
1371 # This is a new NS SET parser
1372 # required due to it's annoying syntax
1374 # Most commands have only 2 params at most
1375 # the target (which is implied to be src when not spec'd)
1376 # However in the case of GREET num-params is unbounded
1378 # Alternative parsings would be possible,
1379 # one being to use a regexp for valid set/keys
1380 if (lc($parms[1]) eq 'greet') {
1381 ns_set
($user, @parms);
1383 elsif(lc($parms[0]) eq 'greet') {
1384 ns_set
($user, $src, @parms);
1388 ns_set
($user, $src, $parms[0], $parms[1]);
1390 elsif(@parms == 3) {
1391 ns_set
($user, $parms[0], $parms[1], $parms[2]);
1394 notice
($user, 'Syntax: SET [nick] <option> <value>');
1401 my ($user, $target, $set, @parms) = @_;
1402 my $src = get_user_nick
($user);
1403 my $override = (adminserv
::can_do
($user, 'SERVOP') or
1404 (adminserv
::can_do
($user, 'FREEZE') and $set =~ /^freeze$/i) ? 1 : 0);
1406 unless(is_registered
($target)) {
1407 notice
($user, "\002$target\002 is not registered.");
1410 unless(is_identified
($user, $target) or $override) {
1411 notice
($user, $err_deny);
1416 $set =~ /^protect$/i or
1417 $set =~ /^e?-?mail$/i or
1418 $set =~ /^pass(?:w(?:or)?d)?$/i or
1419 $set =~ /^hidee?-?mail$/i or
1420 $set =~ /^nomemo$/i or
1421 $set =~ /^no(?:acc|op)$/i or
1422 $set =~ /^neverop$/i or
1423 $set =~ /^auth$/i or
1424 $set =~ /^(hold|no-?expire)$/i or
1425 $set =~ /^freeze$/i or
1426 $set =~ /^vacation$/i or
1427 $set =~ /^greet$/i or
1428 $set =~ /^u?modes?$/i or
1429 $set =~ /^(email)?reg$/i or
1430 $set =~ /^nohighlight$/i or
1431 $set =~ /^(?:(?:chg)?root|display)$/i
1433 notice
($user, qq{"$set" is not a valid NickServ setting.});
1438 if($src eq $target) {
1442 $subj="\002$target\002\'s";
1443 $obj="\002$target\002";
1445 delete($user->{NICKFLAGS
});
1447 if($set =~ /^protect$/i) {
1448 my $level = $protect_level{lc shift @parms};
1449 unless (defined($level)) {
1450 notice
($user, "Syntax: SET PROTECT <none|normal|high|kill>");
1454 $set_protect_level->execute($level, $target);
1455 notice
($user, "$subj protection level is now set to \002".$protect_short[$level]."\002. ".$protect_long[$level]);
1460 elsif($set =~ /^e?-?mail$/i) {
1461 unless(@parms == 1) {
1462 notice
($user, 'Syntax: SET EMAIL <address>');
1465 my $email = $parms[0];
1467 unless(validate_email
($email)) {
1468 notice
($user, $err_email);
1472 $set_email->execute($email, $target);
1473 notice
($user, "$subj email address has been changed to \002$email\002.");
1474 services
::ulog
($nsnick, LOG_INFO
(), "changed email of \002$target\002 to $email", $user);
1479 elsif($set =~ /^pass(?:w(?:or)?d)?$/i) {
1480 unless(@parms == 1) {
1481 notice
($user, 'Syntax: SET PASSWD <address>');
1484 if($parms[0] =~ /pass/i) {
1485 notice
($user, 'Try a more secure password.');
1488 $set_pass->execute(hash_pass
($parms[0]), $target);
1489 notice
($user, "$subj password has been changed.");
1490 services
::ulog
($nsnick, LOG_INFO
(), "changed password of \002$target\002", $user);
1491 if(nr_chk_flag
($target, NRF_SENDPASS
())) {
1492 $del_nicktext->execute(NTF_AUTHCODE
, $target); $del_nicktext->finish();
1493 nr_set_flag
($target, NRF_SENDPASS
(), 0);
1499 elsif($set =~ /^greet$/i) {
1501 notice
($user, 'Syntax: SET [nick] GREET <NONE|greeting>');
1505 my $greet = join(' ', @parms);
1506 if ($greet =~ /^(none|off)$/i) {
1507 $del_greet->execute($target);
1508 notice
($user, "$subj greet has been deleted.");
1509 services
::ulog
($nsnick, LOG_INFO
(), "deleted greet of \002$target\002", $user);
1512 $set_greet->execute($greet, $target);
1513 notice
($user, "$subj greet has been set to \002$greet\002");
1514 services
::ulog
($nsnick, LOG_INFO
(), "changed greet of \002$target\002", $user);
1519 elsif($set =~ /^u?modes?$/i) {
1520 unless(@parms == 1) {
1521 notice
($user, 'Syntax: SET UMODE <+modes-modes|none>');
1525 if (lc $parms[0] eq 'none') {
1526 $del_nicktext->execute(NTF_UMODE
, $target); $del_nicktext->finish();
1527 notice
($user, "$obj will not receive any automatic umodes.");
1530 my ($modes, $rejected) = modes
::allowed_umodes
($parms[0]);
1531 $del_nicktext->execute(NTF_UMODE
, $target); $del_nicktext->finish(); # don't allow dups
1532 $set_umode_ntf->execute($modes, $target); $set_umode_ntf->finish();
1533 foreach my $usernick (get_nick_user_nicks
$target) {
1534 ircd
::setumode
($nsuser, $user, $modes)
1538 push @out, "Cannot set these umodes: " . $rejected if $rejected;
1539 push @out, "$subj automatic umodes have been set to: \002" . ($modes ? $modes : 'none');
1540 notice
($user, @out);
1544 elsif($set =~ /^(?:(?:chg)?root|display)$/i) {
1545 ns_changeroot
($user, $target, $parms[0], $override);
1550 if($parms[0] =~ /^(?:no|off|false|0)$/i) { $val = 0; }
1551 elsif($parms[0] =~ /^(?:yes|on|true|1)$/i) { $val = 1; }
1553 notice
($user, "Please say \002on\002 or \002off\002.");
1557 if($set =~ /^hidee?-?mail$/i) {
1558 nr_set_flag
($target, NRF_HIDEMAIL
, $val);
1561 notice
($user, "$subj email address is now hidden.");
1563 notice
($user, "$subj email address is now visible.");
1569 if($set =~ /^nomemo$/i) {
1570 nr_set_flag
($target, NRF_NOMEMO
, $val);
1573 notice
($user, "$subj memos will be blocked.");
1575 notice
($user, "$subj memos will be delivered.");
1581 if($set =~ /^no(?:acc|op)$/i) {
1582 nr_set_flag
($target, NRF_NOACC
, $val);
1585 notice
($user, "$obj may not be added to channel access lists.");
1587 notice
($user, "$obj may be added to channel access lists.");
1593 if($set =~ /^neverop$/i) {
1594 nr_set_flag
($target, NRF_NEVEROP
, $val);
1597 notice
($user, "$obj will not be granted status upon joining channels.");
1599 notice
($user, "$obj will be granted status upon joining channels.");
1605 if($set =~ /^auth$/i) {
1606 nr_set_flag
($target, NRF_AUTH
, $val);
1609 notice
($user, "$obj must now authorize additions to channel access lists.");
1611 notice
($user, "$obj will not be asked to authorize additions to channel access lists.");
1617 if($set =~ /^(hold|no-?expire)$/i) {
1618 unless (adminserv
::can_do
($user, 'SERVOP') or
1619 is_identified
($user, $target) and adminserv
::is_ircop
($user))
1621 notice
($user, $err_deny);
1625 nr_set_flag
($target, NRF_HOLD
, $val);
1628 notice
($user, "\002$target\002 is now held from expiration.");
1629 services
::ulog
($nsnick, LOG_INFO
(), "has held \002$target\002", $user);
1631 notice
($user, "\002$target\002 will now expire normally.");
1632 services
::ulog
($nsnick, LOG_INFO
(), "released \002$target\002 from hold", $user);
1638 if($set =~ /^freeze$/i) {
1639 unless (adminserv
::can_do
($user, 'FREEZE') or
1640 is_identified
($user, $target) and adminserv
::is_ircop
($user))
1642 notice
($user, $err_deny);
1646 nr_set_flag
($target, NRF_FREEZE
, $val);
1649 notice
($user, "\002$target\002 is now frozen.");
1650 unidentify
($target, "Your nick, \002$target\002, has been frozen and may no longer be used.");
1651 services
::ulog
($nsnick, LOG_INFO
(), "froze \002$target\002", $user);
1653 notice
($user, "\002$target\002 is no longer frozen.");
1654 services
::ulog
($nsnick, LOG_INFO
(), "unfroze \002$target\002", $user);
1660 if($set =~ /^vacation$/i) {
1662 $get_regd_time->execute($target);
1663 my ($regd) = $get_regd_time->fetchrow_array;
1664 $get_regd_time->finish();
1666 if(($regd > (time() - 86400 * int(services_conf_vacationexpire
/ 3))) and !$override) {
1667 notice
($user, "$target is not old enough to use VACATION",
1668 'Minimum age is '.int(services_conf_vacationexpire
/ 3).' days');
1672 $get_vacation_ntf->execute($target);
1673 my ($last_vacation) = $get_vacation_ntf->fetchrow_array();
1674 $get_vacation_ntf->finish();
1675 if(defined($last_vacation)) {
1676 $last_vacation = unpack('N', MIME
::Base64
::decode
($last_vacation));
1677 if ($last_vacation > (time() - 86400 * int(services_conf_vacationexpire
/ 3)) and !$override) {
1678 notice
($user, "I'm sorry, \002$src\002, I'm afraid I can't do that.",
1679 "Last vacation ended ".gmtime2
($last_vacation),
1680 'Minimum time between vacations is '.int(services_conf_vacationexpire
/ 3).' days.');
1686 nr_set_flag
($target, NRF_VACATION
, $val);
1688 services
::ulog
($nsnick, LOG_INFO
(),
1689 ($val ? 'enabled' : 'disabled')." vacation mode for \002$target\002", $user);
1690 notice
($user, "Vacation mode ".($val ? 'enabled' : 'disabled')." for \002$target\002");
1694 if($set =~ /^(email)?reg$/i) {
1695 unless (adminserv
::can_do
($user, 'SERVOP'))
1697 notice
($user, $err_deny);
1701 nr_set_flag
($target, NRF_EMAILREG
, $val);
1704 authcode
($target, 'emailreg');
1705 notice
($user, "\002$target\002 now needs an email validation code.");
1706 unidentify
($target, ["Your nick, \002$target\002, has been flagged for an email validation audit.",
1707 "Your nick will expire within 24 hours if you do not enter the validation code.",
1708 "Check your email for further instructions."]);
1709 services
::ulog
($nsnick, LOG_INFO
(), "requested an email audit for \002$target\002", $user);
1711 $del_nicktext->execute(NTF_AUTHCODE
, $target); $del_nicktext->finish();
1712 notice
($user, "\002$target\002 is now fully registered.");
1713 services
::ulog
($nsnick, LOG_INFO
(), "validated the email for \002$target\002", $user);
1719 if($set =~ /^nohighlight$/i) {
1720 nr_set_flag
($target, NRF_NOHIGHLIGHT
, $val);
1723 notice
($user, "$obj will no longer have alternative highlighting of lists.");
1725 notice
($user, "$obj will have alternative highlighting of lists.");
1733 sub ns_sendpass
($$) {
1734 my ($user, $nick) = @_;
1736 unless(adminserv
::is_svsop
($user, adminserv
::S_HELP
() )) {
1737 notice
($user, $err_deny);
1741 my $email = get_email
($nick);
1744 notice
($user, "\002$nick\002 is not registered or does not have an email address.");
1748 my $pass = get_pass
($nick);
1749 if ($pass and !is_hashed
($pass)) {
1750 send_email
($email, "$nsnick Password Reminder",
1751 "The password for the nick $nick is:\n$pass");
1752 notice
($user, "Password for \002$nick\002 has been sent to \002$email\002.");
1754 authcode
($nick, 'sendpass', $email);
1755 nr_set_flag
($nick, NRF_SENDPASS
);
1756 notice
($user, "Password authentication code for \002$nick\002 has been sent to \002$email\002.");
1759 services
::ulog
($nsnick, LOG_INFO
(), "used SENDPASS on $nick ($email)", $user);
1763 my ($user, @targets) = @_;
1765 foreach my $target (@targets) {
1766 my $root = get_root_nick
($target);
1768 notice
$user, "\002$target\002 is not registered.";
1772 unless(is_identified
($user, $target) or
1773 adminserv
::is_svsop
($user, adminserv
::S_HELP
())
1775 notice
$user, "$target: $err_deny";
1780 $get_glist->execute($root);
1781 while(my ($alias, $protect, $last) = $get_glist->fetchrow_array) {
1784 # This needs a new NS GLIST cmd, like NS GLISTA or something.
1785 # The idea is a command that shows the long version of the time_ago.
1786 $time_ago = time_ago
($last, 1);
1788 $time_ago = time_ago
($last);
1790 push @data, ["\002$alias\002", "Protect: $protect_short[$protect]",
1791 ($last ? "Last used $time_ago ago" : '')
1795 notice
$user, columnar
{TITLE
=> "Group list for \002$root\002 (" . $get_glist->rows . " nicks):",
1796 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
1798 $get_glist->finish();
1803 my ($user, @targets) = @_;
1805 foreach my $target (@targets) {
1806 (adminserv
::is_svsop
($user, adminserv
::S_HELP
()) and (
1807 chk_registered
($user, $target) or next)
1808 ) or chk_identified
($user, $target) or next;
1812 $get_all_access->execute($target);
1813 while(my ($c, $l, $a, $t) = $get_all_access->fetchrow_array) {
1815 push @data, [$c, $chanserv::plevels
[$l+$chanserv::plzero
], ($a ? "($a)" : ''),
1819 notice
$user, columnar
{TITLE
=> "Access listing for \002$target\002 (".scalar(@data)." entries)",
1820 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
1825 my ($user, $mask) = @_;
1827 unless(adminserv
::is_svsop
($user, adminserv
::S_HELP
())) {
1828 notice
($user, $err_deny);
1832 my ($mnick, $mident, $mhost) = glob2sql
(parse_mask
($mask));
1834 $mnick = '%' if($mnick eq '');
1835 $mident = '%' if($mident eq '');
1836 $mhost = '%' if($mhost eq '');
1839 $get_matching_nicks->execute($mnick, $mident, $mhost);
1840 while(my ($rnick, $rroot, $rident, $rhost) = $get_matching_nicks->fetchrow_array) {
1841 push @data, [$rnick, ($rroot ne $rnick ? $rroot : ''), $rident . '@' . $rhost];
1844 notice
$user, columnar
{TITLE
=> "Registered nicks matching \002$mask\002:",
1845 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
1848 sub ns_watch
($$$;$) {
1849 my ($user, $target, $cmd, $mask) = @_;
1850 my $src = get_user_nick
($user);
1852 my $root = get_root_nick
($target);
1854 notice
($user, "\002$target\002 is not registered.");
1857 unless(is_identified
($user, $target)) {
1858 notice
($user, $err_deny);
1862 if ($cmd =~ /^add$/i) {
1863 my $max_watches = $IRCd_capabilities{WATCH
}; # load here for caching.
1864 if ($max_watches eq "") {
1865 notice
($user, "The IRCd is not configured to support WATCH. Please contact your friendly network administrators.");
1868 if(count_watches
($root) >= $max_watches) {
1869 notice
($user, "WATCH list for $target full, there is a limit of $max_watches. Please trim your list.");
1873 if($mask =~ /\!/ or $mask =~ /\@/) {
1874 my ($mnick, $mident, $mhost) = parse_mask
($mask);
1875 if ($mnick =~ /\*/) {
1876 notice
($user, "Invalid mask: \002$mask\002",
1877 'A WATCH mask cannot wildcard the nick.');
1882 $check_watch->execute($root, $mask);
1883 if ($check_watch->fetchrow_array) {
1884 notice
($user, "\002$mask\002 is already in \002$target\002's watch list.");
1888 $set_watch->execute($mask, time(), $root);
1889 ircd
::svswatch
($nsuser, $user, "+$mask");
1890 notice
($user, "\002$mask\002 added to \002$target\002's watch list.");
1893 elsif ($cmd =~ /^del(ete)?$/i) {
1894 $check_watch->execute($root, $mask);
1895 if ($IRCd_capabilities{WATCH
} eq "") {
1896 notice
($user, "The IRCd is not configured to support WATCH. Please contact your friendly network administrators.");
1899 unless ($check_watch->fetchrow_array) {
1900 notice
($user, "\002$mask\002 is not in \002$target\002's watch list.");
1903 $del_watch->execute($root, $mask);
1904 ircd
::svswatch
($nsuser, $user, "-$mask");
1905 notice
($user, "\002$mask\002 removed from \002$target\002's watch list.");
1907 elsif ($cmd =~ /^list$/i) {
1910 $get_watches->execute($root);
1911 while(my ($mask, $time) = $get_watches->fetchrow_array) {
1912 push @data, [$mask, gmtime2
($time)];
1915 notice
$user, columnar
{TITLE
=> "Watch list for \002$target\002:",
1916 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
1919 notice
($user, 'Syntax: WATCH <ADD|DEL|LIST> [nick]');
1923 sub ns_silence
($$$;$@) {
1924 my ($user, $target, $cmd, $mask, @args) = @_;
1925 my ($expiry, $comment);
1926 my $src = get_user_nick
($user);
1928 if(lc(get_user_nick
($user)) eq lc($target)) {
1932 $subj="\002$target\002\'s";
1933 $obj="\002$target\002";
1936 sub get_silence_by_num
($$) {
1937 # This one cannot be converted to SrSv::MySQL::Stub, due to bind_param call
1938 my ($nick, $num) = @_;
1939 $get_silence_by_num->execute($nick, $num-1);
1940 my ($mask) = $get_silence_by_num->fetchrow_array();
1941 $get_silence_by_num->finish();
1945 my $root = get_root_nick
($target);
1947 if(!defined($root)) {
1948 #notice($user, "\002$target\002 is not registered.");
1955 if($isRegistered && !is_identified
($user, $target)) {
1956 notice
($user, $err_deny);
1960 if ($cmd =~ /^add$/i) {
1961 my $max_silences = $IRCd_capabilities{SILENCE
};
1962 if ($max_silences eq "") {
1963 notice
($user, "The IRCd is not configured to support SILENCE. Please contact your friendly network administrators.");
1966 if(count_silences
($root) >= $max_silences) {
1967 notice
($user, "SILENCE list for $target full, there is a limit of $max_silences. Please trim your list.");
1971 if (substr($args[0],0,1) eq '+') {
1972 $expiry = shift @args;
1974 elsif (substr($args[-1],0,1) eq '+') {
1975 $expiry = pop @args;
1977 $comment = join(' ', @args);
1979 if($mask !~ /[!@.]/) {
1980 my $target_user = { NICK
=> $mask };
1981 unless(get_user_id
($target_user)) {
1982 notice
($user, qq{"\002$mask\002" is not a known user, nor a valid hostmask.});
1985 $comment = $mask unless $comment;
1987 my ($ident, $vhost) = get_vhost
($target_user);
1988 my ($nick, $ident, $vhost) = make_hostmask
(10, $mask, $ident, $vhost);
1989 $mask = $nick.'!'.$ident.'@'.$vhost;
1992 $mask = normalize_hostmask
($mask);
1996 if("$nsnick!services\@".main_conf_local
=~ hostmask_to_regexp
($mask)) {
1997 notice
($user, "You shouldn't add NickServ to your SILENCE list.");
2002 if(defined $expiry) {
2003 $expiry = parse_time
($expiry) + time();
2009 $check_silence->execute($root, $mask);
2010 if ($check_silence->fetchrow_array) {
2011 notice
($user, "\002$mask\002 is already in $subj SILENCE list.");
2015 $set_silence->execute($mask, time(), $expiry, $comment, $root);
2017 ircd
::svssilence
($nsuser, $user, "+$mask");
2018 notice
($user, "\002$mask\002 added to $subj SILENCE list.");
2020 elsif ($cmd =~ /^del(ete)?$/i) {
2022 if ($mask =~ /^[0-9\.,-]+$/) {
2023 foreach my $num (makeSeqList
($mask)) {
2024 push @masks, get_silence_by_num
($root, $num) or next;
2026 if(scalar(@masks) == 0) {
2027 notice
($user, "Unable to find any silences matching $mask");
2033 my @reply; my @out_masks;
2034 foreach my $mask (@masks) {
2035 $check_silence->execute($root, $mask);
2036 unless ($check_silence->fetchrow_array) {
2037 $mask = normalize_hostmask
($mask);
2039 $check_silence->execute($root, $mask);
2040 unless ($check_silence->fetchrow_array) {
2041 push @reply, "\002$mask\002 is not in $subj SILENCE list.";
2045 $del_silence->execute($root, $mask);
2046 push @out_masks, "-$mask";
2047 push @reply, "\002$mask\002 removed from $subj SILENCE list.";
2049 ircd
::svssilence
($nsuser, $user, @out_masks);
2050 notice
($user, @reply);
2052 elsif ($cmd =~ /^list$/i) {
2053 $get_silences->execute($root);
2055 my @reply; my $i = 1;
2056 while(my ($mask, $time, $expiry, $comment) = $get_silences->fetchrow_array) {
2057 push @reply, "$i \002[\002 $mask \002]\002 Date added: ".gmtime2
($time),
2058 ' '.($comment ? "\002[\002 $comment \002]\002 " : '').
2059 ($expiry ? 'Expires in '.time_rel
($expiry-time
()) :
2060 "\002[\002 Never expires \002]\002");
2064 notice
($user, "SILENCE list for $obj:", (scalar @reply ? @reply : " list empty"));
2067 notice
($user, 'Syntax: SILENCE [nick] <ADD|DEL|LIST> [mask] [+expiry] [comment]');
2073 my ($user, @targets) = @_;
2076 foreach my $target (@targets) {
2077 unless(is_registered
($target)) {
2078 push @reply, "ACC 0 \002$target\002 is not registered.";
2082 unless(is_online
($target)) {
2083 push @reply, "ACC 1 \002$target\002 is registered and offline.";
2087 unless(is_identified
({NICK
=> $target}, $target)) {
2088 push @reply, "ACC 2 \002$target\002 is online but not identified.";
2092 push @reply, "ACC 3 \002$target\002 is registered and identified.";
2094 notice
($user, @reply);
2098 my ($user, @nicks) = @_;
2100 foreach my $nick (@nicks) {
2101 if(lc $nick eq lc (($user->{AGENT
})->{NICK
})) {
2102 notice
($user, "Oh, a wise guy, eh?");
2105 my ($status, $msg) = do_seen
($nick);
2107 notice
($user, "\002$nick\002 is online now, ".$msg.'.');
2108 } elsif($status == 1) {
2109 notice
($user, "\002$nick\002 was last seen ".$msg.'.');
2111 notice
($user, "The nick \002$nick\002 is not registered.");
2116 sub ns_recover
($$;$) {
2117 my ($user, $nick, $pass) = @_;
2118 my $src = get_user_nick
($user);
2120 if(nr_chk_flag
($nick, NRF_FREEZE
)) {
2121 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
2122 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to recover frozen nick \003\002$nick\002", $user);
2126 unless(is_identified
($user, $nick)) {
2128 my $s = ns_identify
($user, $nick, $pass);
2129 return if($s == 0); #failed to identify
2131 notice
($user, $err_deny);
2136 if(!is_online
($nick)) {
2137 notice
($user, "\002$nick\002 is not online");
2139 } elsif(lc $src eq lc $nick) {
2140 notice
($user, "I'm sorry, $src, I'm afraid I can't do that.");
2145 notice
($user, "User claiming your nick has been collided",
2146 "/msg NickServ RELEASE $nick to get it back before the one-minute timeout.");
2147 services
::ulog
($nsnick, LOG_INFO
(), "used NickServ RECOVER on $nick", $user);
2153 my ($user, @args) = @_;
2156 #These helpers shouldn't be needed anywhere else.
2157 # If they ever are, move them to the helpers section
2158 sub get_auth_num
($$) {
2159 # this cannot be converted to SrSv::MySQL::Stub, due to bind_param
2160 my ($nick, $num) = @_;
2161 $get_auth_num->execute($nick, $num - 1);
2162 my ($cn, $data) = $get_auth_num->fetchrow_array();
2163 $get_auth_num->finish();
2164 return ($data ? ($cn, split(/:/, $data)) : undef);
2166 sub get_auth_chan
($$) {
2167 my ($nick, $cn) = @_;
2168 $get_auth_chan->execute($nick, $cn);
2169 my ($data) = $get_auth_chan->fetchrow_array();
2170 $get_auth_chan->finish();
2171 return (split(/:/, $data));
2174 if ($args[0] =~ /^(list|accept|approve|decline|reject)$/i) {
2175 $target = get_user_nick
($user);
2176 $cmd = lc shift @args;
2179 $target = shift @args;
2180 $cmd = lc shift @args;
2183 unless (is_registered
($target)) {
2184 notice
($user, "The nickname \002$target\002 is not registered");
2187 unless (is_identified
($user, $target)) {
2188 notice
($user, $err_deny);
2192 if ($cmd eq 'list') {
2194 $list_auth->execute($target);
2195 while (my ($cn, $data) = $list_auth->fetchrow_array()) {
2196 my ($adder, $old, $level, $time) = split(':', $data);
2197 push @data, [$cn, $chanserv::levels
[$level], $adder, gmtime2
($time)];
2199 if ($list_auth->rows()) {
2200 notice
$user, columnar
{TITLE
=> "Pending authorizations for \002$target\002:",
2201 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
2204 notice
($user, "There are no pending authorizations for \002$target\002");
2207 elsif ($cmd eq 'accept' or $cmd eq 'approve') {
2208 my $parm = shift @args;
2209 my ($cn, $adder, $old, $level, $time);
2210 if(misc
::isint
($parm) and
2211 ($cn, $adder, $old, $level, $time) = get_auth_num
($target, $parm))
2214 elsif ($parm =~ /^\#/ and
2215 ($adder, $old, $level, $time) = get_auth_chan
($target, $parm))
2220 # This should normally be an 'else' as the elsif above should prove false
2221 # For some reason, it doesn't work. the unless ($cn) fixes it.
2222 # It only doesn't work for numbered entries
2223 notice
($user, "There is no entry for \002$parm\002 in \002$target\002's AUTH list");
2226 my $chan = { CHAN
=> $cn };
2227 my $root = get_root_nick
($target);
2229 # These next 3 lines should use chanserv::set_acc() but it doesn't seem to work.
2230 # It won't let me use a $nick instead of $user
2231 $chanserv::set_acc1-
>execute($cn, $level, $root);
2232 $chanserv::set_acc2-
>execute($level, $adder, $cn, $root);
2233 chanserv
::set_modes_allnick
($root, $chan, $level) unless chanserv
::is_neverop
($root);
2235 my $log_str = ($old?'move':'addition')." \002$root\002"
2236 . ($old ? ' from the '.$chanserv::levels
[$old] : '') .
2237 ' to the '.$chanserv::levels
[$level]." list of \002$cn\002";
2238 services
::ulog
($chanserv::csnick
, LOG_INFO
(), "accepted the $log_str from $adder", $user, $chan);
2239 notice
($user, "You have accepted the $log_str");
2240 $del_auth->execute($target, $cn);
2241 $del_auth->finish();
2242 memoserv
::send_memo
($chanserv::csnick
, $adder, "$target accepted the $log_str");
2244 elsif ($cmd eq 'decline' or $cmd eq 'reject') {
2245 my $parm = shift @args;
2246 my ($cn, $adder, $old, $level, $time);
2247 if(misc
::isint
($parm) and
2248 ($cn, $adder, $old, $level, $time) = get_auth_num
($target, $parm))
2251 elsif ($parm =~ /^\#/ and
2252 ($adder, $old, $level, $time) = get_auth_chan
($target, $parm))
2257 # This should normally be an 'else' as the elsif above should prove false
2258 # For some reason, it doesn't work. the unless ($cn) fixes it.
2259 # It only doesn't work for numbered entries
2260 notice
($user, "There is no entry for \002$parm\002 in \002$target\002's AUTH list");
2263 my $chan = { CHAN
=> $cn };
2265 my $root = get_root_nick
($target);
2266 my $log_str = ($old?'move':'addition')." \002$root\002"
2267 . ($old ? ' from the '.$chanserv::plevels
[$old+$chanserv::plzero
] : '') .
2268 ' to the '.$chanserv::plevels
[$level+$chanserv::plzero
]." list of \002$cn\002";
2269 services
::ulog
($chanserv::csnick
, LOG_INFO
(), "declined the $log_str from $adder", $user, $chan);
2270 notice
($user, "You have declined $log_str");
2271 $del_auth->execute($target, $cn);
2272 $del_auth->finish();
2273 memoserv
::send_memo
($chanserv::csnick
, $adder, "$target declined the $log_str");
2275 #elsif ($cmd eq 'read') {
2278 notice
($user, "Unknown AUTH cmd");
2282 sub ns_authcode
($$$;$) {
2283 my ($user, $target, $code, $pass) = @_;
2285 if ($pass and $pass =~ /pass/i) {
2286 notice
($user, 'Try a more secure password.');
2290 unless(is_registered
($target)) {
2291 notice
($user, "\002$target\002 isn't registered.");
2295 if(authcode
($target, undef, $code)) {
2296 notice
($user, "\002$target\002 authenticated.");
2297 services
::ulog
($nsnick, LOG_INFO
(), "logged in to \002$target\002 using an authcode", $user);
2299 do_identify
($user, $target, $target);
2301 ns_set
($user, $target, 'PASSWD', $pass)
2302 } elsif(nr_chk_flag
($target, NRF_SENDPASS
())) {
2303 notice
($user, "YOU MUST CHANGE YOUR PASSWORD NOW", "/NS SET $target PASSWD <newpassword>");
2307 notice
($user, "\002$target\002 authentication failed. Please verify that you typed or pasted the code correctly.");
2311 sub ns_profile
($@) {
2312 my ($user, $first, @args) = @_;
2314 my %profile_dispatch = (
2315 'read' => \
&ns_profile_read
,
2316 'info' => \
&ns_profile_read
,
2318 'del' => \
&ns_profile_del
,
2319 'delete' => \
&ns_profile_del
,
2321 'set' => \
&ns_profile_update
,
2322 'update' => \
&ns_profile_update
,
2323 'add' => \
&ns_profile_update
,
2325 'wipe' => \
&ns_profile_wipe
,
2329 if(my $sub = $profile_dispatch{$args[0]}) {
2330 # Second command with nick
2332 $sub->($user, $first, @args);
2334 elsif(my $sub = $profile_dispatch{$first}) {
2335 # Second command without nick
2336 $sub->($user, get_user_nick
($user), @args);
2340 ns_profile_read
($user, ($first || get_user_nick
($user)));
2344 "Syntax: PROFILE [nick] [SET|DEL|READ|WIPE ...]",
2345 "For help, type: \002/ns help profile\002";
2349 sub ns_profile_read
($$@) {
2350 my ($user, $target, @args) = @_;
2352 foreach my $nick ((scalar(@args) ? @args : $target)) {
2353 next unless chk_registered
($user, $nick);
2354 my @profile_entries = get_profile_ntf
($nick);
2355 if(scalar(@profile_entries)) {
2356 notice
$user, columnar
({TITLE
=> "Profile information for \002$nick\002:",
2357 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)},
2358 map( ["$_->[0]:", $_->[1]], @profile_entries )
2362 notice
$user, "\002$nick\002 has not created a profile.";
2367 sub ns_profile_update
($$@) {
2368 my ($user, $target, @args) = @_;
2370 return unless chk_registered
($user, $target);
2372 unless(is_identified
($user, $target) or
2373 adminserv
::is_svsop
($user, adminserv
::S_HELP
())
2375 notice
($user, "$target: $err_deny");
2379 my ($key, $data) = (shift @args, join(' ', @args));
2381 unless ($key and $data) {
2382 notice
$user, "Syntax: PROFILE [nick] SET <item> <text>",
2383 "For help, type: \002/ns help profile\002";
2387 if(count_profile_ntf
($target) >= MAX_PROFILE
) {
2388 notice
($user, "You may not have more than ".MAX_PROFILE
." profile items.");
2391 elsif (length($key) > 32) {
2392 notice
($user, "Item name may not be longer than 32 characters.");
2395 elsif (length($data) > MAX_PROFILE_LEN
) {
2396 my $over = length($data) - MAX_PROFILE_LEN
;
2397 notice
($user, "Your entry is $over characters too long. (".MAX_PROFILE_LEN
." max.)");
2400 add_profile_ntf
($key, $data, $target);
2401 notice
($user, "\002$target\002's \002$key\002 is now \002$data\002");
2404 sub ns_profile_del
($$@) {
2405 my ($user, $target, @args) = @_;
2407 return unless chk_registered
($user, $target);
2409 unless(is_identified
($user, $target) or
2410 adminserv
::is_svsop
($user, adminserv
::S_HELP
())
2412 notice
($user, "$target: $err_deny");
2416 my $key = shift @args;
2419 notice
$user, "Syntax: PROFILE [nick] DEL <item>",
2420 "For help, type: \002/ns help profile\002";
2424 if(del_profile_ntf
($target, $key) == 0) {
2425 notice
($user, "There is no profile item \002$key\002 for \002$target\002");
2427 notice
($user, "Profile item \002$key\002 for \002$target\002 deleted.");
2431 sub ns_profile_wipe
($$@) {
2432 my ($user, $target, undef) = @_;
2434 unless (is_registered
($target)) {
2435 notice
($user, "$target is not registered.");
2438 unless(is_identified
($user, $target) or
2439 adminserv
::is_svsop
($user, adminserv
::S_HELP
())
2441 notice
($user, "$target: $err_deny");
2445 wipe_profile_ntf
($target);
2446 notice
($user, "Profile for \002$target\002 wiped.");
2449 sub ns_listemail
($$) {
2450 my ($user, $email) = @_;
2451 unless(adminserv
::is_svsop
($user, adminserv
::S_HELP
())) {
2452 notice
($user, $err_deny);
2455 my $likeemail = glob2sql
($email);
2456 my (@found, $count);
2458 $get_nicks_by_email->execute($likeemail);
2459 while (my ($nick, $ident, $host) = $get_nicks_by_email->fetchrow_array) {
2460 push @found, " $nick ($ident\@$host)";
2462 $email =~ s/\%/\*/g;
2464 notice
($user, "Nicks matching an email address consisting of \002$email\002");
2469 notice
($user, "Found \002$count\002 matching nicks.");
2471 notice
($user, "There were no nicknames registered with an email address consisting of \002$email\002");
2481 $get_seen->execute($nick);
2482 if (my ($alias, $root, $lastseen) = $get_seen->fetchrow_array) {
2483 if(my @usernicks = get_nick_user_nicks
($nick)) {
2485 $msg = "using ".(@usernicks==1 ? 'the nick ' : 'the following nicks: ').join(', ', map "\002$_\002", @usernicks);
2489 $msg = time_ago
($lastseen) . " ago (".gmtime2
($lastseen).")";
2493 $status = 0; $msg = undef();
2496 return ($status, $msg);
2499 # For a whole group:
2500 sub unidentify
($$;$) {
2501 my ($nick, $msg, $src) = @_;
2503 $nick = get_root_nick
($nick);
2505 foreach my $t (get_nick_user_nicks
$nick) {
2506 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2507 get_user_id
($user);
2508 ircd
::notice
($nsuser, $user, (ref $msg ? @$msg : $msg)) unless(lc $t eq lc $src);
2509 if(is_alias_of
($nick, $t)) {
2510 ircd
::setumode
($nsuser, $user, '-r');
2514 $unidentify->execute($nick);
2517 # For a single alias:
2518 sub unidentify_single
($$) {
2519 my ($nick, $msg) = @_;
2520 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2521 get_user_id
($user);
2522 if(is_online
($nick)) {
2523 ircd
::setumode
($nsuser, $user, '-r');
2527 sub kill_clones
($$) {
2528 my ($user, $ip) = @_;
2529 my $uid = get_user_id
($user);
2530 my $src = get_user_nick
($user);
2532 return 0 if $ip == 0;
2534 $chk_clone_except->execute($uid);
2535 my ($lim) = $chk_clone_except->fetchrow_array;
2536 return 0 if $lim == MAX_LIM
();
2537 $lim = services_conf_clone_limit
unless $lim;
2539 $count_clones->execute($ip);
2540 my ($c) = $count_clones->fetchrow_array;
2543 ircd
::irckill
($nsuser, $user, "Session Limit Exceeded");
2549 my ($user, $nick) = @_;
2550 my $src = get_user_nick
($user);
2551 if(my @chans = get_autojoin_ntf
($nick)) {
2552 chanserv
::cs_join
($user, @chans);
2556 sub do_identify
($$$;$$) {
2557 my ($user, $nick, $root, $flags, $svsnick) = @_;
2558 my $uid = get_user_id
($user);
2559 my $src = get_user_nick
($user);
2560 $identify_ign->execute($uid, $root);
2561 $id_update->execute($root, $uid);
2563 notice
($user, 'You are now identified.');
2565 delete($user->{NICKFLAGS
});
2566 if($flags & NRF_VACATION
) {
2567 notice
($user, "Welcome back from your vacation, \002$nick\002.");
2568 my $ts = MIME
::Base64
::encode
(pack('N', time()));
2570 $del_nicktext->execute(NTF_VACATION
, $root); $del_nicktext->finish(); #don't allow dups
2571 $set_vacation_ntf->execute($ts, $root);
2572 $set_vacation_ntf->finish();
2575 $get_umode_ntf->execute($nick);
2576 my ($umodes) = $get_umode_ntf->fetchrow_array();
2577 $get_umode_ntf->finish();
2578 if(adminserv
::get_svs_level
($root)) {
2579 $umodes = modes
::merge_umodes
('+h', $umodes);
2580 ircd
::nolag
($nsuser, '+', $user);
2582 $umodes = modes
::merge_umodes
('+r', $umodes) if(is_identified
($user, $src));
2584 hostserv
::hs_on
($user, $root, 1);
2586 if(my @chans = get_autojoin_ntf
($nick)) {
2587 ircd
::svsjoin
($nsuser, $user, @chans);
2591 if(enforcer_quit
($nick)) {
2592 notice
($user, 'Your nick has been released from custody.');
2596 if (lc($src) eq lc($nick)) {
2597 ircd
::setumode
($nsuser, $user, $umodes);
2598 $update_nickalias_last->execute($nick); $update_nickalias_last->finish();
2601 ircd
::svsnick
($nsuser, $user, $nick);
2602 ircd
::setumode
($nsuser, $user, modes
::merge_umodes
('+r', $umodes) );
2603 # the update _should_ be taken care of in nick_change()
2604 #$update_nickalias_last->execute($nick); $update_nickalias_last->finish();
2606 elsif(defined $umodes) {
2607 ircd
::setumode
($nsuser, $user, $umodes);
2610 do_ajoin
($user, $nick);
2612 nickserv
::do_svssilence
($user, $root);
2613 nickserv
::do_svswatch
($user, $root);
2615 chanserv
::akick_alluser
($user);
2616 chanserv
::set_modes_allchan
($user, $flags & NRF_NEVEROP
);
2617 chanserv
::fix_private_join_before_id
($user);
2619 services
::ulog
($nsnick, LOG_INFO
(), "identified to nick $nick (root: $root)", $user);
2621 memoserv
::notify
($user, $root);
2622 notify_auths
($user, $root) if $flags & NRF_AUTH
;
2623 return ($enforced ? 2 : 1);
2626 sub authcode
($;$$) {
2627 my ($nick, $type, $email) = @_;
2629 unless (defined($email)) {
2630 $email = get_email
($nick);
2633 my $authcode = misc
::gen_uuid
(4, 5);
2634 $set_authcode_ntf->execute($authcode, $nick); $set_authcode_ntf->finish();
2635 send_email
($email, "Nick Authentication Code for $nick",
2638 "You are receiving this message from the automated nickname\n".
2639 "management system of the ".$IRCd_capabilities{NETWORK
}." network.\n\n".
2640 (lc($type) eq 'emailreg' ?
2641 "If you did not try to register your nickname with us, you can\n".
2642 "ignore this message. If you continue getting similar e-mails\n".
2643 "from us, chances are that someone is intentionally abusing your\n".
2644 "e-mail address. Please contact an administrator for help.\n".
2646 "In order to complete your registration, you must follow the\n".
2647 "instructions in this e-mail before ".gmtime2
(time+86400)."\n".
2649 "To complete the registration, the next time you connect, issue the\n".
2650 "following command to NickServ:\n\n".
2652 "After you issue the command, your registration will be complete and\n".
2653 "you will be able to use your nickname.\n\n"
2656 (lc($type) eq 'sendpass' ?
2657 "You requested a password authentication code for the nickname '$nick'\n".
2658 "on the ".$IRCd_capabilities{'NETWORK'}." IRC Network.\n".
2659 "As per our password policies, an authcode has been created for\n".
2660 "you and e-mailed to the address you set in NickServ.\n".
2661 "To complete the process, you need to return to ".$IRCd_capabilities{'NETWORK'}.",\n".
2662 "and execute the following command: \n\n"
2665 "/NS EMAILCODE $nick $authcode\n\n".
2667 (lc($type) eq 'sendpass' ?
2668 "YOU MUST CHANGE YOUR PASSWORD AT THIS POINT.\n".
2669 "You can do so via the following command: \n\n".
2670 "/NS SET $nick PASSWD newpassword\n\n".
2671 "alternately, try this command: \n\n".
2673 "/NS EMAILCODE $nick $authcode <password>\n\n"
2677 "If you feel you have gotten this e-mail in error, please contact\n".
2678 "an administrator.\n\n".
2681 "If this e-mail came to you unsolicited and appears to be spam -\n".
2682 "please e-mail ".main_conf_replyto
." with a copy of this e-mail\n".
2683 "including all headers.\n\n".
2688 $get_authcode_ntf->execute($nick, $email);
2689 my ($passed) = $get_authcode_ntf->fetchrow_array();
2690 $get_authcode_ntf->finish();
2692 nr_set_flag
($nick, NRF_EMAILREG
(), 0);
2693 unless(nr_chk_flag
($nick, NRF_SENDPASS
)) {
2694 $del_nicktext->execute(NTF_AUTHCODE
, $nick); $del_nicktext->finish();
2704 # This is mostly for logging, be careful using it for anything else
2705 sub get_hostmask
($) {
2709 if (ref ($user) eq "HASH") {
2711 $src = get_user_nick
($user);
2713 else { $src = $user; }
2714 ($ident, $host) = get_host
($user);
2716 return "$src!$ident\@$host";
2721 $set_guest->execute(1, $nick);
2722 my $randnick = 'Guest'.int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10));
2723 #Prevent collisions.
2724 while (is_online
($randnick)) {
2725 $randnick = 'Guest'.int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10));
2727 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2728 get_user_id
($user);
2729 ircd
::svsnick
($nsuser, $user, $randnick);
2735 return if services_conf_noexpire
;
2738 my ($ne, $e, $ve, $eve) = (services_conf_nearexpire
, services_conf_nickexpire
, services_conf_vacationexpire
,
2739 services_conf_validate_expire
);
2742 $get_expired->execute(time() - (86400 * services_conf_nickexpire
),
2743 time() - (86400 * services_conf_vacationexpire
),
2744 time() - (86400 * services_conf_validate_expire
));
2745 while(my ($nick, $email, $ident, $vhost) = $get_expired->fetchrow_array) {
2747 wlog
($nsnick, LOG_INFO
(), "$nick has expired. Email: $email Vhost: $ident\@$vhost");
2752 return unless services_conf_nearexpire
; # if nearexpire is zero, don't.
2753 $get_near_expired->execute(
2754 $time - (86400 * (services_conf_nickexpire
- services_conf_nearexpire
)),
2755 $time - (86400 * (services_conf_vacationexpire
- services_conf_nearexpire
))
2757 while(my ($nick, $email, $flags, $last) = $get_near_expired->fetchrow_array) {
2758 my $expire_days = services_conf_nearexpire
;
2759 if ( ( $flags & NRF_VACATION
) and ( $last < time() - (86400 * services_conf_vacationexpire
) )
2760 or (($last < time() - (86400 * services_conf_nickexpire
)) ) )
2763 } elsif ( ( $flags & NRF_VACATION
) and ( $last > time() - (86400 * services_conf_vacationexpire
) )
2764 or (($last > time() - (86400 * services_conf_nickexpire
)) ) )
2766 # this terrible invention is to determine how many days until their nick will expire.
2767 # this should almost always be ~7, unless something weird happens like
2768 # F_HOLD or svsop status is removed.
2769 # int truncates, so we add 0.5.
2770 $expire_days = -int(($time - ($last + (86400 *
2771 ( ( $flags & NRF_VACATION
) ? services_conf_vacationexpire
: services_conf_nickexpire
) )))
2774 if($expire_days >= 1) {
2776 $get_aliases->execute($nick);
2777 my $aliases = $get_aliases->fetchrow_arrayref();
2779 my $message = "We would like to remind you that your registered nick, $nick, will expire\n".
2780 "in approximately $expire_days days unless you sign on and identify.";
2781 if(scalar(@$aliases) > 1) {
2782 $message .= "\n\nThe following nicks are linked in this group:\n " . join("\n ", @$aliases);
2785 send_email
($email, "$nsnick Expiration Notice", $message);
2788 wlog
($nsnick, LOG_INFO
(), "$nick will expire ".($expire_days <= 0 ? "today" : "in $expire_days days.")." ($email)");
2789 $set_near_expired->execute($nick);
2793 sub expire_silence_timed
{
2795 $time = 60 unless $time;
2796 add_timer
('', $time, __PACKAGE__
, 'nickserv::expire_silence_timed');
2798 find_expired_silences
();
2801 # This code is a mess b/c we can only pull one entry at a time
2802 # and we want to batch the list to the user and to the ircd.
2803 # our SQL statement explicitly orders the silence entries by nickreg.nick
2804 sub find_expired_silences
() {
2805 $get_expired_silences->execute();
2806 my ($lastnick, @entries);
2807 while(my ($nick, $mask, $comment) = $get_expired_silences->fetchrow_array()) {
2808 if ($nick eq $lastnick) {
2810 do_expired_silences
($lastnick, \
@entries);
2814 push @entries, [$mask, $comment];
2817 do_expired_silences
($lastnick, \
@entries);
2819 $get_expired_silences->finish();
2820 $del_expired_silences->execute(); $del_expired_silences->finish();
2824 sub do_expired_silences
($$) {
2826 my (@entries) = @{$_[1]};
2828 foreach my $user (get_nick_users
$nick) {
2829 $user->{AGENT
} = $nsnick;
2830 get_user_id
($user);
2831 ircd
::svssilence
($nsuser, $user, map ( { '-'.$_->[0] } @entries) );
2832 #notice($user, "The following SILENCE entries have expired: ".
2833 # join(', ', map ( { $_->[0] } @entries) ));
2834 notice
($user, map( { "The following SILENCE entry has expired: \002".$_->[0]."\002 ".$_->[1] } @entries ) );
2837 sub do_svssilence
($$) {
2838 my ($user, $rootnick) = @_;
2839 if ($IRCd_capabilities{SILENCE
} eq "") {
2840 notice
($user, "The IRCd is not configured to support SILENCE. Please contact your friendly network administrators.");
2843 my $target = get_user_nick
($user);
2845 $get_silences->execute($rootnick);
2846 my $count = $get_silences->rows;
2847 unless ($get_silences->rows) {
2848 $get_silences->finish;
2852 for(my $i = 1; $i <= $count; $i++) {
2853 my ($mask, $time, $expiry) = $get_silences->fetchrow_array;
2854 push @silences, "+$mask";
2856 $get_silences->finish;
2857 ircd
::svssilence
($nsuser, $user, @silences);
2861 sub do_svswatch
($$) {
2862 my ($user, $rootnick) = @_;
2863 if ($IRCd_capabilities{WATCH
} eq "") {
2864 notice
($user, "The IRCd is not configured to support WATCH. Please contact your friendly network administrators.");
2867 my $target = get_user_nick
($user);
2869 $get_watches->execute($rootnick);
2870 my $count = $get_watches->rows;
2871 unless ($get_watches->rows) {
2872 $get_watches->finish;
2876 for(my $i = 1; $i <= $count; $i++) {
2877 my ($mask, $time, $expiry) = $get_watches->fetchrow_array;
2878 push @watches, "+$mask";
2880 $get_watches->finish;
2881 ircd
::svswatch
($nsuser, $user, @watches);
2886 my ($user, $rootnick) = @_;
2887 my $target = get_user_nick
($user);
2889 $get_umode_ntf->execute($rootnick);
2890 my ($umodes) = $get_umode_ntf->fetchrow_array; $get_umode_ntf->finish();
2892 ircd
::setumode
($nsuser, $user, $umodes) if $umodes;
2896 sub notify_auths
($$) {
2897 my ($user, $nick) = @_;
2898 $get_num_nicktext_type->execute($nick, NTF_AUTH
);
2899 my ($count) = $get_num_nicktext_type->fetchrow_array(); $get_num_nicktext_type->finish();
2900 notice
($user, "$nick has $count channel authorizations awaiting action.",
2901 "To list them, type /ns auth $nick list") if $count;
2904 ### PROTECTION AND ENFORCEMENT ###
2909 return if nr_chk_flag
($nick, NRF_EMAILREG
());
2910 my $lev = protect_level
($nick);
2911 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2912 get_user_id
($user);
2914 "This nickname is registered and protected. If it is your",
2915 "nick, type \002/msg NickServ IDENTIFY <password>\002. Otherwise,",
2916 "please choose a different nick."
2920 warn_countdown
("$nick 60");
2926 ircd
::svshold
($nick, 60, "If this is your nick, type /NS SIDENTIFY $nick \002password\002");
2927 kill_user
($user, "Unauthorized nick use with KILL protection enabled.");
2928 $enforcers{lc $nick} = 1;
2929 add_timer
($nick, 60, __PACKAGE__
, "nickserv::enforcer_delete");
2935 sub warn_countdown
($) {
2937 my ($nick, $rem) = split(/ /, $cookie);
2938 $nsuser = { NICK
=> $nsnick, ID
=> ircd
::getAgentUuid
($nsnick) };
2939 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2941 if (is_identified
($user, $nick)) {
2942 print "Line 2778\n";
2943 $update_nickalias_last->execute($nick); $update_nickalias_last->finish();
2946 elsif(!(is_online
($nick)) or !(is_registered
($nick))) { print "Line 2782\n"; return; }
2949 notice
($user, 'Your nick is now being changed.');
2953 "If you do not identify or change your nick in $rem seconds, your nick will be changed.");
2955 add_timer
("$nick $rem", 20, __PACKAGE__
, "nickserv::warn_countdown");
2961 my $newnick = guestnick
($nick);
2962 ircd
::svshold
($nick, 60, "If this is your nick, type /NS SIDENTIFY $nick \002password\002");
2963 $enforcers{lc $nick} = 1;
2964 add_timer
($nick, 60, __PACKAGE__
, "nickserv::enforcer_delete");
2968 sub enforcer_delete
($) {
2970 delete($enforcers{lc $nick});
2973 sub enforcer_quit
($) {
2975 if($enforcers{lc $nick}) {
2976 enforcer_delete
($nick);
2977 ircd
::svsunhold
($nick);
2983 ### DATABASE UTILITY FUNCTIONS ###
2991 if($cur_lock ne $nick) {
2992 really_release_lock
($nick);
2993 die("Tried to get two locks at the same time");
2998 $get_lock->execute(sql_conf_mysql_db
.".user.$nick");
3003 sub release_lock
($) {
3008 if($cur_lock and $cur_lock ne $nick) {
3009 really_release_lock
($cur_lock);
3011 die("Tried to release the wrong lock");
3017 really_release_lock
($nick);
3021 sub really_release_lock
($) {
3025 $release_lock->execute(sql_conf_mysql_db
.".user.$nick");
3026 $release_lock->finish;
3030 sub get_user_modes
($) {
3033 my $uid = get_user_id
($user);
3034 $get_umodes->execute($uid);
3035 my ($umodes) = $get_umodes->fetchrow_array;
3036 $get_umodes->finish();
3037 print "UMODES $umodes\n";
3042 my ($user, $vhost) = @_;
3043 my $id = get_user_id
($user);
3045 return $set_vhost->execute($vhost, $id);
3049 my ($user, $ident) = @_;
3050 my $id = get_user_id
($user);
3052 return $set_ident->execute($ident, $id);
3056 my ($user, $ip, $ipv6) = @_;
3057 my $id = get_user_id
($user);
3059 return $set_ip->execute($ip, $ipv6, $id);
3062 my ($user, $ip) = @_;
3063 my $id = get_user_id
($user);
3065 return $set_ip->execute($ip, undef, $id);
3068 sub get_root_nick
($) {
3071 $get_root_nick->execute($nick);
3072 my ($root) = $get_root_nick->fetchrow_array;
3077 sub get_id_nick
($) {
3080 $get_id_nick->execute($id);
3081 my ($root) = $get_id_nick->fetchrow_array;
3089 my $ret = $drop->execute($nick);
3094 sub changeroot
($$) {
3095 my ($old, $new) = @_;
3097 return if(lc $old eq lc $new);
3099 $change_root->execute($new, $old);
3105 $del_all_access->execute($root);
3106 $memoserv::delete_all_memos-
>execute($root);
3107 $memoserv::wipe_ignore-
>execute($root);
3108 $memoserv::purge_ignore-
>execute($root);
3109 chanserv
::drop_nick_chans
($root);
3110 hostserv
::del_vhost
($root);
3111 $drop_watch->execute($root);
3112 $drop_silence->execute($root);
3113 $drop_nicktext->execute($root);
3114 $delete_aliases->execute($root);
3115 $chanserv::drop_nick_akick-
>execute($root);
3122 return (get_root_nick
($nick) eq $nick);
3125 sub delete_alias
($) {
3127 return $delete_alias->execute($nick);
3130 sub delete_aliases
($) {
3132 return $delete_aliases->execute($root);
3135 sub get_all_access
($) {
3138 $get_all_access->execute($nick);
3139 return $get_all_access->fetchrow_array;
3142 sub del_all_access
($) {
3145 return $del_all_access->execute($root);
3149 my ($nick, $pass, $user) = @_;
3151 if(lc($pass) eq 'force' and adminserv
::can_do
($user, 'SERVOP')) {
3152 if(adminserv
::get_best_svs_level
($user) > adminserv
::get_svs_level
($nick)) {
3157 return validate_pass
(get_pass
($nick), $pass);
3160 sub inc_nick_inval
($) {
3162 my $id = get_user_id
($user);
3164 $inc_nick_inval->execute($id);
3165 $get_nick_inval->execute($id);
3166 my ($nick, $inval) = $get_nick_inval->fetchrow_array;
3168 ircd
::irckill
($nsuser, $user, 'Too many invalid passwords.');
3169 # unnecessary as irckill calls the quit handler.
3170 #nick_delete($nick);
3177 sub is_registered
($) {
3180 $is_registered->execute($nick);
3181 if($is_registered->fetchrow_array) {
3188 sub chk_registered
($;$) {
3189 my ($user, $nick) = @_;
3190 my $src = get_user_nick
($user);
3194 if(lc $src eq lc $nick) {
3195 $what = "Your nick";
3197 $what = "The nick \002$nick\002";
3200 $nick = get_user_nick
($user) unless $nick;
3201 $what = "Your nick";
3204 unless(is_registered
($nick)) {
3205 notice
($user, "$what is not registered.");
3212 sub is_alias_of
($$) {
3213 $is_alias_of->execute($_[0], $_[1]);
3214 return ($is_alias_of->fetchrow_array ? 1 : 0);
3217 sub check_identify
($) {
3219 my $nick = get_user_nick
($user);
3220 if(is_registered
($nick)) {
3221 if(is_identified
($user, $nick)) {
3222 ircd
::setumode
($nsuser, $user, '+r');
3223 $update_nickalias_last->execute($nick); $update_nickalias_last->finish();
3232 sub cleanup_users
() {
3233 add_timer
('', services_conf_old_user_age
, __PACKAGE__
, 'nickserv::cleanup_users');
3235 ircd
::privmsg
('ServServ', main_conf_diag
, "Starting cleanup_users()");
3238 my $time = (time() - (services_conf_old_user_age
* 2));
3240 $get_dead_users->execute($time);
3241 my $arrayRef = $get_dead_users->fetchall_arrayref();
3242 if($arrayRef && scalar(@$arrayRef)) {
3243 ircd
::privmsg
('ServServ', main_conf_diag
, columnar
( { BORDER
=> 1, NOHIGHLIGHT
=> 1 }, @$arrayRef ) );
3245 $get_dead_users->finish();
3247 my $rows = $cleanup_users->execute($time) + 0;
3248 $cleanup_nickid->execute();
3249 $cleanup_chanuser->execute();
3251 ircd
::privmsg
('ServServ', main_conf_diag
, "Deleted $rows dead users\n");
3252 ircd
::privmsg
('ServServ', main_conf_diag
, "Ending cleanup_users()");
3258 add_timer
('fix_vhosts', 5, __PACKAGE__
, 'nickserv::fix_vhosts');
3259 $get_hostless_nicks->execute();
3260 while (my ($nick) = $get_hostless_nicks->fetchrow_array) {
3261 ircd
::notice
($nsuser, main_conf_diag
, "HOSTLESS NICK $nick");
3262 ircd
::userhost
($nick);
3263 ircd
::userip
($nick);
3265 $get_hostless_nicks->finish();
3272 $get_user_id->execute($nick);
3273 if($id = $get_user_id->fetchrow_array) {
3274 $nick_id_delete->execute($id);
3275 $nick_delete->execute($nick);
3282 my ($user, $time, $ident, $host, $vhost, $server, $svsstamp, $modes, $gecos, $ip, $cloakhost) = @_;
3283 my $nick = get_user_nick
($user);
3285 if ($vhost eq '*') {
3286 if ({modes
::splitumodes
($modes)}->{x
} eq '+') {
3287 if(defined($cloakhost)) {
3288 $vhost = $cloakhost;
3290 else { # This should never happen with CLK or VHP
3291 ircd
::userhost
($nick);
3299 if ($id = get_user_id
( $user )) {
3300 #$id = decodeUUID ($id);
3301 $nick_checkExists->execute ($id, $time);
3302 my $exists = $nick_checkExists -> fetchrow_array
();
3303 my $flags = (synced
() ? UF_FINISHED
() : 0);
3304 unless (defined($exists)) {
3305 $nick_deleteChanUser -> execute
($id);
3306 $nick_deleteNickCh -> execute
($id);
3307 $nick_deleteNickId -> execute
($id);
3308 $id_delUser -> execute
($id);
3309 $nick_delUser -> execute
($nick);
3310 $nick_create2 -> execute
($id, $nick, $time, $ident, $host, $vhost, $server, $modes, $gecos, $flags, $cloakhost);
3313 $nick_create_old->execute ($nick, $ident, $host, $vhost, $server, $modes, $gecos, $flags, $cloakhost, $id);
3315 $add_nickchg->execute($ircline, $nick, $nick);
3316 release_lock
($nick);
3317 check_identify
($user);
3321 $get_user_nick->execute($svsstamp);
3322 my ($oldnick) = $get_user_nick->fetchrow_array();
3323 $id = $svsstamp if defined($oldnick);
3326 $nick_check->execute($nick, $time);
3327 ($id) = $nick_check->fetchrow_array;
3331 $olduser{lc $nick} = 1;
3332 $nick_create_old->execute($nick, $ident, $host, $vhost, $server, $modes, $gecos, UF_FINISHED
(), $cloakhost, $id);
3336 my $flags = (synced
() ? UF_FINISHED
() : 0);
3338 while($i < 10 and !$nick_create->execute($nick, $time, $ident, $host, $vhost, $server, $modes, $gecos, $flags, $cloakhost)) { $i++ }
3339 $id = get_user_id
( { NICK
=> $nick } ); # There needs to be a better way to do this
3341 ircd
::setsvsstamp
($nsuser, $user, $id) unless $svsstamp == $id;
3343 $add_nickchg->execute($ircline, $nick, $nick);
3345 release_lock
($nick);
3347 $newuser{lc $nick} = 1;
3350 nickserv
::userip
(undef, $nick, $ip);
3352 else { # This should never happen with NICKIP
3353 ircd
::userip
($nick);
3359 sub nick_create_post
($) {
3361 my $user = { NICK
=> $nick };
3362 my $old = $olduser{lc $nick};
3363 delete $olduser{lc $nick};
3365 operserv
::do_news
($nick, 'u') unless($old);
3369 check_identify
($user);
3371 release_lock
($nick);
3374 sub nick_delete
($$) {
3375 my ($user, $quit) = @_;
3376 my $nick = $user->{NICK
};
3378 my $id = get_user_id
($user);
3379 print "DELETE: $nick, $id\n";
3380 $del_nickchg_id->execute($id); $del_nickchg_id->finish();
3381 $quit_update->execute($quit, $id); $quit_update->finish();
3382 $update_lastseen->execute($id); $update_lastseen->finish();
3383 $get_quit_empty_chans->execute($id);
3384 $chan_user_partall->execute($id); $chan_user_partall->finish();
3385 #$nick_chan_delete->execute($id); $nick_chan_delete->finish();
3386 $nick_quit->execute($nick); $nick_quit->finish();
3387 release_lock
($nick);
3388 while(my ($cn) = $get_quit_empty_chans->fetchrow_array) {
3389 chanserv
::channel_emptied
({CHAN
=> $cn});
3391 $get_quit_empty_chans->finish();
3395 my (undef, $servers, $reason) = @_;
3397 $get_squit_lock->execute; $get_squit_lock->finish;
3399 foreach my $server (@$servers) {
3400 $get_squit_empty_chans->execute($server);
3402 $squit_nickreg->execute($server);
3403 $squit_nickreg->finish;
3405 $squit_lastquit->execute("Netsplit from $server", $server);
3406 $squit_lastquit->finish;
3408 $squit_users->execute($server);
3409 $squit_users->finish;
3411 while(my ($cn) = $get_squit_empty_chans->fetchrow_array) {
3412 chanserv
::channel_emptied
({CHAN
=> $cn});
3414 $get_squit_empty_chans->finish;
3417 $unlock_tables->execute; $unlock_tables->finish;
3420 sub nick_change
($$$) {
3421 my ($user, $new, $time) = @_;
3422 my $old = $user->{NICK
};
3423 return if(lc $old eq lc $new);
3424 print "NICK CHANGE: $old -> $new ($time)\n";
3427 $nick_change->execute($new, $old);
3428 $add_nickchg->execute($ircline, $new, $new);
3430 if($new =~ /^guest/i) {
3431 $get_guest->execute($new);
3432 my ($guest) = $get_guest->fetchrow_array();
3434 $set_guest->execute(0, $new);
3440 my $user = { NICK
=> $new, AGENT
=> $nsuser };
3442 ircd
::setumode
($nsuser, $user, '-r')
3443 unless check_identify
({ NICK
=> $new });
3445 sub handle_oper
($) {
3447 my $nick = $user->{NICK
};
3449 my $id = get_user_id
($user);
3450 $get_umodes->execute($id);
3451 my ($omodes) = $get_umodes->fetchrow_array;
3452 $set_umodes->execute(modes
::add
($omodes, "o", 0), $id);
3453 #this is _safe_. even an oper block with no privs gets +o
3454 #it's just not passed to srsv for some reason, all we get is :UID opertype X
3455 release_lock
($nick);
3458 my ($user, $modes) = @_;
3459 my $nick = $user->{NICK
};
3462 my $id = get_user_id
($user);
3464 $get_umodes->execute($id);
3465 my ($omodes) = $get_umodes->fetchrow_array;
3466 $set_umodes->execute(modes
::add
($omodes, $modes, 0), $id);
3469 my %modelist = modes
::splitumodes
($modes);
3470 if (defined($modelist{x
})) {
3471 if($modelist{x
} eq '-') {
3472 my ($ident, $host) = get_host
($user);
3473 do_chghost
(undef, $nick, $host, 1);
3475 elsif(($modelist{x
} eq '+') and !defined($modelist{t
}) ) {
3476 my (undef, $cloakhost) = get_cloakhost
($user);
3478 do_chghost
(undef, $nick, $cloakhost, 1);
3480 ircd
::userhost
($nick);
3485 # awaiting resolution UnrealIRCd bug 2613
3486 elsif ($modelist{t
} eq '-') {
3487 my %omodelist = modes
::splitumodes
($omodes);
3488 if($omodelist{x
} eq '+') {
3489 my (undef, $cloakhost) = get_cloakhost
($user);
3491 do_chghost
(undef, $nick, $cloakhost, 1);
3493 ircd
::userhost
($nick);
3498 release_lock
($nick);
3500 # Else we will get it in a sethost or chghost
3501 # Also be aware, our tracking of umodes xt is imperfect
3502 # as the ircd doesn't always report it to us
3503 # This might need fixing up in chghost()
3506 sub killhandle
($$$$) {
3507 my ($srcUser, $dstUser, $path, $reason) = @_;
3508 my $dst = $dstUser->{NICK
};
3509 my $src = $srcUser->{NICK
};
3510 print "KILL $src $dst\n";
3511 unless (is_agent
($dst)) {
3512 nick_delete
($dstUser, "Killed ($src ($reason))");
3517 my($src, $nick, $ip) = @_;
3519 ($is_ipv6, $ip) = is_ipv6
($ip);
3520 my $user = { 'NICK' => $nick };
3521 my $new = $newuser{lc $nick};
3522 delete $newuser{lc $nick};
3523 #my $targetid = get_nick_id($target);
3526 my @ips = split(/\./, $ip);
3527 for(my $i; $i < 4; $i++) {
3528 $iip += $ips[$i] * (2 ** ((3 - $i) * 8));
3531 $iip = Socket6
::inet_pton
(&AF_INET6
, $ip);
3536 my $id = get_user_id
($user);
3538 set_ip
($user, $iip);
3540 $iip = get_ipv6_net
($ip);
3541 set_ipv6
($user, $iip, $ip);
3543 my $killed = kill_clones
($user, $iip);
3545 release_lock
($nick);
3547 nick_create_post
($nick) if(!$killed and $new);
3551 my ($src, $dst, $vhost) = @_;
3552 my $user = { NICK
=> $dst };
3553 my $uid = get_user_id
($user);
3556 do_chghost
($src, $dst, $vhost, 1);
3558 $get_umodes->execute($uid);
3559 my ($omodes) = $get_umodes->fetchrow_array;
3560 # I'm told that this is only valid if CLK is set, and
3561 # there is no good way yet to get info from the ircd/net
3562 # module to this code. it stinks of ircd-specific too
3563 # Also, we currently do any USERHOST replies as CHGHOST events
3564 # However, that is no longer necessary with CLK
3565 $set_umodes->execute(modes
::add
($omodes, '+xt', 0), $uid);
3569 sub do_chghost
($$$;$) {
3570 # Don't use this for the handler,
3571 # this is only for internal use
3572 # where we don't want full loopback semantics.
3573 # We call it from the normal handler.
3574 my ($src, $dst, $vhost, $no_lock) = @_;
3575 # $no_lock is for where we already took the lock in the caller
3576 # MySQL's GET LOCK doesn't allow recursive locks
3577 my $user = { NICK
=> $dst };
3578 my $uid = get_user_id
($user);
3580 $update_regnick_vhost->execute($vhost, $uid);
3581 $update_regnick_vhost->finish();
3583 get_lock
($dst) unless $no_lock;
3585 set_vhost
($user, $vhost);
3586 chanserv
::akick_alluser
($user);
3588 release_lock
($dst) unless $no_lock;
3592 my ($src, $dst, $ident) = @_;
3593 my $user = { NICK
=> $dst };
3595 set_ident
($user, $ident);
3596 chanserv
::akick_alluser
($user);