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 DBI
qw(:sql_types);
22 use SrSv
::Timer
qw(add_timer);
23 use SrSv
::IRCd
::State
qw($ircline synced initial_synced %IRCd_capabilities);
25 use SrSv
::Conf
qw(main services sql);
26 use SrSv
::Conf2Consts
qw(main services sql);
27 use SrSv
::HostMask
qw(normalize_hostmask hostmask_to_regexp parse_mask parse_hostmask make_hostmask);
29 use SrSv
::MySQL
'$dbh';
30 use SrSv
::MySQL
::Glob
;
32 use SrSv
::Shared
qw(%newuser %olduser);
35 use SrSv
::Text
::Format
qw(columnar);
41 use SrSv
::User
::Notice
;
42 use SrSv
::Help
qw( sendhelp );
44 use SrSv
::NickReg
::Flags
;
45 use SrSv
::NickReg
::User
'/./';
46 use SrSv
::Hash
::Passwords
;
48 use SrSv
::NickControl
::Enforcer
qw(%enforcers);
52 use SrSv
::Util
qw( makeSeqList );
53 use SrSv
::IRCd
::Send qw
(getRevUuid ircd
::getUuid setRevUuid setUuid
);
54 require SrSv
::MySQL
::Stub
;
57 # Clone exception max limit.
58 # This number typically means infinite/no-limit.
71 # This could be made a config option
72 # But our config system currently sucks.
74 # This value likely cannot be increased very far
75 # as the following limits would apply:
76 # 106 (nick/hostmask), 6 (NOTICE), 30 (destination-nick), 32 (key length) = 174
78 # but this does not take into account additional spaces/colons
79 # or reformatting by the SrSv::Format code.
80 # Likely the maximum value is ~300
81 MAX_PROFILE_LEN
=> 250,
84 our $nsnick_default = 'NickServ';
85 our $nsnick = $nsnick_default;
86 our $nsuser = { NICK
=> $nsnick, ID
=> "123AAAAAB" }; #FIXME - erry
90 our @protect_short = ('none', 'normal', 'high', 'kill');
92 'You will not be required to identify to use this nick.',
93 'You must identify within 60 seconds to use this nick.',
94 'You must identify before using this nick.',
95 'You must identify before using this nick or you will be disconnected.'
97 our %protect_level = (
118 $nick_check, $nick_checkExists,
119 $nick_create, $nick_create2, $nick_create_old, $nick_change, $nick_quit, $nick_delete, $nick_id_delete,
120 $get_quit_empty_chans, $nick_chan_delete, $chan_user_partall,
123 $get_squit_lock, $squit_users, $squit_nickreg, $get_squit_empty_chans, $squit_lastquit,
125 $del_nickchg_id, $add_nickchg, $reap_nickchg,
127 $get_nick_inval, $inc_nick_inval,
131 $get_guest, $set_guest,
133 $get_lock, $release_lock,
135 $get_umodes, $set_umodes,
138 $set_vhost, $set_ident, $set_ip,
139 $update_regnick_vhost, $get_regd_time, $get_nickreg_quit,
141 $chk_clone_except, $count_clones,
146 $get_root_nick, $get_id_nick, $chk_pass, $identify, $identify_ign, $id_update, $logout, $unidentify, $unidentify_single,
147 $update_lastseen, $quit_update, $update_nickalias_last,
150 $get_register_lock, $register, $create_alias, $drop, $change_root,
152 $get_aliases, $get_glist, $count_aliases, $get_random_alias, $delete_alias, $delete_aliases,
153 $get_all_access, $del_all_access, $change_all_access, $change_akicks, $change_founders,
154 $change_successors, $change_svsops,
156 $lock_user_table, $unlock_tables,
160 $cleanup_nickid, $cleanup_users, $cleanup_chanuser,
161 $get_expired, $get_near_expired, $set_near_expired,
163 $get_watches, $check_watch, $set_watch, $del_watch, $drop_watch,
164 $get_silences, $check_silence, $set_silence, $del_silence, $drop_silence,
166 $get_expired_silences, $del_expired_silences,
170 $set_greet, $get_greet, $get_greet_nick, $del_greet,
171 $get_num_nicktext_type, $drop_nicktext,
173 $get_auth_chan, $get_auth_num, $del_auth, $list_auth, $add_auth,
177 $set_umode_ntf, $get_umode_ntf,
179 $set_vacation_ntf, $get_vacation_ntf,
181 $set_authcode_ntf, $get_authcode_ntf,
182 $nick_deleteChanUser, $nick_deleteNickCh, $nick_deleteNickId,
187 $nick_check = $dbh->prepare("SELECT id FROM user WHERE nick=? AND online=0 AND time=?");
188 $nick_checkExists = $dbh -> prepare
("SELECT nick FROM user WHERE id=? AND time=?");
189 $nick_deleteChanUser = $dbh -> prepare
("DELETE FROM chanuser WHERE nickid=?");
190 $nick_deleteNickCh = $dbh -> prepare
("DELETE FROM nickchg WHERE nickid=?");
191 $nick_deleteNickId = $dbh -> prepare
("DELETE FROM nickid WHERE id=?");
192 $id_delUser = $dbh->prepare ("DELETE FROM user WHERE id=?");
193 $nick_create = $dbh->prepare("INSERT INTO user SET nick=?, time=?, inval=0, ident=?, host=?, vhost=?, server=?, modes=?,
194 gecos=?, flags=?, cloakhost=?, online=1");
195 $nick_create2 = $dbh->prepare("INSERT INTO user SET id=?, nick=?, time=?, inval=0, ident=?, host=?, vhost=?, server=?, modes=?,
196 gecos=?, flags=?, cloakhost=?, online=1");
197 # $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");
198 $nick_create_old = $dbh->prepare("UPDATE user SET nick=?, ident=?, host=?, vhost=?, server=?, modes=?, gecos=?,
199 flags=?, cloakhost=?, online=1 WHERE id=?");
200 $nick_change = $dbh->prepare("UPDATE user SET nick=? WHERE nick=?");
201 $nick_quit = $dbh->prepare("UPDATE user SET online=0, quittime=UNIX_TIMESTAMP() WHERE nick=?");
202 $nick_delete = $dbh->prepare("DELETE FROM user WHERE nick=?");
203 $nick_id_delete = $dbh->prepare("DELETE FROM nickid WHERE id=?");
204 $get_quit_empty_chans = $dbh->prepare("SELECT cu2.chan, COUNT(*) AS c
205 FROM chanuser AS cu1, chanuser AS cu2
207 AND cu1.chan=cu2.chan AND cu1.joined=1 AND cu2.joined=1
208 GROUP BY cu2.chan HAVING c=1 ORDER BY NULL");
209 $nick_chan_delete = $dbh->prepare("DELETE FROM chanuser WHERE nickid=?");
210 $chan_user_partall = $dbh->prepare("UPDATE chanuser SET joined=0 WHERE nickid=?");
211 $get_hostless_nicks = $dbh->prepare("SELECT nick FROM user WHERE vhost='*'");
213 $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");
214 $squit_users = $dbh->prepare("UPDATE chanuser, user
215 SET chanuser.joined=0, user.online=0, user.quittime=UNIX_TIMESTAMP()
216 WHERE user.id=chanuser.nickid AND user.server=?");
217 # Must call squit_nickreg and squit_lastquit before squit_users as it modifies user.online
218 $squit_nickreg = $dbh->prepare("UPDATE nickreg, nickid, user
219 SET nickreg.last=UNIX_TIMESTAMP()
220 WHERE nickreg.id=nickid.nrid AND nickid.id=user.id
221 AND user.online=1 AND user.server=?");
223 $squit_lastquit = $dbh->prepare("UPDATE nickid, user, nicktext
225 WHERE nicktext.nrid=nickid.nrid AND nickid.id=user.id
226 AND user.online=1 AND user.server=?");
228 $squit_lastquit = $dbh->prepare("REPLACE INTO nicktext ".
229 "SELECT nickid.nrid, ".NTF_QUIT
.", 0, '', ? ".
230 "FROM nickid JOIN user ON (nickid.id=user.id) ".
231 "WHERE user.online=1 AND user.server=?");
232 $get_squit_empty_chans = $dbh->prepare("SELECT cu2.chan, COUNT(*) AS c
233 FROM user, chanuser AS cu1, chanuser AS cu2
234 WHERE user.server=? AND cu1.nickid=user.id
235 AND cu1.chan=cu2.chan AND cu1.joined=1 AND cu2.joined=1
236 GROUP BY cu2.chan HAVING c=1 ORDER BY NULL");
238 $del_nickchg_id = $dbh->prepare("DELETE FROM nickchg WHERE nickid=?");
239 $add_nickchg = $dbh->prepare("REPLACE INTO nickchg SELECT ?, id, ? FROM user WHERE nick=?");
240 $reap_nickchg = $dbh->prepare("DELETE FROM nickchg WHERE seq<?");
242 $get_nick_inval = $dbh->prepare("SELECT nick, inval FROM user WHERE id=?");
243 $inc_nick_inval = $dbh->prepare("UPDATE user SET inval=inval+1 WHERE id=?");
245 $is_registered = $dbh->prepare("SELECT 1 FROM nickalias WHERE alias=?");
246 $is_alias_of = $dbh->prepare("SELECT 1 FROM nickalias AS n1 LEFT JOIN nickalias AS n2 ON n1.nrid=n2.nrid
247 WHERE n1.alias=? AND n2.alias=? LIMIT 1");
249 $get_guest = $dbh->prepare("SELECT guest FROM user WHERE nick=?");
250 $set_guest = $dbh->prepare("UPDATE user SET guest=? WHERE nick=?");
252 $get_lock = $dbh->prepare("SELECT GET_LOCK(?, 10)");
253 $release_lock = $dbh->prepare("SELECT RELEASE_LOCK(?)");
255 $get_umodes = $dbh->prepare("SELECT modes FROM user WHERE id=?");
256 $set_umodes = $dbh->prepare("UPDATE user SET modes=? WHERE id=?");
258 $get_info = $dbh->prepare("SELECT nickreg.email, nickreg.regd, nickreg.last, nickreg.flags, nickreg.ident,
259 nickreg.vhost, nickreg.gecos, nickalias.last
260 FROM nickreg, nickalias WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
261 $get_nickreg_quit = $dbh->prepare("SELECT nicktext.data FROM nickreg, nicktext, nickalias
262 WHERE nickalias.nrid=nickreg.id AND nickalias.alias=? AND
263 (nicktext.nrid=nickreg.id AND nicktext.type=".NTF_QUIT
.")");
264 $set_ident = $dbh->prepare("UPDATE user SET ident=? WHERE id=?");
265 $set_vhost = $dbh->prepare("UPDATE user SET vhost=? WHERE id=?");
266 $set_ip = $dbh->prepare("UPDATE user SET ip=? WHERE id=?");
267 $update_regnick_vhost = $dbh->prepare("UPDATE nickreg,nickid SET nickreg.vhost=?
268 WHERE nickreg.id=nickid.nrid AND nickid.id=?");
269 $get_regd_time = $dbh->prepare("SELECT nickreg.regd FROM nickreg, nickalias
270 WHERE nickalias.nrid=nickreg.id and nickalias.alias=?");
272 $chk_clone_except = $dbh->prepare("SELECT
273 GREATEST(IF((user.ip >> (32 - sesexip.mask)) = (sesexip.ip >> (32 - sesexip.mask)), sesexip.lim, 0),
274 IF(IF(sesexname.serv, user.server, user.host) LIKE sesexname.host, sesexname.lim, 0)) AS n
275 FROM user, sesexip, sesexname WHERE user.id=? ORDER BY n DESC LIMIT 1");
276 $count_clones = $dbh->prepare("SELECT COUNT(*) FROM user WHERE ip=? AND online=1");
278 $get_root_nick = $dbh->prepare("SELECT nickreg.nick FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
279 $get_id_nick = $dbh->prepare("SELECT nickreg.nick FROM nickreg WHERE nickreg.id=?");
280 $identify = $dbh->prepare("INSERT INTO nickid SELECT ?, nickalias.nrid FROM nickalias WHERE alias=?");
281 $identify_ign = $dbh->prepare("INSERT IGNORE INTO nickid SELECT ?, nickalias.nrid FROM nickalias WHERE alias=?");
282 $id_update = $dbh->prepare("UPDATE nickreg, user SET
283 nickreg.last=UNIX_TIMESTAMP(), nickreg.ident=user.ident,
284 nickreg.vhost=user.vhost, nickreg.gecos=user.gecos,
285 nickreg.nearexp=0, nickreg.flags = (nickreg.flags & ~". NRF_VACATION
.")
286 WHERE nickreg.nick=? AND user.id=?");
287 $logout = $dbh->prepare("DELETE FROM nickid WHERE id=?");
288 $unidentify = $dbh->prepare("DELETE FROM nickid USING nickreg, nickid WHERE nickreg.nick=? AND nickid.nrid=nickreg.id");
290 $update_lastseen = $dbh->prepare("UPDATE nickreg,nickid SET nickreg.last=UNIX_TIMESTAMP()
291 WHERE nickreg.id=nickid.nrid AND nickid.id=?");
292 $update_nickalias_last = $dbh->prepare("UPDATE nickalias SET last=UNIX_TIMESTAMP() WHERE alias=?");
293 $quit_update = $dbh->prepare("REPLACE INTO nicktext
294 SELECT nickreg.id, ".NTF_QUIT
().", 0, NULL, ? FROM nickreg, nickid
295 WHERE nickreg.id=nickid.nrid AND nickid.id=?");
297 $set_protect_level = $dbh->prepare("UPDATE nickalias SET protect=? WHERE alias=?");
300 $set_email = $dbh->prepare("UPDATE nickreg, nickalias SET nickreg.email=? WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
302 $set_pass = $dbh->prepare("UPDATE nickreg, nickalias SET nickreg.pass=? WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
304 $get_register_lock = $dbh->prepare("LOCK TABLES nickalias WRITE, nickreg WRITE");
305 $register = $dbh->prepare("INSERT INTO nickreg SET nick=?, pass=?, email=?, flags=".NRF_HIDEMAIL
().", regd=UNIX_TIMESTAMP(), last=UNIX_TIMESTAMP()");
306 $create_alias = $dbh->prepare("INSERT INTO nickalias SELECT id, ?, NULL, NULL FROM nickreg WHERE nick=?");
308 $drop = $dbh->prepare("DELETE FROM nickreg WHERE nick=?");
310 $get_aliases = $dbh->prepare("SELECT nickalias.alias FROM nickalias, nickreg WHERE
311 nickalias.nrid=nickreg.id AND nickreg.nick=? ORDER BY nickalias.alias");
312 $get_glist = $dbh->prepare("SELECT nickalias.alias, nickalias.protect, nickalias.last
313 FROM nickalias, nickreg WHERE
314 nickalias.nrid=nickreg.id AND nickreg.nick=? ORDER BY nickalias.alias");
315 $count_aliases = $dbh->prepare("SELECT COUNT(*) FROM nickalias, nickreg WHERE
316 nickalias.nrid=nickreg.id AND nickreg.nick=?");
317 $get_random_alias = $dbh->prepare("SELECT nickalias.alias FROM nickalias, nickreg WHERE
318 nickalias.nrid=nickreg.id AND nickreg.nick=? AND nickalias.alias != nickreg.nick LIMIT 1");
319 $delete_alias = $dbh->prepare("DELETE FROM nickalias WHERE alias=?");
320 $delete_aliases = $dbh->prepare("DELETE FROM nickalias USING nickreg, nickalias WHERE
321 nickalias.nrid=nickreg.id AND nickreg.nick=?");
323 $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");
324 $del_all_access = $dbh->prepare("DELETE FROM chanacc USING chanacc, nickreg WHERE chanacc.nrid=nickreg.id AND nickreg.nick=?");
326 $change_root = $dbh->prepare("UPDATE nickreg SET nick=? WHERE nick=?");
328 $unlock_tables = $dbh->prepare("UNLOCK TABLES");
330 $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");
332 $cleanup_chanuser = $dbh->prepare("DELETE FROM chanuser USING chanuser
333 LEFT JOIN user ON (chanuser.nickid=user.id) WHERE user.id IS NULL;");
334 $cleanup_nickid = $dbh->prepare("DELETE FROM nickid, user USING nickid LEFT JOIN user ON(nickid.id=user.id) WHERE user.id IS NULL OR (user.online=0 AND quittime<?)");
335 $cleanup_users = $dbh->prepare("DELETE FROM user WHERE online=0 AND quittime<?");
337 $get_expired = $dbh->prepare("SELECT nickreg.nick, nickreg.email, nickreg.ident, nickreg.vhost
338 FROM nickreg LEFT JOIN nickid ON(nickreg.id=nickid.nrid)
339 LEFT JOIN svsop ON(nickreg.id=svsop.nrid)
340 WHERE nickid.nrid IS NULL AND svsop.nrid IS NULL ".
341 'AND ('.(services_conf_nearexpire
? 'nickreg.nearexp!=0 AND' : '').
342 " ( !(nickreg.flags & " . NRF_HOLD
. ") AND !(nickreg.flags & " . NRF_VACATION
. ") AND nickreg.last<? ) OR
343 ( (nickreg.flags & " . NRF_VACATION
. ") AND nickreg.last<? ) ) OR
344 ( (nickreg.flags & ". NRF_EMAILREG
.") AND nickreg.last<?)");
345 $get_near_expired = $dbh->prepare("SELECT nickreg.nick, nickreg.email, nickreg.flags, nickreg.last
346 FROM nickreg LEFT JOIN nickid ON(nickreg.id=nickid.nrid)
347 LEFT JOIN svsop ON(nickreg.id=svsop.nrid)
348 WHERE nickid.nrid IS NULL AND svsop.nrid IS NULL AND 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<? )
352 $set_near_expired = $dbh->prepare("UPDATE nickreg SET nearexp=1 WHERE nick=?");
354 $get_watches = $dbh->prepare("SELECT watch.mask, watch.time
356 JOIN nickalias ON (watch.nrid=nickalias.nrid)
357 WHERE nickalias.alias=?");
358 $check_watch = $dbh->prepare("SELECT 1
360 JOIN nickalias ON (watch.nrid=nickalias.nrid)
361 WHERE nickalias.alias=? AND watch.mask=?");
362 $set_watch = $dbh->prepare("INSERT INTO watch SELECT nrid, ?, ? FROM nickalias WHERE alias=?");
363 $del_watch = $dbh->prepare("DELETE FROM watch USING watch
364 JOIN nickalias ON (watch.nrid=nickalias.nrid)
365 WHERE nickalias.alias=? AND watch.mask=?");
366 $drop_watch = $dbh->prepare("DELETE FROM watch
367 USING nickreg JOIN watch ON (watch.nrid=nickreg.id)
368 WHERE nickreg.nick=?");
369 $get_silences = $dbh->prepare("SELECT silence.mask, silence.time, silence.expiry, silence.comment
371 JOIN nickalias ON (silence.nrid=nickalias.nrid)
372 WHERE nickalias.alias=? ORDER BY silence.time");
373 $check_silence = $dbh->prepare("SELECT 1 FROM silence
374 JOIN nickalias ON (silence.nrid=nickalias.nrid)
375 WHERE nickalias.alias=? AND silence.mask=?");
376 $set_silence = $dbh->prepare("INSERT INTO silence SELECT nrid, ?, ?, ?, ? FROM nickalias WHERE alias=?");
377 $del_silence = $dbh->prepare("DELETE FROM silence USING silence, nickalias
378 WHERE silence.nrid=nickalias.nrid AND nickalias.alias=? AND silence.mask=?");
379 $drop_silence = $dbh->prepare("DELETE FROM silence USING nickreg, silence
380 WHERE silence.nrid=nickreg.id AND nickreg.nick=?");
381 $get_expired_silences = $dbh->prepare("SELECT nickreg.nick, silence.mask, silence.comment
383 JOIN silence ON (nickreg.id=silence.nrid)
384 WHERE silence.expiry < UNIX_TIMESTAMP() AND silence.expiry!=0 ORDER BY nickreg.nick");
385 $del_expired_silences = $dbh->prepare("DELETE silence.* FROM silence
386 WHERE silence.expiry < UNIX_TIMESTAMP() AND silence.expiry!=0");
387 $get_silence_by_num = $dbh->prepare("SELECT silence.mask, silence.time, silence.expiry, silence.comment
389 JOIN nickalias ON (silence.nrid=nickalias.nrid)
390 WHERE nickalias.alias=? ORDER BY silence.time LIMIT 1 OFFSET ?");
391 $get_silence_by_num->bind_param(2, 0, SQL_INTEGER
);
393 $get_seen = $dbh->prepare("SELECT nickalias.alias, nickreg.nick, nickreg.last FROM nickreg, nickalias
394 WHERE nickalias.nrid=nickreg.id AND nickalias.alias=?");
396 $set_greet = $dbh->prepare("REPLACE INTO nicktext SELECT nickreg.id, ".NTF_GREET
.", 0, NULL, ?
397 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
398 $get_greet = $dbh->prepare("SELECT nicktext.data FROM nicktext, nickid
399 WHERE nicktext.nrid=nickid.nrid AND nicktext.type=".NTF_GREET
." AND nickid.id=?
401 $get_greet_nick = $dbh->prepare("SELECT nicktext.data FROM nicktext, nickalias
402 WHERE nicktext.nrid=nickalias.nrid AND nicktext.type=".NTF_GREET
." AND nickalias.alias=?");
403 $del_greet = $dbh->prepare("DELETE nicktext.* FROM nicktext, nickreg, nickalias WHERE
404 nicktext.type=".NTF_GREET
." AND nickreg.id=nickalias.nrid AND nickalias.alias=?");
406 $get_num_nicktext_type = $dbh->prepare("SELECT COUNT(nicktext.id) FROM nicktext, nickalias
407 WHERE nicktext.nrid=nickalias.nrid AND nickalias.alias=? AND nicktext.type=?");
408 $drop_nicktext = $dbh->prepare("DELETE FROM nicktext USING nickreg
409 JOIN nicktext ON (nicktext.nrid=nickreg.id)
410 WHERE nickreg.nick=?");
412 $get_auth_chan = $dbh->prepare("SELECT nicktext.data FROM nicktext, nickalias WHERE
413 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH
().") AND nickalias.alias=? AND nicktext.chan=?");
414 $get_auth_num = $dbh->prepare("SELECT nicktext.chan, nicktext.data FROM nicktext, nickalias WHERE
415 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH
().") AND nickalias.alias=? LIMIT 1 OFFSET ?");
416 $get_auth_num->bind_param(2, 0, SQL_INTEGER
);
417 $del_auth = $dbh->prepare("DELETE nicktext.* FROM nicktext, nickalias WHERE
418 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH
().") AND nickalias.alias=? AND nicktext.chan=?");;
419 $list_auth = $dbh->prepare("SELECT nicktext.chan, nicktext.data FROM nicktext, nickalias WHERE
420 nicktext.nrid=nickalias.nrid AND nicktext.type=(".NTF_AUTH
().") AND nickalias.alias=?");
422 $del_nicktext = $dbh->prepare("DELETE nicktext.* FROM nickreg
423 JOIN nickalias ON (nickalias.nrid=nickreg.id)
424 JOIN nicktext ON (nicktext.nrid=nickreg.id)
425 WHERE nicktext.type=? AND nickalias.alias=?");
427 $set_umode_ntf = $dbh->prepare("REPLACE INTO nicktext SELECT nickreg.id, ".NTF_UMODE
().", 1, ?, NULL
428 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
429 $get_umode_ntf = $dbh->prepare("SELECT nicktext.chan FROM nickreg, nickalias, nicktext
430 WHERE nicktext.type=(".NTF_UMODE
().") AND nicktext.nrid=nickalias.nrid AND nickalias.alias=?");
432 $set_vacation_ntf = $dbh->prepare("INSERT INTO nicktext SELECT nickreg.id, ".NTF_VACATION
().", 0, ?, NULL
433 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
434 $get_vacation_ntf = $dbh->prepare("SELECT nicktext.chan FROM nickalias, nicktext
435 WHERE nicktext.nrid=nickalias.nrid AND nicktext.type=".NTF_VACATION
()." AND nickalias.alias=?");
437 $set_authcode_ntf = $dbh->prepare("REPLACE INTO nicktext SELECT nickreg.id, ".NTF_AUTHCODE
().", 0, '', ?
438 FROM nickreg, nickalias WHERE nickreg.id=nickalias.nrid AND nickalias.alias=?");
439 $get_authcode_ntf = $dbh->prepare("SELECT 1 FROM nickalias, nicktext
440 WHERE nicktext.nrid=nickalias.nrid AND nicktext.type=".NTF_AUTHCODE
()." AND nickalias.alias=? AND nicktext.data=?");
443 import SrSv
::MySQL
::Stub
{
444 add_profile_ntf
=> ['INSERT', "REPLACE INTO nicktext SELECT nickreg.id, @{[NTF_PROFILE]}, 0, ?, ?
445 FROM nickreg JOIN nickalias ON (nickreg.id=nickalias.nrid) WHERE nickalias.alias=?"],
446 get_profile_ntf
=> ['ARRAY', "SELECT chan, data FROM nicktext
447 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
448 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=?"],
449 del_profile_ntf
=> ['NULL', "DELETE nicktext.* FROM nicktext
450 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
451 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=? AND nicktext.chan=?"],
452 wipe_profile_ntf
=> ['NULL', "DELETE nicktext.* FROM nicktext
453 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
454 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=?"],
455 count_profile_ntf
=> ['SCALAR', "SELECT COUNT(chan) FROM nicktext
456 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
457 WHERE nicktext.type=@{[NTF_PROFILE]} AND nickalias.alias=?"],
459 protect_level
=> ['SCALAR', 'SELECT protect FROM nickalias WHERE alias=?'],
460 get_pass
=> ['SCALAR', "SELECT nickreg.pass
461 FROM nickreg JOIN nickalias ON (nickreg.id=nickalias.nrid)
462 WHERE nickalias.alias=?"],
463 get_email
=> ['SCALAR', "SELECT nickreg.email
464 FROM nickalias JOIN nickreg ON (nickreg.id=nickalias.nrid)
465 WHERE nickalias.alias=?"],
466 count_silences
=> ['SCALAR', "SELECT COUNT(silence.nrid) FROM silence
467 JOIN nickalias ON (silence.nrid=nickalias.nrid)
468 WHERE nickalias.alias=?"],
469 count_watches
=> ['SCALAR', "SELECT COUNT(watch.nrid) FROM watch
470 JOIN nickalias ON (watch.nrid=nickalias.nrid)
471 WHERE nickalias.alias=?"],
473 add_autojoin_ntf
=> ['INSERT', "INSERT INTO nicktext
474 SELECT nickreg.id, @{[NTF_JOIN]}, 0, ?, NULL
475 FROM nickreg JOIN nickalias ON (nickreg.id=nickalias.nrid)
476 WHERE nickalias.alias=?"],
477 get_autojoin_ntf
=> ['COLUMN', "SELECT chan
479 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
480 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=?"],
481 del_autojoin_ntf
=> ['NULL', "DELETE nicktext.* FROM nickreg
482 JOIN nickalias ON (nickalias.nrid=nickreg.id)
483 JOIN nicktext ON (nicktext.nrid=nickreg.id)
484 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=? AND nicktext.chan=?"],
485 check_autojoin_ntf
=> ['SCALAR', "SELECT 1 FROM nicktext
486 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
487 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=? AND nicktext.chan=?"],
488 get_autojoin_by_num
=> ['SCALAR', "SELECT nicktext.chan
490 JOIN nickalias ON (nicktext.nrid=nickalias.nrid)
491 WHERE nicktext.type=@{[NTF_JOIN]} AND nickalias.alias=? LIMIT 1 OFFSET ?"],
495 ### NICKSERV COMMANDS ###
497 sub ns_ajoin_list
($$) {
498 my ($user, $nick)=@_;
501 foreach my $chan (get_autojoin_ntf
($nick)) {
502 push @data, [++$i, $chan];
505 notice
( $user, columnar
( {TITLE
=> "Channels in \002$nick\002's ajoin",
506 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data ) );
508 sub ns_ajoin_del
($$@) {
509 my ($user, $nick, @args) = @_;
511 foreach my $arg (@args) {
512 if ($arg =~ /^[0-9\.,-]+$/) {
513 foreach my $num (makeSeqList
($arg)) {
514 if(my $chan = get_autojoin_by_num
($nick, $num - 1)) {
515 push @entries, $chan;
517 notice
($user, "No entry \002#$num\002 was found in your ajoin list");
524 foreach my $entry (@entries) {
525 if(check_autojoin_ntf
($nick, $entry)) {
526 del_autojoin_ntf
($nick, $entry);
527 notice
($user,"Successfully removed \002$entry\002 from your ajoin list.");
530 notice
($user, "\002$entry\002 was not in your ajoin!");
536 my ($user, $cmd, @args) = @_;
537 my $src = get_user_nick
($user);
538 if(!is_identified
($user, $src)) {
539 if(!is_registered
($src)) {
540 notice
($user, "\002$src\002 is not registered.");
542 notice
($user, "Permission denied for \002$src\002");
545 if ($cmd =~ /^add$/i) {
547 notice
($user, "Syntax: \002AJOIN ADD #channel\002");
548 notice
($user, "Type \002/msg NickServ HELP AJOIN\002 for more help");
550 foreach my $chan (@args) {
551 if (defined($chan) && $chan !~ /^#/) {
554 if(check_autojoin_ntf
($src, $chan)) {
555 notice
($user, $chan . " is already in your ajoin list! ");
558 add_autojoin_ntf
($chan, $src);
559 notice
($user, "\002$chan\002 added to your ajoin.");
563 elsif ($cmd =~ /^list$/i) {
564 ns_ajoin_list
($user, $src);
566 elsif ($cmd =~ /^del(ete)?$/i) {
567 ns_ajoin_del
($user, $src, @args);
570 notice
($user,"Syntax: AJOIN ADD/DEL/LIST");
571 notice
($user,"Type \002/msg NickServ HELP AJOIN\002 for more help!");
576 $nsuser = { NICK
=> $nsnick, ID
=> "123AAAAAB" }; #FIXME = erry
577 my ($user, $dstUser, $msg) = @_;
578 return unless (lc $dstUser->{NICK
} eq lc $nsnick);
580 my @args = split(/\s+/, $msg);
581 my $cmd = shift @args;
583 my $src = $user->{NICK
};
584 $user->{AGENT
} = $dstUser;
585 return if flood_check
($user);
586 if($cmd =~ /^help$/i) {
587 sendhelp
($user, 'nickserv', @args)
589 elsif ($cmd =~ /^ajoin$/i) {
590 ns_ajoin
($user, shift @args, @args);
592 elsif($cmd =~ /^id(entify)?$/i) {
594 ns_identify
($user, $src, $args[0]);
595 } elsif(@args == 2) {
596 ns_identify
($user, $args[0], $args[1]);
598 notice
($user, 'Syntax: IDENTIFY [nick] <password>');
601 elsif($cmd =~ /^sid(entify)?$/i) {
603 ns_identify
($user, $args[0], $args[1], 1);
605 notice
($user, 'Syntax: SIDENTIFY <nick> <password>');
608 elsif($cmd =~ /^gid(entify)?$/i) {
610 ns_identify
($user, $args[0], $args[1], 2);
612 notice
($user, 'Syntax: GIDENTIFY <nick> <password>');
615 elsif($cmd =~ /^logout$/i) {
618 elsif($cmd =~ /^release$/i) {
620 ns_release
($user, $args[0]);
621 } elsif(@args == 2) {
622 ns_release
($user, $args[0], $args[1]);
624 notice
($user, 'Syntax: RELEASE <nick> [password]');
627 elsif($cmd =~ /^ghost$/i) {
629 ns_ghost
($user, $args[0]);
630 } elsif(@args == 2) {
631 ns_ghost
($user, $args[0], $args[1]);
633 notice
($user, 'Syntax: GHOST <nick> [password]');
636 elsif($cmd =~ /^register$/i) {
638 ns_register
($user, $args[0], $args[1]);
640 notice
($user, 'Syntax: REGISTER <password> <email>');
643 elsif($cmd =~ /^(?:link|group)$/i) {
645 ns_link
($user, $args[0], $args[1]);
647 notice
($user, 'Syntax: LINK <nick> <password>');
650 elsif($cmd =~ /^info$/i) {
652 ns_info
($user, @args);
654 notice
($user, 'Syntax: INFO <nick> [nick ...]');
657 elsif($cmd =~ /^set$/i) {
658 ns_set_parse
($user, @args);
660 elsif($cmd =~ /^(drop|unlink)$/i) {
662 ns_unlink
($user, $src, $args[0]);
665 ns_unlink
($user, $args[0], $args[1]);
668 notice
($user, 'Syntax: UNLINK [nick] <password>');
671 elsif($cmd =~ /^dropgroup$/i) {
673 ns_dropgroup
($user, $src, $args[0]);
676 ns_dropgroup
($user, $args[0], $args[1]);
679 notice
($user, 'Syntax: DROPGROUP [nick] <password>');
682 elsif($cmd =~ /^chgroot$/i) {
684 ns_changeroot
($user, $src, $args[0]);
687 ns_changeroot
($user, $args[0], $args[1]);
690 notice
($user, 'Syntax: CHGROOT [oldroot] <newroot>');
693 elsif($cmd =~ /^sendpass$/i) {
695 ns_sendpass
($user, $args[0]);
697 notice
($user, 'Syntax: SENDPASS <nick>');
700 elsif($cmd =~ /^(?:glist|links)$/i) {
702 ns_glist
($user, $src);
705 ns_glist
($user, @args);
708 notice
($user, 'Syntax: GLIST [nick] [nick ...]');
711 elsif($cmd =~ /^(?:alist|listchans)$/i) {
713 ns_alist
($user, $src);
716 ns_alist
($user, @args);
719 notice
($user, 'Syntax: ALIST [nick] [nick ...]');
722 elsif($cmd =~ /^list$/i) {
724 ns_list
($user, $args[0]);
726 notice
($user, 'Syntax: LIST <mask>');
729 elsif($cmd =~ /^watch$/i) {
730 if ($args[0] =~ /^(add|del|list)$/i) {
731 ns_watch
($user, $src, @args);
733 elsif ($args[1] =~ /^(add|del|list)$/i) {
734 ns_watch
($user, @args);
737 notice
($user, 'Syntax: WATCH <ADD|DEL|LIST> [nick]');
740 elsif($cmd =~ /^silence$/i) {
741 if ($args[0] =~ /^(add|del|list)$/i) {
742 ns_silence
($user, $src, @args);
744 elsif ($args[1] =~ /^(add|del|list)$/i) {
745 ns_silence
($user, @args);
748 notice
($user, 'Syntax: SILENCE [nick] <ADD|DEL|LIST> [mask] [+expiry] [comment]');
751 elsif($cmd =~ /^(acc(ess)?|stat(us)?)$/i) {
753 ns_acc
($user, @args);
756 notice
($user, 'Syntax: ACC <nick> [nick ...]');
759 elsif($cmd =~ /^seen$/i) {
761 ns_seen
($user, @args);
764 notice
($user, 'Syntax: SEEN <nick> [nick ...]');
767 elsif($cmd =~ /^recover$/i) {
769 ns_recover
($user, $args[0]);
770 } elsif(@args == 2) {
771 ns_recover
($user, $args[0], $args[1]);
773 notice
($user, 'Syntax: RECOVER <nick> [password]');
776 elsif($cmd =~ /^auth$/i) {
778 ns_auth
($user, @args);
781 notice
($user, 'Syntax: AUTH [nick] <LIST|ACCEPT|DECLINE> [num|chan]');
784 elsif($cmd =~ /^(?:emailreg|(?:auth|email)code)$/i) {
785 if(scalar(@args) >= 2 and scalar(@args) <= 3) {
786 ns_authcode
($user, @args);
788 notice
($user, 'Syntax: AUTHCODE <nick> <code> [newpassword]');
791 elsif($cmd =~ /^profile$/i) {
792 ns_profile
($user, @args);
795 notice
($user, "Unrecognized command.", "For help, type: \002/msg nickserv help\002");
796 wlog
($nsnick, LOG_DEBUG
(), "$src tried to use NickServ $msg");
800 sub ns_identify
($$$;$) {
801 my ($user, $nick, $pass, $svsnick) = @_;
802 my $src = get_user_nick
($user);
804 my $root = get_root_nick
($nick);
806 notice
($user, 'Your nick is not registered.');
811 if(lc($src) ne lc($nick) and is_online
($nick)) {
813 ns_ghost
($user, $nick, $pass) or return;
815 notice
($user, $nick.' is already in use. Please use GHOST, GIDENTIFY or RECOVER');
819 if (is_identified
($user, $nick)) {
820 if(lc $src eq lc $nick) {
821 notice
($user, "Cannot only change case of nick");
824 ircd
::svsnick
($nsuser, $user, $nick);
825 ircd
::setumode
($nsuser, $user, '+r');
829 # cannot be an else, note change of $svsnick above.
830 if (!$svsnick and is_identified
($user, $nick)) {
831 notice
($user, 'You are already identified for nick '.$nick.'.');
835 my $flags = nr_get_flags
($root);
837 if($flags & NRF_FREEZE
) {
838 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
839 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to identify to frozen nick \003\002$nick\002", $user);
843 if($flags & NRF_EMAILREG
) {
844 notice
($user, "This nick is awaiting an email validation code. Please check your email for instructions.");
848 elsif($flags & NRF_SENDPASS
) {
849 notice
($user, "This nick is awaiting a SENDPASS authentication code. Please check your email for instructions.");
853 my $uid = get_user_id
($user);
854 unless(chk_pass
($root, $pass, $user)) {
855 if(inc_nick_inval
($user)) {
856 notice
($user, $err_pass);
858 services
::ulog
($nsnick, LOG_INFO
(), "failed to identify to nick $nick (root: $root)", $user);
862 return do_identify
($user, $nick, $root, $flags, $svsnick);
867 my $uid = get_user_id
($user);
869 $update_lastseen->execute($uid);
870 $logout->execute($uid);
871 delete($user->{NICKFLAGS
});
872 ircd
::nolag
($nsnick, '-', $user);
873 notice
($user, 'You are now logged out');
874 services
::ulog
($nsnick, LOG_INFO
(), "used NickServ LOGOUT", $user);
877 sub ns_release
($$;$) {
878 my ($user, $nick, $pass) = @_;
880 if(nr_chk_flag
($nick, NRF_FREEZE
)) {
881 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
882 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to release frozen nick \003\002$nick\002", $user);
886 unless(is_identified
($user, $nick)) {
888 my $s = ns_identify
($user, $nick, $pass);
889 return if($s == 0); #failed to identify
891 notice
($user, "Nick $nick is not being held.");
895 notice
($user, $err_deny);
899 elsif(enforcer_quit
($nick)) {
900 notice
($user, 'Your nick has been released from custody.');
902 notice
($user, "Nick $nick is not being held.");
908 my @ghostbusters_quotes = (
909 'Ray. If someone asks if you are a god, you say, "yes!"',
910 'I feel like the floor of a taxicab.',
911 'I don\'t have to take this abuse from you, I\'ve got hundreds of people dying to abuse me.',
913 'This chick is *toast*.',
914 '"Where do these stairs go?" "They go up."',
915 '"That\'s the bedroom, but nothing ever happened in there." "What a crime."',
916 'NOBODY steps on a church in my town.',
917 'Whoa, whoa, whoa! Nice shootin\', Tex!',
918 'It\'s the Stay Puft Marshmallow Man.',
919 '"Symmetrical book stacking. Just like the Philadelphia mass turbulence of 1947." "You\'re right, no human being would stack books like this."',
920 '"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."',
921 '"Ray has gone bye-bye, Egon... what\'ve you got left?" "Sorry, Venkman, I\'m terrified beyond the capacity for rational thought."',
922 'Listen! Do you smell something?',
923 '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?',
924 '"You know, you don\'t act like a scientist." "They\'re usually pretty stiff." "You\'re more like a game show host."',
926 my ($user, $nick, $pass) = @_;
927 my $src = get_user_nick
($user);
929 if(nr_chk_flag
($nick, NRF_FREEZE
)) {
930 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
931 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to ghost frozen nick \003\002$nick\002", $user);
935 unless(is_identified
($user, $nick)) {
937 my $s = ns_identify
($user, $nick, $pass);
938 return 0 if($s == 0); #failed to identify
940 notice
($user, $err_deny);
945 if(!is_online
($nick)) {
946 notice
($user, "\002$nick\002 is not online");
948 } elsif(lc $src eq lc $nick) {
949 notice
($user, "I'm sorry, $src, I'm afraid I can't do that.");
953 my $ghostbusters = @ghostbusters_quotes[int rand(scalar(@ghostbusters_quotes))];
954 ircd
::irckill
($nsuser, $user, "GHOST command used by $src ($ghostbusters)");
955 notice
($user, "Your ghost has been disconnected");
956 services
::ulog
($nsnick, LOG_INFO
(), "used NickServ GHOST on $nick", $user);
962 sub ns_register
($$$) {
963 my ($user, $pass, $email) = @_;
964 my $src = get_user_nick
($user);
966 if($src =~ /^guest/i) {
967 notice
($user, $err_deny);
971 unless(validate_email
($email)) {
972 notice
($user, $err_email);
976 if ($pass =~ /pass/i) {
977 notice
($user, 'Try a more secure password.');
981 my $uid = get_user_id
($user);
983 $get_register_lock->execute; $get_register_lock->finish;
985 if(not is_registered
($src)) {
986 $register->execute($src, hash_pass
($pass), $email); $register->finish();
987 $create_alias->execute($src, $src); $create_alias->finish;
988 if (defined(services_conf_default_protect
)) {
989 $set_protect_level->execute((defined(services_conf_default_protect
) ?
990 $protect_level{lc services_conf_default_protect
} : 1), $src);
991 $set_protect_level->finish();
993 $unlock_tables->execute; $unlock_tables->finish;
995 if(services_conf_validate_email
) {
996 nr_set_flag
($src, NRF_EMAILREG
());
997 authcode
($src, 'emailreg', $email);
998 notice
($user, "Your registration is not yet complete.",
999 "Your nick will expire within ".
1000 (services_conf_validate_expire
== 1 ? '24 hours' : services_conf_validate_expire
.' days').
1001 " if you do not enter the validation code.",
1002 "Check your email for further instructions.");
1005 $identify->execute($uid, $src); $identify->finish();
1006 notice
($user, 'You are now registered and identified.');
1007 ircd
::setumode
($nsuser, $user, '+r');
1010 $id_update->execute($src, $uid); $id_update->finish();
1011 services
::ulog
($nsuser, LOG_INFO
(), "registered $src (email: $email)".
1012 (services_conf_validate_email
? ' requires email validation code' : ''),
1015 $unlock_tables->execute; $unlock_tables->finish;
1016 notice
($user, 'Your nickname has already been registered.');
1021 my ($user, $nick, $pass) = @_;
1023 my $root = get_root_nick
($nick);
1024 my $src = get_user_nick
($user);
1025 my $uid = get_user_id
($user);
1027 if($src =~ /^guest/i) {
1028 notice
($user, $err_deny);
1032 unless (is_registered
($nick)) {
1033 if(is_registered
($src)) {
1034 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.");
1035 } else { # if neither $nick nor $src are registered
1036 notice
($user, "You need to register your nick first. For help, type \002/ns help register");
1041 unless(chk_pass
($root, $pass, $user)) {
1042 notice
($user, $err_pass);
1046 if(nr_chk_flag
($nick, NRF_FREEZE
) and (lc $pass ne 'force')) {
1047 notice
($user, "\002$root\002 has been frozen and may not be used.");
1051 if(is_alias_of
($src, $nick)) {
1052 notice
($user, "\002$nick\002 is already linked to \002$src\002.");
1056 $get_register_lock->execute; $get_register_lock->finish;
1058 if(is_registered
($src)) {
1059 $unlock_tables->execute; $unlock_tables->finish;
1061 if(is_identified
($user, $src)) {
1062 notice
($user, "You cannot link an already registered nick. Type this and try again: \002/ns drop $src <password>");
1065 notice
($user, 'Your nickname has already been registered.');
1069 $create_alias->execute($src, $root); $create_alias->finish();
1070 if (defined(services_conf_default_protect
)) {
1071 $set_protect_level->execute((defined(services_conf_default_protect
) ?
1072 $protect_level{lc services_conf_default_protect
} : 1), $src);
1073 $set_protect_level->finish();
1075 $unlock_tables->execute; $unlock_tables->finish;
1077 if(is_identified
($user, $root)) {
1078 $identify_ign->execute($uid, $root); $identify_ign->finish();
1079 $id_update->execute($root, $uid); $id_update->finish();
1081 ns_identify
($user, $root, $pass);
1085 notice
($user, "\002$src\002 is now linked to \002$root\002.");
1086 services
::ulog
($nsnick, LOG_INFO
(), "made $src an alias of $root.", $user);
1088 check_identify
($user);
1091 sub ns_unlink
($$$) {
1092 my ($user, $nick, $pass) = @_;
1093 my $uid = get_user_id
($user);
1094 my $src = get_user_nick
($user);
1096 my $root = get_root_nick
($nick);
1097 unless(chk_pass
($root, $pass, $user)) {
1098 notice
($user, $err_pass);
1102 if(nr_chk_flag
($nick, NRF_FREEZE
) and (lc $pass ne 'force')) {
1103 notice
($user, "\002$root\002 has been frozen and may not be used.", $err_deny);
1104 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to unlink \002$nick\002 from frozen nick \002$root\002", $user);
1108 if(lc $root eq lc $nick) {
1109 $count_aliases->execute($root);
1110 my ($count) = $count_aliases->fetchrow_array;
1112 ns_dropgroup_real
($user, $root);
1116 $get_random_alias->execute($root);
1117 my ($new) = $get_random_alias->fetchrow_array;
1118 ns_changeroot
($user, $root, $new, 1);
1123 unidentify_single
($nick);
1124 delete_alias
($nick);
1125 enforcer_quit
($nick);
1127 notice
($user, "\002$nick\002 has been unlinked from \002$root\002.");
1128 services
::ulog
($nsnick, LOG_INFO
(), "removed alias $nick from $root.", $user);
1131 sub ns_dropgroup
($$$) {
1132 my ($user, $nick, $pass) = @_;
1133 my $uid = get_user_id
($user);
1134 my $src = get_user_nick
($user);
1135 my $root = get_root_nick
($nick);
1137 if(adminserv
::get_svs_level
($root)) {
1138 notice
($user, "A nick with services access may not be dropped.");
1142 unless(chk_pass
($root, $pass, $user)) {
1143 notice
($user, $err_pass);
1147 if(nr_chk_flag
($nick, NRF_FREEZE
) and (lc $pass ne 'force')) {
1148 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
1149 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to dropgroup frozen nick \002$root\002", $user);
1153 ns_dropgroup_real
($user, $root);
1156 sub ns_dropgroup_real
($$) {
1157 my ($user, $root) = @_;
1158 my $src = get_user_nick
($user);
1160 unidentify
($root, "Your nick, \002$root\002, was dropped by \002$src\002.", $src);
1162 #enforcer_quit($nick);
1163 notice
($user, "Your nick(s) have been dropped. Thanks for playing.");
1165 services
::ulog
($nsnick, LOG_INFO
(), "dropped group $root.", $user);
1168 sub ns_changeroot
($$$;$) {
1169 my ($user, $old, $new, $force) = @_;
1171 $force or chk_identified
($user, $old) or return;
1173 my $root = get_root_nick
($old);
1175 if(lc($new) eq lc($root)) {
1176 notice
($user, "\002$root\002 is already your root nick.");
1180 unless(get_root_nick
($new) eq $root) {
1181 notice
($user, "\002$new\002 is not an alias of your nick. Type \002/msg nickserv help link\002 for information about creating aliases.");
1185 changeroot
($root, $new);
1187 notice
($user, "Your root nick is now \002$new\002.");
1188 services
::ulog
($nsnick, LOG_INFO
(), "changed root $root to $new.", $user);
1192 my ($user, @nicks) = @_;
1194 foreach my $nick (@nicks) {
1195 my $root = get_root_nick
($nick);
1197 $get_info->execute($nick);
1198 my @result = $get_info->fetchrow_array;
1199 $get_info->finish();
1202 notice
($user, "The nick \002$nick\002 is not registered.");
1206 my ($email, $regd, $last, $flags, $ident, $vhost, $gecos, $alias_used) = @result;
1207 # the quit entry might not exist if the user hasn't quit yet.
1208 $get_nickreg_quit->execute($nick);
1209 my ($quit) = $get_nickreg_quit->fetchrow_array(); $get_nickreg_quit->finish();
1210 my $hidemail = $flags & NRF_HIDEMAIL
;
1212 $get_greet_nick->execute($nick);
1213 my ($greet) = $get_greet_nick->fetchrow_array(); $get_greet_nick->finish();
1214 $get_umode_ntf->execute($nick);
1215 my ($umode) = $get_umode_ntf->fetchrow_array(); $get_umode_ntf->finish();
1217 my $svslev = adminserv
::get_svs_level
($root);
1218 my $protect = protect_level
($nick);
1219 my $showprivate = (is_identified
($user, $nick) or
1220 adminserv
::is_svsop
($user, adminserv
::S_HELP
()));
1222 my ($seens, $seenm) = do_seen
($nick);
1226 push @data, {FULLROW
=>"(Online now, $seenm.)"} if $seens == 2;
1227 push @data, ["Last seen:", "$seenm."] if $seens == 1;
1230 ["Last seen address:", "$ident\@$vhost"],
1231 ["Registered:", gmtime2
($regd)];
1232 push @data, ["Last used:", ($alias_used ? gmtime2
($alias_used) : 'Unknown')] if $showprivate;
1233 push @data, ["Last real name:", $gecos];
1235 push @data, ["Services Rank:", $adminserv::levels
[$svslev]]
1237 push @data, ["E-mail:", $email] unless $hidemail;
1238 push @data, ["E-mail:", "$email (Hidden)"]
1239 if($hidemail and $showprivate);
1240 push @data, ["Alias of:", $root]
1241 if ((lc $root ne lc $nick) and $showprivate);
1245 push @extra, "Last quit: $quit" if $quit;
1246 push @extra, $protect_long[$protect] if $protect;
1247 push @extra, "Does not accept memos." if($flags & NRF_NOMEMO
);
1248 push @extra, "Cannot be added to channel access lists." if($flags & NRF_NOACC
);
1249 push @extra, "Will not be automatically opped in channels." if($flags & NRF_NEVEROP
);
1250 push @extra, "Requires authorization to be added to channel access lists."
1251 if($flags & NRF_AUTH
);
1252 push @extra, "Is frozen and may not be used." if($flags & NRF_FREEZE
);
1253 push @extra, "Will not expire." if($flags & NRF_HOLD
);
1254 push @extra, "Is currently on vacation." if($flags & NRF_VACATION
);
1255 push @extra, "Registration pending email-code verification." if($flags & NRF_EMAILREG
);
1256 push @extra, "UModes on Identify: ".$umode if ($umode and $showprivate);
1257 push @extra, "Greeting: ".$greet if ($greet and $showprivate);
1258 push @extra, "Disabled highlighting of alternating lines." if ($flags & NRF_NOHIGHLIGHT
);
1260 notice
($user, columnar
({TITLE
=> "NickServ info for \002$nick\002:",
1261 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)},
1262 @data, {COLLAPSE
=> \
@extra, BULLET
=> 1}));
1266 sub ns_set_parse
($@) {
1267 my ($user, @parms) = @_;
1268 my $src = get_user_nick
($user);
1269 # This is a new NS SET parser
1270 # required due to it's annoying syntax
1272 # Most commands have only 2 params at most
1273 # the target (which is implied to be src when not spec'd)
1274 # However in the case of GREET num-params is unbounded
1276 # Alternative parsings would be possible,
1277 # one being to use a regexp for valid set/keys
1278 if (lc($parms[1]) eq 'greet') {
1279 ns_set
($user, @parms);
1281 elsif(lc($parms[0]) eq 'greet') {
1282 ns_set
($user, $src, @parms);
1286 ns_set
($user, $src, $parms[0], $parms[1]);
1288 elsif(@parms == 3) {
1289 ns_set
($user, $parms[0], $parms[1], $parms[2]);
1292 notice
($user, 'Syntax: SET [nick] <option> <value>');
1299 my ($user, $target, $set, @parms) = @_;
1300 my $src = get_user_nick
($user);
1301 my $override = (adminserv
::can_do
($user, 'SERVOP') or
1302 (adminserv
::can_do
($user, 'FREEZE') and $set =~ /^freeze$/i) ? 1 : 0);
1304 unless(is_registered
($target)) {
1305 notice
($user, "\002$target\002 is not registered.");
1308 unless(is_identified
($user, $target) or $override) {
1309 notice
($user, $err_deny);
1314 $set =~ /^protect$/i or
1315 $set =~ /^e?-?mail$/i or
1316 $set =~ /^pass(?:w(?:or)?d)?$/i or
1317 $set =~ /^hidee?-?mail$/i or
1318 $set =~ /^nomemo$/i or
1319 $set =~ /^no(?:acc|op)$/i or
1320 $set =~ /^neverop$/i or
1321 $set =~ /^auth$/i or
1322 $set =~ /^(hold|no-?expire)$/i or
1323 $set =~ /^freeze$/i or
1324 $set =~ /^vacation$/i or
1325 $set =~ /^greet$/i or
1326 $set =~ /^u?modes?$/i or
1327 $set =~ /^(email)?reg$/i or
1328 $set =~ /^nohighlight$/i or
1329 $set =~ /^(?:(?:chg)?root|display)$/i
1331 notice
($user, qq{"$set" is not a valid NickServ setting.});
1336 if($src eq $target) {
1340 $subj="\002$target\002\'s";
1341 $obj="\002$target\002";
1343 delete($user->{NICKFLAGS
});
1345 if($set =~ /^protect$/i) {
1346 my $level = $protect_level{lc shift @parms};
1347 unless (defined($level)) {
1348 notice
($user, "Syntax: SET PROTECT <none|normal|high|kill>");
1352 $set_protect_level->execute($level, $target);
1353 notice
($user, "$subj protection level is now set to \002".$protect_short[$level]."\002. ".$protect_long[$level]);
1358 elsif($set =~ /^e?-?mail$/i) {
1359 unless(@parms == 1) {
1360 notice
($user, 'Syntax: SET EMAIL <address>');
1363 my $email = $parms[0];
1365 unless(validate_email
($email)) {
1366 notice
($user, $err_email);
1370 $set_email->execute($email, $target);
1371 notice
($user, "$subj email address has been changed to \002$email\002.");
1372 services
::ulog
($nsnick, LOG_INFO
(), "changed email of \002$target\002 to $email", $user);
1377 elsif($set =~ /^pass(?:w(?:or)?d)?$/i) {
1378 unless(@parms == 1) {
1379 notice
($user, 'Syntax: SET PASSWD <address>');
1382 if($parms[0] =~ /pass/i) {
1383 notice
($user, 'Try a more secure password.');
1386 $set_pass->execute(hash_pass
($parms[0]), $target);
1387 notice
($user, "$subj password has been changed.");
1388 services
::ulog
($nsnick, LOG_INFO
(), "changed password of \002$target\002", $user);
1389 if(nr_chk_flag
($target, NRF_SENDPASS
())) {
1390 $del_nicktext->execute(NTF_AUTHCODE
, $target); $del_nicktext->finish();
1391 nr_set_flag
($target, NRF_SENDPASS
(), 0);
1397 elsif($set =~ /^greet$/i) {
1399 notice
($user, 'Syntax: SET [nick] GREET <NONE|greeting>');
1403 my $greet = join(' ', @parms);
1404 if ($greet =~ /^(none|off)$/i) {
1405 $del_greet->execute($target);
1406 notice
($user, "$subj greet has been deleted.");
1407 services
::ulog
($nsnick, LOG_INFO
(), "deleted greet of \002$target\002", $user);
1410 $set_greet->execute($greet, $target);
1411 notice
($user, "$subj greet has been set to \002$greet\002");
1412 services
::ulog
($nsnick, LOG_INFO
(), "changed greet of \002$target\002", $user);
1417 elsif($set =~ /^u?modes?$/i) {
1418 unless(@parms == 1) {
1419 notice
($user, 'Syntax: SET UMODE <+modes-modes|none>');
1423 if (lc $parms[0] eq 'none') {
1424 $del_nicktext->execute(NTF_UMODE
, $target); $del_nicktext->finish();
1425 notice
($user, "$obj will not receive any automatic umodes.");
1428 my ($modes, $rejected) = modes
::allowed_umodes
($parms[0]);
1429 $del_nicktext->execute(NTF_UMODE
, $target); $del_nicktext->finish(); # don't allow dups
1430 $set_umode_ntf->execute($modes, $target); $set_umode_ntf->finish();
1431 foreach my $usernick (get_nick_user_nicks
$target) {
1432 ircd
::setumode
($nsuser, $user, $modes)
1436 push @out, "Cannot set these umodes: " . $rejected if $rejected;
1437 push @out, "$subj automatic umodes have been set to: \002" . ($modes ? $modes : 'none');
1438 notice
($user, @out);
1442 elsif($set =~ /^(?:(?:chg)?root|display)$/i) {
1443 ns_changeroot
($user, $target, $parms[0], $override);
1448 if($parms[0] =~ /^(?:no|off|false|0)$/i) { $val = 0; }
1449 elsif($parms[0] =~ /^(?:yes|on|true|1)$/i) { $val = 1; }
1451 notice
($user, "Please say \002on\002 or \002off\002.");
1455 if($set =~ /^hidee?-?mail$/i) {
1456 nr_set_flag
($target, NRF_HIDEMAIL
, $val);
1459 notice
($user, "$subj email address is now hidden.");
1461 notice
($user, "$subj email address is now visible.");
1467 if($set =~ /^nomemo$/i) {
1468 nr_set_flag
($target, NRF_NOMEMO
, $val);
1471 notice
($user, "$subj memos will be blocked.");
1473 notice
($user, "$subj memos will be delivered.");
1479 if($set =~ /^no(?:acc|op)$/i) {
1480 nr_set_flag
($target, NRF_NOACC
, $val);
1483 notice
($user, "$obj may not be added to channel access lists.");
1485 notice
($user, "$obj may be added to channel access lists.");
1491 if($set =~ /^neverop$/i) {
1492 nr_set_flag
($target, NRF_NEVEROP
, $val);
1495 notice
($user, "$obj will not be granted status upon joining channels.");
1497 notice
($user, "$obj will be granted status upon joining channels.");
1503 if($set =~ /^auth$/i) {
1504 nr_set_flag
($target, NRF_AUTH
, $val);
1507 notice
($user, "$obj must now authorize additions to channel access lists.");
1509 notice
($user, "$obj will not be asked to authorize additions to channel access lists.");
1515 if($set =~ /^(hold|no-?expire)$/i) {
1516 unless (adminserv
::can_do
($user, 'SERVOP') or
1517 is_identified
($user, $target) and adminserv
::is_ircop
($user))
1519 notice
($user, $err_deny);
1523 nr_set_flag
($target, NRF_HOLD
, $val);
1526 notice
($user, "\002$target\002 is now held from expiration.");
1527 services
::ulog
($nsnick, LOG_INFO
(), "has held \002$target\002", $user);
1529 notice
($user, "\002$target\002 will now expire normally.");
1530 services
::ulog
($nsnick, LOG_INFO
(), "released \002$target\002 from hold", $user);
1536 if($set =~ /^freeze$/i) {
1537 unless (adminserv
::can_do
($user, 'FREEZE') or
1538 is_identified
($user, $target) and adminserv
::is_ircop
($user))
1540 notice
($user, $err_deny);
1544 nr_set_flag
($target, NRF_FREEZE
, $val);
1547 notice
($user, "\002$target\002 is now frozen.");
1548 unidentify
($target, "Your nick, \002$target\002, has been frozen and may no longer be used.");
1549 services
::ulog
($nsnick, LOG_INFO
(), "froze \002$target\002", $user);
1551 notice
($user, "\002$target\002 is no longer frozen.");
1552 services
::ulog
($nsnick, LOG_INFO
(), "unfroze \002$target\002", $user);
1558 if($set =~ /^vacation$/i) {
1560 $get_regd_time->execute($target);
1561 my ($regd) = $get_regd_time->fetchrow_array;
1562 $get_regd_time->finish();
1564 if(($regd > (time() - 86400 * int(services_conf_vacationexpire
/ 3))) and !$override) {
1565 notice
($user, "$target is not old enough to use VACATION",
1566 'Minimum age is '.int(services_conf_vacationexpire
/ 3).' days');
1570 $get_vacation_ntf->execute($target);
1571 my ($last_vacation) = $get_vacation_ntf->fetchrow_array();
1572 $get_vacation_ntf->finish();
1573 if(defined($last_vacation)) {
1574 $last_vacation = unpack('N', MIME
::Base64
::decode
($last_vacation));
1575 if ($last_vacation > (time() - 86400 * int(services_conf_vacationexpire
/ 3)) and !$override) {
1576 notice
($user, "I'm sorry, \002$src\002, I'm afraid I can't do that.",
1577 "Last vacation ended ".gmtime2
($last_vacation),
1578 'Minimum time between vacations is '.int(services_conf_vacationexpire
/ 3).' days.');
1584 nr_set_flag
($target, NRF_VACATION
, $val);
1586 services
::ulog
($nsnick, LOG_INFO
(),
1587 ($val ? 'enabled' : 'disabled')." vacation mode for \002$target\002", $user);
1588 notice
($user, "Vacation mode ".($val ? 'enabled' : 'disabled')." for \002$target\002");
1592 if($set =~ /^(email)?reg$/i) {
1593 unless (adminserv
::can_do
($user, 'SERVOP'))
1595 notice
($user, $err_deny);
1599 nr_set_flag
($target, NRF_EMAILREG
, $val);
1602 authcode
($target, 'emailreg');
1603 notice
($user, "\002$target\002 now needs an email validation code.");
1604 unidentify
($target, ["Your nick, \002$target\002, has been flagged for an email validation audit.",
1605 "Your nick will expire within 24 hours if you do not enter the validation code.",
1606 "Check your email for further instructions."]);
1607 services
::ulog
($nsnick, LOG_INFO
(), "requested an email audit for \002$target\002", $user);
1609 $del_nicktext->execute(NTF_AUTHCODE
, $target); $del_nicktext->finish();
1610 notice
($user, "\002$target\002 is now fully registered.");
1611 services
::ulog
($nsnick, LOG_INFO
(), "validated the email for \002$target\002", $user);
1617 if($set =~ /^nohighlight$/i) {
1618 nr_set_flag
($target, NRF_NOHIGHLIGHT
, $val);
1621 notice
($user, "$obj will no longer have alternative highlighting of lists.");
1623 notice
($user, "$obj will have alternative highlighting of lists.");
1631 sub ns_sendpass
($$) {
1632 my ($user, $nick) = @_;
1634 unless(adminserv
::is_svsop
($user, adminserv
::S_HELP
() )) {
1635 notice
($user, $err_deny);
1639 my $email = get_email
($nick);
1642 notice
($user, "\002$nick\002 is not registered or does not have an email address.");
1646 my $pass = get_pass
($nick);
1647 if ($pass and !is_hashed
($pass)) {
1648 send_email
($email, "$nsnick Password Reminder",
1649 "The password for the nick $nick is:\n$pass");
1650 notice
($user, "Password for \002$nick\002 has been sent to \002$email\002.");
1652 authcode
($nick, 'sendpass', $email);
1653 nr_set_flag
($nick, NRF_SENDPASS
);
1654 notice
($user, "Password authentication code for \002$nick\002 has been sent to \002$email\002.");
1657 services
::ulog
($nsnick, LOG_INFO
(), "used SENDPASS on $nick ($email)", $user);
1661 my ($user, @targets) = @_;
1663 foreach my $target (@targets) {
1664 my $root = get_root_nick
($target);
1666 notice
$user, "\002$target\002 is not registered.";
1670 unless(is_identified
($user, $target) or
1671 adminserv
::is_svsop
($user, adminserv
::S_HELP
())
1673 notice
$user, "$target: $err_deny";
1678 $get_glist->execute($root);
1679 while(my ($alias, $protect, $last) = $get_glist->fetchrow_array) {
1682 # This needs a new NS GLIST cmd, like NS GLISTA or something.
1683 # The idea is a command that shows the long version of the time_ago.
1684 $time_ago = time_ago
($last, 1);
1686 $time_ago = time_ago
($last);
1688 push @data, ["\002$alias\002", "Protect: $protect_short[$protect]",
1689 ($last ? "Last used $time_ago ago" : '')
1693 notice
$user, columnar
{TITLE
=> "Group list for \002$root\002 (" . $get_glist->rows . " nicks):",
1694 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
1696 $get_glist->finish();
1701 my ($user, @targets) = @_;
1703 foreach my $target (@targets) {
1704 (adminserv
::is_svsop
($user, adminserv
::S_HELP
()) and (
1705 chk_registered
($user, $target) or next)
1706 ) or chk_identified
($user, $target) or next;
1710 $get_all_access->execute($target);
1711 while(my ($c, $l, $a, $t) = $get_all_access->fetchrow_array) {
1713 push @data, [$c, $chanserv::plevels
[$l+$chanserv::plzero
], ($a ? "($a)" : ''),
1717 notice
$user, columnar
{TITLE
=> "Access listing for \002$target\002 (".scalar(@data)." entries)",
1718 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
1723 my ($user, $mask) = @_;
1725 unless(adminserv
::is_svsop
($user, adminserv
::S_HELP
())) {
1726 notice
($user, $err_deny);
1730 my ($mnick, $mident, $mhost) = glob2sql
(parse_mask
($mask));
1732 $mnick = '%' if($mnick eq '');
1733 $mident = '%' if($mident eq '');
1734 $mhost = '%' if($mhost eq '');
1737 $get_matching_nicks->execute($mnick, $mident, $mhost);
1738 while(my ($rnick, $rroot, $rident, $rhost) = $get_matching_nicks->fetchrow_array) {
1739 push @data, [$rnick, ($rroot ne $rnick ? $rroot : ''), $rident . '@' . $rhost];
1742 notice
$user, columnar
{TITLE
=> "Registered nicks matching \002$mask\002:",
1743 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
1746 sub ns_watch
($$$;$) {
1747 my ($user, $target, $cmd, $mask) = @_;
1748 my $src = get_user_nick
($user);
1750 my $root = get_root_nick
($target);
1752 notice
($user, "\002$target\002 is not registered.");
1755 unless(is_identified
($user, $target)) {
1756 notice
($user, $err_deny);
1760 if ($cmd =~ /^add$/i) {
1761 my $max_watches = $IRCd_capabilities{WATCH
}; # load here for caching.
1762 if(count_watches
($root) >= $max_watches) {
1763 notice
($user, "WATCH list for $target full, there is a limit of $max_watches. Please trim your list.");
1767 if($mask =~ /\!/ or $mask =~ /\@/) {
1768 my ($mnick, $mident, $mhost) = parse_mask
($mask);
1769 if ($mnick =~ /\*/) {
1770 notice
($user, "Invalid mask: \002$mask\002",
1771 'A WATCH mask cannot wildcard the nick.');
1776 $check_watch->execute($root, $mask);
1777 if ($check_watch->fetchrow_array) {
1778 notice
($user, "\002$mask\002 is already in \002$target\002's watch list.");
1782 $set_watch->execute($mask, time(), $root);
1783 ircd
::svswatch
($nsuser, $user, "+$mask");
1784 notice
($user, "\002$mask\002 added to \002$target\002's watch list.");
1787 elsif ($cmd =~ /^del(ete)?$/i) {
1788 $check_watch->execute($root, $mask);
1789 unless ($check_watch->fetchrow_array) {
1790 notice
($user, "\002$mask\002 is not in \002$target\002's watch list.");
1793 $del_watch->execute($root, $mask);
1794 ircd
::svswatch
($nsuser, $user, "-$mask");
1795 notice
($user, "\002$mask\002 removed from \002$target\002's watch list.");
1797 elsif ($cmd =~ /^list$/i) {
1800 $get_watches->execute($root);
1801 while(my ($mask, $time) = $get_watches->fetchrow_array) {
1802 push @data, [$mask, gmtime2
($time)];
1805 notice
$user, columnar
{TITLE
=> "Watch list for \002$target\002:",
1806 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
1809 notice
($user, 'Syntax: WATCH <ADD|DEL|LIST> [nick]');
1813 sub ns_silence
($$$;$@) {
1814 my ($user, $target, $cmd, $mask, @args) = @_;
1815 my ($expiry, $comment);
1816 my $src = get_user_nick
($user);
1818 sub get_silence_by_num
($$) {
1819 # This one cannot be converted to SrSv::MySQL::Stub, due to bind_param call
1820 my ($nick, $num) = @_;
1821 $get_silence_by_num->execute($nick, $num-1);
1822 my ($mask) = $get_silence_by_num->fetchrow_array();
1823 $get_silence_by_num->finish();
1827 my $root = get_root_nick
($target);
1829 notice
($user, "\002$target\002 is not registered.");
1833 unless(is_identified
($user, $target)) {
1834 notice
($user, $err_deny);
1838 if ($cmd =~ /^add$/i) {
1839 my $max_silences = $IRCd_capabilities{SILENCE
};
1840 if(count_silences
($root) >= $max_silences) {
1841 notice
($user, "SILENCE list for $target full, there is a limit of $max_silences. Please trim your list.");
1845 if (substr($args[0],0,1) eq '+') {
1846 $expiry = shift @args;
1848 elsif (substr($args[-1],0,1) eq '+') {
1849 $expiry = pop @args;
1851 $comment = join(' ', @args);
1853 if($mask !~ /[!@.]/) {
1854 my $target_user = { NICK
=> $mask };
1855 unless(get_user_id
($target_user)) {
1856 notice
($user, qq{"\002$mask\002" is not a known user, nor a valid hostmask.});
1859 $comment = $mask unless $comment;
1861 my ($ident, $vhost) = get_vhost
($target_user);
1862 my ($nick, $ident, $vhost) = make_hostmask
(10, $mask, $ident, $vhost);
1863 $mask = $nick.'!'.$ident.'@'.$vhost;
1866 $mask = normalize_hostmask
($mask);
1869 if("$nsnick!services\@".main_conf_local
=~ hostmask_to_regexp
($mask)) {
1870 notice
($user, "You shouldn't add NickServ to your SILENCE list.");
1874 $check_silence->execute($root, $mask);
1875 if ($check_silence->fetchrow_array) {
1876 notice
($user, "\002$mask\002 is already in \002$target\002's SILENCE list.");
1880 if(defined $expiry) {
1881 $expiry = parse_time
($expiry) + time();
1886 $set_silence->execute($mask, time(), $expiry, $comment, $root);
1887 ircd
::svssilence
($nsuser, $user, "+$mask");
1888 notice
($user, "\002$mask\002 added to \002$target\002's SILENCE list.");
1890 elsif ($cmd =~ /^del(ete)?$/i) {
1892 if ($mask =~ /^[0-9\.,-]+$/) {
1893 foreach my $num (makeSeqList
($mask)) {
1894 push @masks, get_silence_by_num
($root, $num) or next;
1896 if(scalar(@masks) == 0) {
1897 notice
($user, "Unable to find any silences matching $mask");
1903 my @reply; my @out_masks;
1904 foreach my $mask (@masks) {
1905 $check_silence->execute($root, $mask);
1906 unless ($check_silence->fetchrow_array) {
1907 $mask = normalize_hostmask
($mask);
1909 $check_silence->execute($root, $mask);
1910 unless ($check_silence->fetchrow_array) {
1911 push @reply, "\002$mask\002 is not in \002$target\002's SILENCE list.";
1915 $del_silence->execute($root, $mask);
1916 push @out_masks, "-$mask";
1917 push @reply, "\002$mask\002 removed from \002$target\002's SILENCE list.";
1919 ircd
::svssilence
($nsuser, $user, @out_masks);
1920 notice
($user, @reply);
1922 elsif ($cmd =~ /^list$/i) {
1923 $get_silences->execute($root);
1925 my @reply; my $i = 1;
1926 while(my ($mask, $time, $expiry, $comment) = $get_silences->fetchrow_array) {
1927 push @reply, "$i \002[\002 $mask \002]\002 Date added: ".gmtime2
($time),
1928 ' '.($comment ? "\002[\002 $comment \002]\002 " : '').
1929 ($expiry ? 'Expires in '.time_rel
($expiry-time
()) :
1930 "\002[\002 Never expires \002]\002");
1934 notice
($user, "SILENCE list for \002$target\002:", (scalar @reply ? @reply : " list empty"));
1937 notice
($user, 'Syntax: SILENCE [nick] <ADD|DEL|LIST> [mask] [+expiry] [comment]');
1943 my ($user, @targets) = @_;
1946 foreach my $target (@targets) {
1947 unless(is_registered
($target)) {
1948 push @reply, "ACC 0 \002$target\002 is not registered.";
1952 unless(is_online
($target)) {
1953 push @reply, "ACC 1 \002$target\002 is registered and offline.";
1957 unless(is_identified
({NICK
=> $target}, $target)) {
1958 push @reply, "ACC 2 \002$target\002 is online but not identified.";
1962 push @reply, "ACC 3 \002$target\002 is registered and identified.";
1964 notice
($user, @reply);
1968 my ($user, @nicks) = @_;
1970 foreach my $nick (@nicks) {
1971 if(lc $nick eq lc $user->{AGENT
}) {
1972 notice
($user, "Oh, a wise guy, eh?");
1975 my ($status, $msg) = do_seen
($nick);
1977 notice
($user, "\002$nick\002 is online now, ".$msg.'.');
1978 } elsif($status == 1) {
1979 notice
($user, "\002$nick\002 was last seen ".$msg.'.');
1981 notice
($user, "The nick \002$nick\002 is not registered.");
1986 sub ns_recover
($$;$) {
1987 my ($user, $nick, $pass) = @_;
1988 my $src = get_user_nick
($user);
1990 if(nr_chk_flag
($nick, NRF_FREEZE
)) {
1991 notice
($user, "This nick has been frozen and may not be used.", $err_deny);
1992 services
::ulog
($nsnick, LOG_INFO
(), "\00305attempted to recover frozen nick \003\002$nick\002", $user);
1996 unless(is_identified
($user, $nick)) {
1998 my $s = ns_identify
($user, $nick, $pass);
1999 return if($s == 0); #failed to identify
2001 notice
($user, $err_deny);
2006 if(!is_online
($nick)) {
2007 notice
($user, "\002$nick\002 is not online");
2009 } elsif(lc $src eq lc $nick) {
2010 notice
($user, "I'm sorry, $src, I'm afraid I can't do that.");
2015 notice
($user, "User claiming your nick has been collided",
2016 "/msg NickServ RELEASE $nick to get it back before the one-minute timeout.");
2017 services
::ulog
($nsnick, LOG_INFO
(), "used NickServ RECOVER on $nick", $user);
2023 my ($user, @args) = @_;
2026 #These helpers shouldn't be needed anywhere else.
2027 # If they ever are, move them to the helpers section
2028 sub get_auth_num
($$) {
2029 # this cannot be converted to SrSv::MySQL::Stub, due to bind_param
2030 my ($nick, $num) = @_;
2031 $get_auth_num->execute($nick, $num - 1);
2032 my ($cn, $data) = $get_auth_num->fetchrow_array();
2033 $get_auth_num->finish();
2034 return ($data ? ($cn, split(/:/, $data)) : undef);
2036 sub get_auth_chan
($$) {
2037 my ($nick, $cn) = @_;
2038 $get_auth_chan->execute($nick, $cn);
2039 my ($data) = $get_auth_chan->fetchrow_array();
2040 $get_auth_chan->finish();
2041 return (split(/:/, $data));
2044 if ($args[0] =~ /^(list|accept|approve|decline|reject)$/i) {
2045 $target = get_user_nick
($user);
2046 $cmd = lc shift @args;
2049 $target = shift @args;
2050 $cmd = lc shift @args;
2053 unless (is_registered
($target)) {
2054 notice
($user, "The nickname \002$target\002 is not registered");
2057 unless (is_identified
($user, $target)) {
2058 notice
($user, $err_deny);
2062 if ($cmd eq 'list') {
2064 $list_auth->execute($target);
2065 while (my ($cn, $data) = $list_auth->fetchrow_array()) {
2066 my ($adder, $old, $level, $time) = split(':', $data);
2067 push @data, [$cn, $chanserv::levels
[$level], $adder, gmtime2
($time)];
2069 if ($list_auth->rows()) {
2070 notice
$user, columnar
{TITLE
=> "Pending authorizations for \002$target\002:",
2071 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data;
2074 notice
($user, "There are no pending authorizations for \002$target\002");
2077 elsif ($cmd eq 'accept' or $cmd eq 'approve') {
2078 my $parm = shift @args;
2079 my ($cn, $adder, $old, $level, $time);
2080 if(misc
::isint
($parm) and
2081 ($cn, $adder, $old, $level, $time) = get_auth_num
($target, $parm))
2084 elsif ($parm =~ /^\#/ and
2085 ($adder, $old, $level, $time) = get_auth_chan
($target, $parm))
2090 # This should normally be an 'else' as the elsif above should prove false
2091 # For some reason, it doesn't work. the unless ($cn) fixes it.
2092 # It only doesn't work for numbered entries
2093 notice
($user, "There is no entry for \002$parm\002 in \002$target\002's AUTH list");
2096 my $chan = { CHAN
=> $cn };
2097 my $root = get_root_nick
($target);
2099 # These next 3 lines should use chanserv::set_acc() but it doesn't seem to work.
2100 # It won't let me use a $nick instead of $user
2101 $chanserv::set_acc1-
>execute($cn, $level, $root);
2102 $chanserv::set_acc2-
>execute($level, $adder, $cn, $root);
2103 chanserv
::set_modes_allnick
($root, $chan, $level) unless chanserv
::is_neverop
($root);
2105 my $log_str = ($old?'move':'addition')." \002$root\002"
2106 . ($old ? ' from the '.$chanserv::levels
[$old] : '') .
2107 ' to the '.$chanserv::levels
[$level]." list of \002$cn\002";
2108 services
::ulog
($chanserv::csnick
, LOG_INFO
(), "accepted the $log_str from $adder", $user, $chan);
2109 notice
($user, "You have accepted the $log_str");
2110 $del_auth->execute($target, $cn);
2111 $del_auth->finish();
2112 memoserv
::send_memo
($chanserv::csnick
, $adder, "$target accepted the $log_str");
2114 elsif ($cmd eq 'decline' or $cmd eq 'reject') {
2115 my $parm = shift @args;
2116 my ($cn, $adder, $old, $level, $time);
2117 if(misc
::isint
($parm) and
2118 ($cn, $adder, $old, $level, $time) = get_auth_num
($target, $parm))
2121 elsif ($parm =~ /^\#/ and
2122 ($adder, $old, $level, $time) = get_auth_chan
($target, $parm))
2127 # This should normally be an 'else' as the elsif above should prove false
2128 # For some reason, it doesn't work. the unless ($cn) fixes it.
2129 # It only doesn't work for numbered entries
2130 notice
($user, "There is no entry for \002$parm\002 in \002$target\002's AUTH list");
2133 my $chan = { CHAN
=> $cn };
2135 my $root = get_root_nick
($target);
2136 my $log_str = ($old?'move':'addition')." \002$root\002"
2137 . ($old ? ' from the '.$chanserv::levels
[$old] : '') .
2138 ' to the '.$chanserv::levels
[$level]." list of \002$cn\002";
2139 services
::ulog
($chanserv::csnick
, LOG_INFO
(), "declined the $log_str from $adder", $user, $chan);
2140 notice
($user, "You have declined $log_str");
2141 $del_auth->execute($target, $cn);
2142 $del_auth->finish();
2143 memoserv
::send_memo
($chanserv::csnick
, $adder, "$target declined the $log_str");
2145 #elsif ($cmd eq 'read') {
2148 notice
($user, "Unknown AUTH cmd");
2152 sub ns_authcode
($$$;$) {
2153 my ($user, $target, $code, $pass) = @_;
2155 if ($pass and $pass =~ /pass/i) {
2156 notice
($user, 'Try a more secure password.');
2160 unless(is_registered
($target)) {
2161 notice
($user, "\002$target\002 isn't registered.");
2165 if(authcode
($target, undef, $code)) {
2166 notice
($user, "\002$target\002 authenticated.");
2167 services
::ulog
($nsnick, LOG_INFO
(), "logged in to \002$target\002 using an authcode", $user);
2169 do_identify
($user, $target, $target);
2171 ns_set
($user, $target, 'PASSWD', $pass)
2172 } elsif(nr_chk_flag
($target, NRF_SENDPASS
())) {
2173 notice
($user, "YOU MUST CHANGE YOUR PASSWORD NOW", "/NS SET $target PASSWD <newpassword>");
2177 notice
($user, "\002$target\002 authentication failed. Please verify that you typed or pasted the code correctly.");
2181 sub ns_profile
($@) {
2182 my ($user, $first, @args) = @_;
2184 my %profile_dispatch = (
2185 'read' => \
&ns_profile_read
,
2186 'info' => \
&ns_profile_read
,
2188 'del' => \
&ns_profile_del
,
2189 'delete' => \
&ns_profile_del
,
2191 'set' => \
&ns_profile_update
,
2192 'update' => \
&ns_profile_update
,
2193 'add' => \
&ns_profile_update
,
2195 'wipe' => \
&ns_profile_wipe
,
2199 if(my $sub = $profile_dispatch{$args[0]}) {
2200 # Second command with nick
2202 $sub->($user, $first, @args);
2204 elsif(my $sub = $profile_dispatch{$first}) {
2205 # Second command without nick
2206 $sub->($user, get_user_nick
($user), @args);
2210 ns_profile_read
($user, ($first || get_user_nick
($user)));
2214 "Syntax: PROFILE [nick] [SET|DEL|READ|WIPE ...]",
2215 "For help, type: \002/ns help profile\002";
2219 sub ns_profile_read
($$@) {
2220 my ($user, $target, @args) = @_;
2222 foreach my $nick ((scalar(@args) ? @args : $target)) {
2223 next unless chk_registered
($user, $nick);
2224 my @profile_entries = get_profile_ntf
($nick);
2225 if(scalar(@profile_entries)) {
2226 notice
$user, columnar
({TITLE
=> "Profile information for \002$nick\002:",
2227 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)},
2228 map( ["$_->[0]:", $_->[1]], @profile_entries )
2232 notice
$user, "\002$nick\002 has not created a profile.";
2237 sub ns_profile_update
($$@) {
2238 my ($user, $target, @args) = @_;
2240 return unless chk_registered
($user, $target);
2242 unless(is_identified
($user, $target) or
2243 adminserv
::is_svsop
($user, adminserv
::S_HELP
())
2245 notice
($user, "$target: $err_deny");
2249 my ($key, $data) = (shift @args, join(' ', @args));
2251 unless ($key and $data) {
2252 notice
$user, "Syntax: PROFILE [nick] SET <item> <text>",
2253 "For help, type: \002/ns help profile\002";
2257 if(count_profile_ntf
($target) >= MAX_PROFILE
) {
2258 notice
($user, "You may not have more than ".MAX_PROFILE
." profile items.");
2261 elsif (length($key) > 32) {
2262 notice
($user, "Item name may not be longer than 32 characters.");
2265 elsif (length($data) > MAX_PROFILE_LEN
) {
2266 my $over = length($data) - MAX_PROFILE_LEN
;
2267 notice
($user, "Your entry is $over characters too long. (".MAX_PROFILE_LEN
." max.)");
2270 add_profile_ntf
($key, $data, $target);
2271 notice
($user, "\002$target\002's \002$key\002 is now \002$data\002");
2274 sub ns_profile_del
($$@) {
2275 my ($user, $target, @args) = @_;
2277 return unless chk_registered
($user, $target);
2279 unless(is_identified
($user, $target) or
2280 adminserv
::is_svsop
($user, adminserv
::S_HELP
())
2282 notice
($user, "$target: $err_deny");
2286 my $key = shift @args;
2289 notice
$user, "Syntax: PROFILE [nick] DEL <item>",
2290 "For help, type: \002/ns help profile\002";
2294 if(del_profile_ntf
($target, $key) == 0) {
2295 notice
($user, "There is no profile item \002$key\002 for \002$target\002");
2297 notice
($user, "Profile item \002$key\002 for \002$target\002 deleted.");
2301 sub ns_profile_wipe
($$@) {
2302 my ($user, $target, undef) = @_;
2304 unless (is_registered
($target)) {
2305 notice
($user, "$target is not registered.");
2308 unless(is_identified
($user, $target) or
2309 adminserv
::is_svsop
($user, adminserv
::S_HELP
())
2311 notice
($user, "$target: $err_deny");
2315 wipe_profile_ntf
($target);
2316 notice
($user, "Profile for \002$target\002 wiped.");
2326 $get_seen->execute($nick);
2327 if (my ($alias, $root, $lastseen) = $get_seen->fetchrow_array) {
2328 if(my @usernicks = get_nick_user_nicks
($nick)) {
2330 $msg = "using ".(@usernicks==1 ? 'the nick ' : 'the following nicks: ').join(', ', map "\002$_\002", @usernicks);
2334 $msg = time_ago
($lastseen) . " ago (".gmtime2
($lastseen).")";
2338 $status = 0; $msg = undef();
2341 return ($status, $msg);
2344 # For a whole group:
2345 sub unidentify
($$;$) {
2346 my ($nick, $msg, $src) = @_;
2348 $nick = get_root_nick
($nick);
2350 foreach my $t (get_nick_user_nicks
$nick) {
2351 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2352 get_user_id
($user);
2353 ircd
::notice
($nsuser, $user, (ref $msg ? @$msg : $msg)) unless(lc $t eq lc $src);
2354 if(is_alias_of
($nick, $t)) {
2355 ircd
::setumode
($nsuser, $user, '-r');
2359 $unidentify->execute($nick);
2362 # For a single alias:
2363 sub unidentify_single
($$) {
2364 my ($nick, $msg) = @_;
2365 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2366 get_user_id
($user);
2367 if(is_online
($nick)) {
2368 ircd
::setumode
($nsuser, $user, '-r');
2372 sub kill_clones
($$) {
2373 my ($user, $ip) = @_;
2374 my $uid = get_user_id
($user);
2375 my $src = get_user_nick
($user);
2377 return 0 if $ip == 0;
2379 $chk_clone_except->execute($uid);
2380 my ($lim) = $chk_clone_except->fetchrow_array;
2381 return 0 if $lim == MAX_LIM
();
2382 $lim = services_conf_clone_limit
unless $lim;
2384 $count_clones->execute($ip);
2385 my ($c) = $count_clones->fetchrow_array;
2388 ircd
::irckill
($nsuser, $user, "Session Limit Exceeded");
2394 my ($user, $reason) = @_;
2396 ircd
::irckill
(get_user_agent
($user) || main_conf_local
, $user, $reason);
2399 sub kline_user
($$$) {
2400 my ($user, $time, $reason) = @_;
2401 my $agent = get_user_agent
($user);
2402 my ($ident, $host) = get_host
($user);
2404 ircd
::kline
($agent, '*', $host, $time, $reason);
2407 sub do_identify
($$$;$$) {
2408 my ($user, $nick, $root, $flags, $svsnick) = @_;
2409 my $uid = get_user_id
($user);
2410 my $src = get_user_nick
($user);
2411 $identify_ign->execute($uid, $root);
2412 $id_update->execute($root, $uid);
2414 notice
($user, 'You are now identified.');
2416 delete($user->{NICKFLAGS
});
2417 if($flags & NRF_VACATION
) {
2418 notice
($user, "Welcome back from your vacation, \002$nick\002.");
2419 my $ts = MIME
::Base64
::encode
(pack('N', time()));
2421 $del_nicktext->execute(NTF_VACATION
, $root); $del_nicktext->finish(); #don't allow dups
2422 $set_vacation_ntf->execute($ts, $root);
2423 $set_vacation_ntf->finish();
2426 $get_umode_ntf->execute($nick);
2427 my ($umodes) = $get_umode_ntf->fetchrow_array();
2428 $get_umode_ntf->finish();
2429 if(adminserv
::get_svs_level
($root)) {
2430 $umodes = modes
::merge_umodes
('+h', $umodes);
2431 ircd
::nolag
($nsuser, '+', $user);
2433 $umodes = modes
::merge_umodes
('+r', $umodes) if(is_identified
($user, $src));
2435 hostserv
::hs_on
($user, $root, 1);
2437 if(my @chans = get_autojoin_ntf
($nick)) {
2438 ircd
::svsjoin
($nsuser, $user, @chans);
2442 if(enforcer_quit
($nick)) {
2443 notice
($user, 'Your nick has been released from custody.');
2447 if (lc($src) eq lc($nick)) {
2448 ircd
::setumode
($nsuser, $user, $umodes);
2449 $update_nickalias_last->execute($nick); $update_nickalias_last->finish();
2452 ircd
::svsnick
($nsuser, $user, $nick);
2453 ircd
::setumode
($nsuser, $user, modes
::merge_umodes
('+r', $umodes) );
2454 # the update _should_ be taken care of in nick_change()
2455 #$update_nickalias_last->execute($nick); $update_nickalias_last->finish();
2457 elsif(defined $umodes) {
2458 ircd
::setumode
($nsuser, $user, $umodes);
2460 nickserv
::do_svssilence
($user, $root);
2461 nickserv
::do_svswatch
($user, $root);
2463 chanserv
::akick_alluser
($user);
2464 chanserv
::set_modes_allchan
($user, $flags & NRF_NEVEROP
);
2465 chanserv
::fix_private_join_before_id
($user);
2467 services
::ulog
($nsnick, LOG_INFO
(), "identified to nick $nick (root: $root)", $user);
2469 memoserv
::notify
($user, $root);
2470 notify_auths
($user, $root) if $flags & NRF_AUTH
;
2471 return ($enforced ? 2 : 1);
2474 sub authcode
($;$$) {
2475 my ($nick, $type, $email) = @_;
2477 unless (defined($email)) {
2478 $email = get_email
($nick);
2481 my $authcode = misc
::gen_uuid
(4, 5);
2482 $set_authcode_ntf->execute($authcode, $nick); $set_authcode_ntf->finish();
2483 send_email
($email, "Nick Authentication Code for $nick",
2486 "You are receiving this message from the automated nickname\n".
2487 "management system of the ".$IRCd_capabilities{NETWORK
}." network.\n\n".
2488 (lc($type) eq 'emailreg' ?
2489 "If you did not try to register your nickname with us, you can\n".
2490 "ignore this message. If you continue getting similar e-mails\n".
2491 "from us, chances are that someone is intentionally abusing your\n".
2492 "e-mail address. Please contact an administrator for help.\n".
2494 "In order to complete your registration, you must follow the\n".
2495 "instructions in this e-mail before ".gmtime2
(time+86400)."\n".
2497 "To complete the registration, the next time you connect, issue the\n".
2498 "following command to NickServ:\n\n".
2500 "After you issue the command, your registration will be complete and\n".
2501 "you will be able to use your nickname.\n\n"
2504 (lc($type) eq 'sendpass' ?
2505 "You requested a password authentication code for the nickname '$nick'\n".
2506 "on the ".$IRCd_capabilities{'NETWORK'}." IRC Network.\n".
2507 "As per our password policies, an authcode has been created for\n".
2508 "you and e-mailed to the address you set in NickServ.\n".
2509 "To complete the process, you need to return to ".$IRCd_capabilities{'NETWORK'}.",\n".
2510 "and execute the following command: \n\n"
2513 "/NS EMAILCODE $nick $authcode\n\n".
2515 (lc($type) eq 'sendpass' ?
2516 "YOU MUST CHANGE YOUR PASSWORD AT THIS POINT.\n".
2517 "You can do so via the following command: \n\n".
2518 "/NS SET $nick PASSWD newpassword\n\n".
2519 "alternately, try this command: \n\n".
2521 "/NS EMAILCODE $nick $authcode <password>\n\n"
2525 "If you feel you have gotten this e-mail in error, please contact\n".
2526 "an administrator.\n\n".
2529 "If this e-mail came to you unsolicited and appears to be spam -\n".
2530 "please e-mail ".main_conf_replyto
." with a copy of this e-mail\n".
2531 "including all headers.\n\n".
2536 $get_authcode_ntf->execute($nick, $email);
2537 my ($passed) = $get_authcode_ntf->fetchrow_array();
2538 $get_authcode_ntf->finish();
2540 nr_set_flag
($nick, NRF_EMAILREG
(), 0);
2541 unless(nr_chk_flag
($nick, NRF_SENDPASS
)) {
2542 $del_nicktext->execute(NTF_AUTHCODE
, $nick); $del_nicktext->finish();
2552 # This is mostly for logging, be careful using it for anything else
2553 sub get_hostmask
($) {
2556 my $src = get_user_nick
($user);
2558 ($ident, $host) = get_host
($user);
2560 return "$src!$ident\@$host";
2565 $set_guest->execute(1, $nick);
2566 my $randnick = 'Guest'.int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10));
2567 #Prevent collisions.
2568 while (is_online
($randnick)) {
2569 $randnick = 'Guest'.int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10)).int(rand(10));
2571 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2572 get_user_id
($user);
2573 ircd
::svsnick
($nsuser, $user, $randnick);
2579 return if services_conf_noexpire
;
2582 my ($ne, $e, $ve, $eve) = (services_conf_nearexpire
, services_conf_nickexpire
, services_conf_vacationexpire
,
2583 services_conf_validate_expire
);
2586 $get_expired->execute(time() - (86400 * services_conf_nickexpire
),
2587 time() - (86400 * services_conf_vacationexpire
),
2588 time() - (86400 * services_conf_validate_expire
));
2589 while(my ($nick, $email, $ident, $vhost) = $get_expired->fetchrow_array) {
2591 wlog
($nsnick, LOG_INFO
(), "$nick has expired. Email: $email Vhost: $ident\@$vhost");
2596 return unless services_conf_nearexpire
; # if nearexpire is zero, don't.
2597 $get_near_expired->execute(
2598 $time - (86400 * (services_conf_nickexpire
- services_conf_nearexpire
)),
2599 $time - (86400 * (services_conf_vacationexpire
- services_conf_nearexpire
))
2601 while(my ($nick, $email, $flags, $last) = $get_near_expired->fetchrow_array) {
2602 my $expire_days = services_conf_nearexpire
;
2603 if ( ( $flags & NRF_VACATION
) and ( $last < time() - (86400 * services_conf_vacationexpire
) )
2604 or (($last < time() - (86400 * services_conf_nickexpire
)) ) )
2607 } elsif ( ( $flags & NRF_VACATION
) and ( $last > time() - (86400 * services_conf_vacationexpire
) )
2608 or (($last > time() - (86400 * services_conf_nickexpire
)) ) )
2610 # this terrible invention is to determine how many days until their nick will expire.
2611 # this should almost always be ~7, unless something weird happens like
2612 # F_HOLD or svsop status is removed.
2613 # int truncates, so we add 0.5.
2614 $expire_days = -int(($time - ($last + (86400 *
2615 ( ( $flags & NRF_VACATION
) ? services_conf_vacationexpire
: services_conf_nickexpire
) )))
2618 if($expire_days >= 1) {
2620 $get_aliases->execute($nick);
2621 my $aliases = $get_aliases->fetchrow_arrayref();
2623 my $message = "We would like to remind you that your registered nick, $nick, will expire\n".
2624 "in approximately $expire_days days unless you sign on and identify.";
2625 if(scalar(@$aliases) > 1) {
2626 $message .= "\n\nThe following nicks are linked in this group:\n " . join("\n ", @$aliases);
2629 send_email
($email, "$nsnick Expiration Notice", $message);
2632 wlog
($nsnick, LOG_INFO
(), "$nick will expire ".($expire_days <= 0 ? "today" : "in $expire_days days.")." ($email)");
2633 $set_near_expired->execute($nick);
2637 sub expire_silence_timed
{
2639 $time = 60 unless $time;
2640 add_timer
('', $time, __PACKAGE__
, 'nickserv::expire_silence_timed');
2642 find_expired_silences
();
2645 # This code is a mess b/c we can only pull one entry at a time
2646 # and we want to batch the list to the user and to the ircd.
2647 # our SQL statement explicitly orders the silence entries by nickreg.nick
2648 sub find_expired_silences
() {
2649 $get_expired_silences->execute();
2650 my ($lastnick, @entries);
2651 while(my ($nick, $mask, $comment) = $get_expired_silences->fetchrow_array()) {
2652 if ($nick eq $lastnick) {
2654 do_expired_silences
($lastnick, \
@entries);
2658 push @entries, [$mask, $comment];
2661 do_expired_silences
($lastnick, \
@entries);
2663 $get_expired_silences->finish();
2664 $del_expired_silences->execute(); $del_expired_silences->finish();
2668 sub do_expired_silences
($$) {
2670 my (@entries) = @{$_[1]};
2672 foreach my $user (get_nick_users
$nick) {
2673 $user->{AGENT
} = $nsnick;
2674 $user->{ID
} = ircd
::getUuid
($nick);
2675 ircd
::svssilence
($nsuser, $user, map ( { '-'.$_->[0] } @entries) );
2676 #notice($user, "The following SILENCE entries have expired: ".
2677 # join(', ', map ( { $_->[0] } @entries) ));
2678 notice
($user, map( { "The following SILENCE entry has expired: \002".$_->[0]."\002 ".$_->[1] } @entries ) );
2681 sub do_svssilence
($$) {
2682 my ($user, $rootnick) = @_;
2683 my $target = get_user_nick
($user);
2685 $get_silences->execute($rootnick);
2686 my $count = $get_silences->rows;
2687 unless ($get_silences->rows) {
2688 $get_silences->finish;
2692 for(my $i = 1; $i <= $count; $i++) {
2693 my ($mask, $time, $expiry) = $get_silences->fetchrow_array;
2694 push @silences, "+$mask";
2696 $get_silences->finish;
2697 ircd
::svssilence
($nsuser, $user, @silences);
2701 sub do_svswatch
($$) {
2702 my ($user, $rootnick) = @_;
2703 my $target = get_user_nick
($user);
2705 $get_watches->execute($rootnick);
2706 my $count = $get_watches->rows;
2707 unless ($get_watches->rows) {
2708 $get_watches->finish;
2712 for(my $i = 1; $i <= $count; $i++) {
2713 my ($mask, $time, $expiry) = $get_watches->fetchrow_array;
2714 push @watches, "+$mask";
2716 $get_watches->finish;
2717 ircd
::svswatch
($nsuser, $user, @watches);
2722 my ($user, $rootnick) = @_;
2723 my $target = get_user_nick
($user);
2725 $get_umode_ntf->execute($rootnick);
2726 my ($umodes) = $get_umode_ntf->fetchrow_array; $get_umode_ntf->finish();
2728 ircd
::setumode
($nsuser, $user, $umodes) if $umodes;
2732 sub notify_auths
($$) {
2734 my $nick = get_user_nick
($user);
2735 $get_num_nicktext_type->execute($nick, NTF_AUTH
);
2736 my ($count) = $get_num_nicktext_type->fetchrow_array(); $get_num_nicktext_type->finish();
2737 notice
($user, "$nick has $count channel authorizations awaiting action.",
2738 "To list them, type /ns auth $nick list") if $count;
2741 ### PROTECTION AND ENFORCEMENT ###
2746 return if nr_chk_flag
($nick, NRF_EMAILREG
());
2747 my $lev = protect_level
($nick);
2748 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2749 get_user_id
($user);
2751 "This nickname is registered and protected. If it is your",
2752 "nick, type \002/msg NickServ IDENTIFY <password>\002. Otherwise,",
2753 "please choose a different nick."
2757 warn_countdown
("$nick 60");
2763 ircd
::svshold
($nick, 60, "If this is your nick, type /NS SIDENTIFY $nick \002password\002");
2764 kill_user
($user, "Unauthorized nick use with KILL protection enabled.");
2765 $enforcers{lc $nick} = 1;
2766 add_timer
($nick, 60, __PACKAGE__
, "nickserv::enforcer_delete");
2772 sub warn_countdown
($) {
2774 my ($nick, $rem) = split(/ /, $cookie);
2775 my $user = { NICK
=> $nick, AGENT
=> $nsuser };
2777 if (is_identified
($user, $nick)) {
2778 print "Line 2778\n";
2779 $update_nickalias_last->execute($nick); $update_nickalias_last->finish();
2782 elsif(!(is_online
($nick)) or !(is_registered
($nick))) { print "Line 2782\n"; return; }
2785 notice
($user, 'Your nick is now being changed.');
2789 "If you do not identify or change your nick in $rem seconds, your nick will be changed.");
2791 add_timer
("$nick $rem", 20, __PACKAGE__
, "nickserv::warn_countdown");
2797 my $newnick = guestnick
($nick);
2798 ircd
::svshold
($nick, 60, "If this is your nick, type /NS SIDENTIFY $nick \002password\002");
2799 $enforcers{lc $nick} = 1;
2800 add_timer
($nick, 60, __PACKAGE__
, "nickserv::enforcer_delete");
2804 sub enforcer_delete
($) {
2806 delete($enforcers{lc $nick});
2809 sub enforcer_quit
($) {
2811 if($enforcers{lc $nick}) {
2812 enforcer_delete
($nick);
2813 ircd
::svsunhold
($nick);
2819 ### DATABASE UTILITY FUNCTIONS ###
2827 if($cur_lock ne $nick) {
2828 really_release_lock
($nick);
2829 die("Tried to get two locks at the same time");
2834 $get_lock->execute(sql_conf_mysql_db
.".user.$nick");
2839 sub release_lock
($) {
2844 if($cur_lock and $cur_lock ne $nick) {
2845 really_release_lock
($cur_lock);
2847 die("Tried to release the wrong lock");
2853 really_release_lock
($nick);
2857 sub really_release_lock
($) {
2861 $release_lock->execute(sql_conf_mysql_db
.".user.$nick");
2862 $release_lock->finish;
2866 sub get_user_modes
($) {
2869 my $uid = get_user_id
($user);
2870 $get_umodes->execute($uid);
2871 my ($umodes) = $get_umodes->fetchrow_array;
2872 $get_umodes->finish();
2873 print "UMODES $umodes\n";
2878 my ($user, $vhost) = @_;
2879 my $id = get_user_id
($user);
2881 return $set_vhost->execute($vhost, $id);
2885 my ($user, $ident) = @_;
2886 my $id = get_user_id
($user);
2888 return $set_ident->execute($ident, $id);
2892 my ($user, $ip) = @_;
2893 my $id = get_user_id
($user);
2895 return $set_ip->execute($ip, $id);
2898 sub get_root_nick
($) {
2901 $get_root_nick->execute($nick);
2902 my ($root) = $get_root_nick->fetchrow_array;
2907 sub get_id_nick
($) {
2910 $get_id_nick->execute($id);
2911 my ($root) = $get_id_nick->fetchrow_array;
2919 my $ret = $drop->execute($nick);
2924 sub changeroot
($$) {
2925 my ($old, $new) = @_;
2927 return if(lc $old eq lc $new);
2929 $change_root->execute($new, $old);
2935 $del_all_access->execute($root);
2936 $memoserv::delete_all_memos-
>execute($root);
2937 $memoserv::wipe_ignore-
>execute($root);
2938 $memoserv::purge_ignore-
>execute($root);
2939 chanserv
::drop_nick_chans
($root);
2940 $hostserv::del_vhost-
>execute($root);
2941 $drop_watch->execute($root);
2942 $drop_silence->execute($root);
2943 $drop_nicktext->execute($root);
2944 $delete_aliases->execute($root);
2945 $chanserv::drop_nick_akick-
>execute($root);
2952 return (get_root_nick
($nick) eq $nick);
2955 sub delete_alias
($) {
2957 return $delete_alias->execute($nick);
2960 sub delete_aliases
($) {
2962 return $delete_aliases->execute($root);
2965 sub get_all_access
($) {
2968 $get_all_access->execute($nick);
2969 return $get_all_access->fetchrow_array;
2972 sub del_all_access
($) {
2975 return $del_all_access->execute($root);
2979 my ($nick, $pass, $user) = @_;
2981 if(lc($pass) eq 'force' and adminserv
::can_do
($user, 'SERVOP')) {
2982 if(adminserv
::get_best_svs_level
($user) > adminserv
::get_svs_level
($nick)) {
2987 return validate_pass
(get_pass
($nick), $pass);
2990 sub inc_nick_inval
($) {
2992 my $id = get_user_id
($user);
2994 $inc_nick_inval->execute($id);
2995 $get_nick_inval->execute($id);
2996 my ($nick, $inval) = $get_nick_inval->fetchrow_array;
2998 ircd
::irckill
($nsuser, $user, 'Too many invalid passwords.');
2999 # unnecessary as irckill calls the quit handler.
3000 #nick_delete($nick);
3007 sub is_registered
($) {
3010 $is_registered->execute($nick);
3011 if($is_registered->fetchrow_array) {
3018 sub chk_registered
($;$) {
3019 my ($user, $nick) = @_;
3020 my $src = get_user_nick
($user);
3024 if(lc $src eq lc $nick) {
3025 $what = "Your nick";
3027 $what = "The nick \002$nick\002";
3030 $nick = get_user_nick
($user) unless $nick;
3031 $what = "Your nick";
3034 unless(is_registered
($nick)) {
3035 notice
($user, "$what is not registered.");
3042 sub is_alias_of
($$) {
3043 $is_alias_of->execute($_[0], $_[1]);
3044 return ($is_alias_of->fetchrow_array ? 1 : 0);
3047 sub check_identify
($) {
3049 my $nick = get_user_nick
($user);
3050 if(is_registered
($nick)) {
3051 if(is_identified
($user, $nick)) {
3052 ircd
::setumode
($nsuser, $user, '+r');
3053 $update_nickalias_last->execute($nick); $update_nickalias_last->finish();
3062 sub cleanup_users
() {
3063 add_timer
('', services_conf_old_user_age
, __PACKAGE__
, 'nickserv::cleanup_users');
3064 my $time = (time() - (services_conf_old_user_age
* 2));
3065 $cleanup_users->execute($time);
3066 $cleanup_nickid->execute($time);
3067 $cleanup_chanuser->execute();
3072 add_timer
('fix_vhosts', 5, __PACKAGE__
, 'nickserv::fix_vhosts');
3073 $get_hostless_nicks->execute();
3074 while (my ($nick) = $get_hostless_nicks->fetchrow_array) {
3075 ircd
::notice
($nsuser, main_conf_diag
, "HOSTLESS NICK $nick");
3076 ircd
::userhost
($nick);
3077 ircd
::userip
($nick);
3079 $get_hostless_nicks->finish();
3086 $get_user_id->execute($nick);
3087 if($id = $get_user_id->fetchrow_array) {
3088 $nick_id_delete->execute($id);
3089 $nick_delete->execute($nick);
3096 my ($user, $time, $ident, $host, $vhost, $server, $svsstamp, $modes, $gecos, $ip, $cloakhost) = @_;
3097 my $nick = get_user_nick
($user);
3099 if ($vhost eq '*') {
3100 if ({modes
::splitumodes
($modes)}->{x
} eq '+') {
3101 if(defined($cloakhost)) {
3102 $vhost = $cloakhost;
3104 else { # This should never happen with CLK or VHP
3105 ircd
::userhost
($nick);
3113 if ($id = get_user_id
( $user )) {
3114 #$id = decodeUUID ($id);
3115 $nick_checkExists->execute ($id, $time);
3116 my $exists = $nick_checkExists -> fetchrow_array
();
3117 my $flags = (synced
() ? UF_FINISHED
() : 0);
3118 unless (defined($exists)) {
3119 $nick_deleteChanUser -> execute
($id);
3120 $nick_deleteNickCh -> execute
($id);
3121 $nick_deleteNickId -> execute
($id);
3122 $id_delUser -> execute
($id);
3123 $nick_create2 -> execute
($id, $nick, $time, $ident, $host, $vhost, $server, $modes, $gecos, $flags, $cloakhost);
3126 $nick_create_old->execute ($nick, $ident, $host, $vhost, $server, $modes, $gecos, $flags, $cloakhost, $id);
3128 $add_nickchg->execute($ircline, $nick, $nick);
3129 release_lock
($nick);
3130 check_identify
($user);
3134 $get_user_nick->execute($svsstamp);
3135 my ($oldnick) = $get_user_nick->fetchrow_array();
3136 $id = $svsstamp if defined($oldnick);
3139 $nick_check->execute($nick, $time);
3140 ($id) = $nick_check->fetchrow_array;
3144 $olduser{lc $nick} = 1;
3145 $nick_create_old->execute($nick, $ident, $host, $vhost, $server, $modes, $gecos, UF_FINISHED
(), $cloakhost, $id);
3149 my $flags = (synced
() ? UF_FINISHED
() : 0);
3151 while($i < 10 and !$nick_create->execute($nick, $time, $ident, $host, $vhost, $server, $modes, $gecos, $flags, $cloakhost)) { $i++ }
3152 $id = get_user_id
( { NICK
=> $nick } ); # There needs to be a better way to do this
3154 ircd
::setsvsstamp
($nsuser, $user, $id) unless $svsstamp == $id;
3156 $add_nickchg->execute($ircline, $nick, $nick);
3158 release_lock
($nick);
3160 $newuser{lc $nick} = 1;
3163 nickserv
::userip
(undef, $nick, $ip);
3165 else { # This should never happen with NICKIP
3166 ircd
::userip
($nick);
3172 sub nick_create_post
($) {
3174 my $user = { NICK
=> $nick };
3175 my $old = $olduser{lc $nick};
3176 delete $olduser{lc $nick};
3178 operserv
::do_news
($nick, 'u') unless($old);
3182 check_identify
($user);
3184 release_lock
($nick);
3187 sub nick_delete
($$) {
3188 my ($user, $quit) = @_;
3189 my $nick = $user->{NICK
};
3191 my $id = get_user_id
($user);
3192 $del_nickchg_id->execute($id); $del_nickchg_id->finish();
3193 $quit_update->execute($quit, $id); $quit_update->finish();
3194 $update_lastseen->execute($id); $update_lastseen->finish();
3195 $get_quit_empty_chans->execute($id);
3196 $chan_user_partall->execute($id); $chan_user_partall->finish();
3197 #$nick_chan_delete->execute($id); $nick_chan_delete->finish();
3198 $nick_quit->execute($nick); $nick_quit->finish();
3199 release_lock
($nick);
3200 while(my ($cn) = $get_quit_empty_chans->fetchrow_array) {
3201 chanserv
::channel_emptied
({CHAN
=> $cn});
3203 $get_quit_empty_chans->finish();
3208 my (undef, $servers, $reason) = @_;
3210 $get_squit_lock->execute; $get_squit_lock->finish;
3212 foreach my $server (@$servers) {
3213 $get_squit_empty_chans->execute($server);
3215 $squit_nickreg->execute($server);
3216 $squit_nickreg->finish;
3218 $squit_lastquit->execute("Netsplit from $server", $server);
3219 $squit_lastquit->finish;
3221 $squit_users->execute($server);
3222 $squit_users->finish;
3224 while(my ($cn) = $get_squit_empty_chans->fetchrow_array) {
3225 chanserv
::channel_emptied
({CHAN
=> $cn});
3227 $get_squit_empty_chans->finish;
3230 $unlock_tables->execute; $unlock_tables->finish;
3233 sub nick_change
($$$) {
3234 my ($user, $new, $time) = @_;
3235 my $old = $user->{NICK
};
3236 return if(lc $old eq lc $new);
3237 print "NICK CHANGE: $old -> $new ($time)\n";
3240 $nick_change->execute($new, $old);
3241 $add_nickchg->execute($ircline, $new, $new);
3243 if($new =~ /^guest/i) {
3244 $get_guest->execute($new);
3245 if($get_guest->fetchrow_array) {
3246 $set_guest->execute(0, $new);
3252 my $user = { NICK
=> $new, AGENT
=> $nsuser };
3254 ircd
::setumode
($nsuser, $user, '-r')
3255 unless check_identify
({ NICK
=> $new });
3257 sub handle_oper
($) {
3259 my $nick = $user->{NICK
};
3261 my $id = get_user_id
($user);
3262 $get_umodes->execute($id);
3263 my ($omodes) = $get_umodes->fetchrow_array;
3264 $set_umodes->execute(modes
::add
($omodes, "o", 0), $id);
3265 #this is _safe_. even an oper block with no privs gets +o
3266 #it's just not passed to srsv for some reason, all we get is :UID opertype X
3269 my ($user, $modes) = @_;
3270 my $nick = $user->{NICK
};
3273 my $id = get_user_id
($user);
3275 $get_umodes->execute($id);
3276 my ($omodes) = $get_umodes->fetchrow_array;
3277 $set_umodes->execute(modes
::add
($omodes, $modes, 0), $id);
3280 my %modelist = modes
::splitumodes
($modes);
3281 if (defined($modelist{x
})) {
3282 if($modelist{x
} eq '-') {
3283 my ($ident, $host) = get_host
($user);
3284 do_chghost
(undef, $nick, $host, 1);
3286 elsif(($modelist{x
} eq '+') and !defined($modelist{t
}) ) {
3287 my (undef, $cloakhost) = get_cloakhost
($user);
3289 do_chghost
(undef, $nick, $cloakhost, 1);
3291 ircd
::userhost
($nick);
3296 # awaiting resolution UnrealIRCd bug 2613
3297 elsif ($modelist{t
} eq '-') {
3298 my %omodelist = modes
::splitumodes
($omodes);
3299 if($omodelist->{x
} eq '+') {
3300 my (undef, $cloakhost) = get_cloakhost
($user);
3302 do_chghost
(undef, $nick, $cloakhost, 1);
3304 ircd
::userhost
($nick);
3309 release_lock
($nick);
3311 # Else we will get it in a sethost or chghost
3312 # Also be aware, our tracking of umodes xt is imperfect
3313 # as the ircd doesn't always report it to us
3314 # This might need fixing up in chghost()
3317 sub killhandle
($$$$) {
3318 my ($src, $dst, $path, $reason) = @_;
3319 unless (is_agent
($dst)) {
3320 nick_delete
($dst, "Killed ($src ($reason))");
3325 my($src, $nick, $ip) = @_;
3326 my $user = { 'NICK' => $nick };
3327 my $new = $newuser{lc $nick};
3328 delete $newuser{lc $nick};
3329 #my $targetid = get_nick_id($target);
3330 my $iip; my @ips = split(/\./, $ip);
3331 for(my $i; $i < 4; $i++) {
3332 $iip += $ips[$i] * (2 ** ((3 - $i) * 8));
3337 my $id = get_user_id
($user);
3338 set_ip
($user, $iip);
3339 my $killed = kill_clones
($user, $iip);
3341 release_lock
($nick);
3343 nick_create_post
($nick) if(!$killed and $new);
3347 my ($src, $dst, $vhost) = @_;
3348 my $user = { NICK
=> $dst };
3349 my $uid = get_user_id
($user);
3352 do_chghost
($src, $dst, $vhost, 1);
3354 $get_umodes->execute($uid);
3355 my ($omodes) = $get_umodes->fetchrow_array;
3356 # I'm told that this is only valid if CLK is set, and
3357 # there is no good way yet to get info from the ircd/net
3358 # module to this code. it stinks of ircd-specific too
3359 # Also, we currently do any USERHOST replies as CHGHOST events
3360 # However, that is no longer necessary with CLK
3361 $set_umodes->execute(modes
::add
($omodes, '+xt', 0), $uid);
3365 sub do_chghost
($$$;$) {
3366 # Don't use this for the handler,
3367 # this is only for internal use
3368 # where we don't want full loopback semantics.
3369 # We call it from the normal handler.
3370 my ($src, $dst, $vhost, $no_lock) = @_;
3371 # $no_lock is for where we already took the lock in the caller
3372 # MySQL's GET LOCK doesn't allow recursive locks
3373 my $user = { NICK
=> $dst };
3374 my $uid = get_user_id
($user);
3376 $update_regnick_vhost->execute($vhost, $uid);
3377 $update_regnick_vhost->finish();
3379 get_lock
($dst) unless $no_lock;
3381 set_vhost
($user, $vhost);
3382 chanserv
::akick_alluser
($user);
3384 release_lock
($dst) unless $no_lock;
3388 my ($src, $dst, $ident) = @_;
3389 my $user = { NICK
=> $dst };
3391 set_ident
($user, $ident);
3392 chanserv
::akick_alluser
($user);