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