]>
Commit | Line | Data |
---|---|---|
5975999e | 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 memoserv; | |
17 | ||
18 | use strict; | |
19 | use DBI qw(:sql_types); | |
20 | #use constant { | |
21 | # READ => 1, | |
22 | # DEL => 2, | |
23 | # ACK => 4, | |
24 | # NOEXP => 8 | |
25 | #}; | |
26 | ||
27 | use SrSv::Agent qw(is_agent); | |
28 | ||
29 | use SrSv::Time; | |
30 | use SrSv::Text::Format qw(columnar); | |
31 | use SrSv::Errors; | |
32 | ||
33 | use SrSv::User qw(get_user_nick get_user_id :flood); | |
34 | use SrSv::User::Notice; | |
35 | use SrSv::Help qw( sendhelp ); | |
36 | ||
37 | use SrSv::NickReg::Flags; | |
38 | use SrSv::NickReg::User qw(is_identified get_nick_user_nicks); | |
39 | ||
40 | use SrSv::MySQL '$dbh'; | |
41 | ||
42 | use SrSv::Util qw( makeSeqList ); | |
43 | ||
44 | use constant ( | |
45 | MAX_MEMO_LEN => 400 | |
46 | ); | |
47 | ||
48 | our $msnick_default = 'MemoServ'; | |
49 | our $msnick = $msnick_default; | |
2eef9154 | 50 | our $msuser = { NICK => $msnick, ID => "123AAAAAE" }; |
5975999e | 51 | our ( |
52 | $send_memo, $send_chan_memo, $get_chan_recipients, | |
53 | ||
54 | $get_memo_list, | |
55 | ||
56 | $get_memo, $get_memo_full, $get_memo_count, $get_unread_memo_count, | |
57 | ||
58 | $set_flag, | |
59 | ||
60 | $delete_memo, $purge_memos, $delete_all_memos, | |
61 | $memo_chgroot, | |
62 | ||
63 | $add_ignore, $get_ignore_num, $del_ignore_nick, $list_ignore, $chk_ignore, | |
64 | $wipe_ignore, $purge_ignore, | |
2eef9154 | 65 | $get_first_unread |
5975999e | 66 | ); |
67 | ||
68 | sub init() { | |
2eef9154 | 69 | $get_first_unread = $dbh->prepare("SELECT memo.src, memo.chan, memo.time, memo.flag, memo.msg FROM memo, nickreg WHERE nickreg.nick=? AND memo.dstid=nickreg.id AND memo.flag=0 LIMIT 1"); |
5975999e | 70 | $send_memo = $dbh->prepare("INSERT INTO memo SELECT ?, id, NULL, UNIX_TIMESTAMP(), NULL, ? FROM nickreg WHERE nick=?"); |
71 | $send_chan_memo = $dbh->prepare("INSERT INTO memo SELECT ?, nickreg.id, ?, ?, NULL, ? FROM chanacc, nickreg | |
72 | WHERE chanacc.chan=? AND chanacc.level >= ? AND chanacc.nrid=nickreg.id | |
73 | AND !(nickreg.flags & ". NRF_NOMEMO() . ")"); | |
74 | $get_chan_recipients = $dbh->prepare("SELECT user.nick FROM user, nickid, nickreg, chanacc WHERE | |
75 | user.id=nickid.id AND nickid.nrid=chanacc.nrid AND chanacc.nrid=nickreg.id AND chanacc.chan=? | |
76 | AND level >= ? AND | |
77 | !(nickreg.flags & ". NRF_NOMEMO() . ")"); | |
78 | ||
79 | $get_memo_list = $dbh->prepare("SELECT memo.src, memo.chan, memo.time, memo.flag, memo.msg FROM memo, nickreg WHERE nickreg.nick=? AND memo.dstid=nickreg.id ORDER BY memo.time ASC"); | |
80 | ||
81 | $get_memo = $dbh->prepare("SELECT memo.src, memo.chan, memo.time | |
82 | FROM memo JOIN nickreg ON (memo.dstid=nickreg.id) WHERE nickreg.nick=? ORDER BY memo.time ASC LIMIT 1 OFFSET ?"); | |
83 | $get_memo->bind_param(2, 0, SQL_INTEGER); | |
84 | $get_memo_full = $dbh->prepare("SELECT memo.src, memo.chan, memo.time, memo.flag, memo.msg FROM memo, nickreg WHERE nickreg.nick=? AND memo.dstid=nickreg.id ORDER BY memo.time ASC LIMIT 1 OFFSET ?"); | |
85 | $get_memo_full->bind_param(2, 0, SQL_INTEGER); | |
86 | $get_memo_count = $dbh->prepare("SELECT COUNT(*) FROM memo, nickreg WHERE nickreg.nick=? AND memo.dstid=nickreg.id"); | |
87 | $get_unread_memo_count = $dbh->prepare("SELECT COUNT(*) FROM memo, nickreg WHERE nickreg.nick=? AND memo.dstid=nickreg.id AND memo.flag=0"); | |
88 | ||
89 | $set_flag = $dbh->prepare("UPDATE memo, nickreg SET memo.flag=? WHERE memo.src=? AND nickreg.nick=? AND memo.dstid=nickreg.id AND memo.chan=? AND memo.time=?"); | |
90 | ||
91 | $delete_memo = $dbh->prepare("DELETE FROM memo USING memo, nickreg WHERE memo.src=? AND nickreg.nick=? AND memo.dstid=nickreg.id AND memo.chan=? AND memo.time=?"); | |
92 | $purge_memos = $dbh->prepare("DELETE FROM memo USING memo, nickreg WHERE nickreg.nick=? AND memo.dstid=nickreg.id AND memo.flag=1"); | |
93 | $delete_all_memos = $dbh->prepare("DELETE FROM memo USING memo, nickreg WHERE nickreg.nick=? AND memo.dstid=nickreg.id"); | |
94 | ||
95 | $add_ignore = $dbh->prepare("INSERT INTO ms_ignore (ms_ignore.nrid, ms_ignore.ignoreid, time) | |
96 | SELECT nickreg.id, ignorenick.id, UNIX_TIMESTAMP() FROM nickreg, nickreg AS ignorenick | |
97 | WHERE nickreg.nick=? AND ignorenick.nick=?"); | |
98 | $del_ignore_nick = $dbh->prepare("DELETE FROM ms_ignore USING ms_ignore | |
99 | JOIN nickreg ON (ms_ignore.nrid=nickreg.id) | |
100 | JOIN nickreg AS ignorenick ON(ms_ignore.ignoreid=ignorenick.id) | |
101 | WHERE nickreg.nick=? AND ignorenick.nick=?"); | |
102 | $get_ignore_num = $dbh->prepare("SELECT ignorenick.nick FROM ms_ignore | |
103 | JOIN nickreg ON (ms_ignore.nrid=nickreg.id) | |
104 | JOIN nickreg AS ignorenick ON(ms_ignore.ignoreid=ignorenick.id) | |
105 | WHERE nickreg.nick=? | |
106 | ORDER BY ms_ignore.time LIMIT 1 OFFSET ?"); | |
107 | $get_ignore_num->bind_param(2, 0, SQL_INTEGER); | |
108 | ||
109 | $list_ignore = $dbh->prepare("SELECT ignorenick.nick, ms_ignore.time | |
110 | FROM ms_ignore, nickreg, nickreg AS ignorenick | |
111 | WHERE nickreg.nick=? AND ms_ignore.nrid=nickreg.id AND ms_ignore.ignoreid=ignorenick.id | |
112 | ORDER BY ms_ignore.time"); | |
113 | $chk_ignore = $dbh->prepare("SELECT 1 | |
114 | FROM ms_ignore, nickreg, nickreg AS ignorenick | |
115 | WHERE nickreg.nick=? AND ms_ignore.nrid=nickreg.id AND ignorenick.nick=? AND ms_ignore.ignoreid=ignorenick.id"); | |
116 | ||
117 | $wipe_ignore = $dbh->prepare("DELETE FROM ms_ignore USING ms_ignore JOIN nickreg ON(ms_ignore.nrid=nickreg.id) WHERE nickreg.nick=?"); | |
118 | $purge_ignore = $dbh->prepare("DELETE FROM ms_ignore USING ms_ignore JOIN nickreg ON(ms_ignore.ignoreid=nickreg.id) WHERE nickreg.nick=?"); | |
119 | } | |
120 | ||
121 | ### MEMOSERV COMMANDS ### | |
122 | ||
123 | sub dispatch($$$) { | |
2eef9154 | 124 | my ($user, $dstUser, $msg) = @_; |
5975999e | 125 | $msg =~ s/^\s+//; |
126 | my @args = split(/\s+/, $msg); | |
127 | my $cmd = shift @args; | |
2eef9154 | 128 | $user -> {AGENT} = $dstUser; |
129 | return unless (lc $dstUser->{NICK} eq lc $msnick); | |
130 | get_user_id ($user); | |
5975999e | 131 | return if flood_check($user); |
132 | ||
133 | if($cmd =~ /^send$/i) { | |
134 | if(@args >= 2) { | |
135 | my @args = split(/\s+/, $msg, 3); | |
136 | ms_send($user, $args[1], $args[2], 0); | |
137 | } else { | |
138 | notice($user, 'Syntax: SEND <recipient> <message>'); | |
139 | } | |
140 | } | |
141 | elsif($cmd =~ /^csend$/i) { | |
142 | if(@args >= 3 and $args[1] =~ /^(?:[uvhas]op|co?f(ounder)?|founder)$/i) { | |
143 | my @args = split(/\s+/, $msg, 4); | |
144 | my $level = chanserv::xop_byname($args[2]); | |
145 | ms_send($user, $args[1], $args[3], $level); | |
146 | } else { | |
147 | notice($user, 'Syntax: CSEND <recipient> <uop|vop|hop|aop|sop|cf|founder> <message>'); | |
148 | } | |
149 | } | |
150 | elsif($cmd =~ /^read$/i) { | |
2eef9154 | 151 | if(@args == 1 and (lc($args[0]) eq 'last' or $args[0] > 0 or (lc($args[0]) eq 'unread'))) { |
5975999e | 152 | ms_read($user, $args[0]); |
153 | } else { | |
2eef9154 | 154 | notice($user, 'Syntax: READ <num|LAST|UNREAD>'); |
5975999e | 155 | } |
156 | } | |
157 | elsif($cmd =~ /^list$/i) { | |
158 | ms_list($user); | |
159 | } | |
160 | elsif($cmd =~ /^del(ete)?$/i) { | |
161 | if(@args >= 1 and (lc($args[0]) eq 'all' or $args[0] > 0)) { | |
162 | ms_delete($user, $args[0]); | |
163 | } else { | |
164 | notice($user, 'Syntax: DELETE <num|num1-num2|ALL>'); | |
165 | } | |
166 | } | |
167 | elsif($cmd =~ /^ign(ore)?$/i) { | |
168 | my $cmd2 = shift @args; | |
169 | if($cmd2 =~ /^a(dd)?$/i) { | |
170 | if(@args == 1) { | |
171 | ms_ignore_add($user, $args[0]); | |
172 | } | |
173 | else { | |
174 | notice($user, 'Syntax: IGNORE ADD <nick>'); | |
175 | } | |
176 | } | |
177 | elsif($cmd2 =~ /^d(el)?$/i) { | |
178 | if(@args == 1) { | |
179 | ms_ignore_del($user, $args[0]); | |
180 | } | |
181 | else { | |
182 | notice($user, 'Syntax: IGNORE DEL [nick|num]'); | |
183 | } | |
184 | } | |
185 | elsif($cmd2 =~ /^l(ist)?$/i) { | |
186 | ms_ignore_list($user); | |
187 | } | |
188 | else { | |
189 | notice($user, 'Syntax: IGNORE <ADD|DEL|LIST> [nick|num]'); | |
190 | } | |
191 | } | |
192 | elsif($cmd =~ /^help$/i) { | |
193 | sendhelp($user, 'memoserv', @args); | |
194 | } | |
195 | else { | |
196 | notice($user, "Unrecognized command. For help, type: \002/ms help\002"); | |
197 | } | |
198 | } | |
199 | ||
200 | sub ms_send($$$$) { | |
201 | my ($user, $dst, $msg, $level) = @_; | |
202 | my $src = get_user_nick($user); | |
203 | ||
204 | my $root = auth($user) or return; | |
205 | ||
206 | if(length($msg) > MAX_MEMO_LEN()) { | |
207 | notice($user, 'Memo too long. Maximum memo length is '.MAX_MEMO_LEN().' characters.'); | |
208 | return; | |
209 | } | |
210 | ||
211 | if($dst =~ /^#/) { | |
212 | my $chan = { CHAN => $dst }; | |
213 | unless(chanserv::is_registered($chan)) { | |
214 | notice($user, "$dst is not registered"); | |
215 | return; | |
216 | } | |
217 | ||
218 | my $srcnick = chanserv::can_do($chan, 'MEMO', $user) or return; | |
219 | ||
220 | send_chan_memo($srcnick, $chan, $msg, $level); | |
221 | } else { | |
222 | nickserv::chk_registered($user, $dst) or return; | |
223 | ||
224 | if (nr_chk_flag($dst, NRF_NOMEMO(), +1)) { | |
225 | notice($user, "\002$dst\002 is not accepting memos."); | |
226 | return; | |
227 | } | |
228 | $chk_ignore->execute(nickserv::get_root_nick($dst), $root); | |
229 | if ($chk_ignore->fetchrow_array) { | |
230 | notice($user, "\002$dst\002 is not accepting memos."); | |
231 | return; | |
232 | } | |
233 | ||
234 | send_memo($src, $dst, $msg); | |
235 | } | |
236 | ||
237 | notice($user, "Your memo has been sent."); | |
238 | } | |
239 | ||
240 | sub ms_read($$) { | |
241 | my ($user, $num) = @_; | |
242 | my ($from, $chan, $time, $flag, $msg); | |
243 | my $src = get_user_nick($user); | |
244 | ||
245 | my $root = auth($user) or return; | |
246 | ||
247 | my @nums; | |
248 | if(lc($num) eq 'last') { | |
249 | $get_memo_count->execute($root); | |
250 | ($num) = $get_memo_count->fetchrow_array; | |
251 | if (!$num) { | |
252 | notice($user, "Memo \002$num\002 not found."); | |
253 | return; | |
254 | } | |
255 | @nums = ($num); | |
2eef9154 | 256 | } |
257 | elsif (lc($num) eq 'unread') { | |
258 | $get_first_unread->execute($root); | |
259 | $get_memo_full->execute($root, $num-1); | |
260 | unless(($from, $chan, $time, $flag, $msg) = $get_first_unread->fetchrow_array) { | |
261 | notice($user, "You have no unread memos."); | |
262 | return; | |
263 | } | |
264 | $set_flag->execute(1, $from, $root, $chan, $time); | |
265 | my @reply; | |
266 | push @reply, "Memo \002$num\002 from \002$from\002 ". | |
267 | ($chan ? "to \002$chan\002 " : "to \002$root\002 "). | |
268 | "at ".gmtime2($time), $msg, ' --'; | |
269 | notice ($user, @reply); | |
270 | return; | |
271 | } | |
272 | else { | |
5975999e | 273 | @nums = makeSeqList($num); |
274 | } | |
275 | ||
276 | my $count = 0; | |
277 | my @reply; | |
278 | while (my $num = shift @nums) { | |
279 | if (++$count > 5) { | |
280 | push @reply, "You can only read 5 memos at a time."; | |
281 | last; | |
282 | } | |
283 | $get_memo_full->execute($root, $num-1); | |
284 | unless(($from, $chan, $time, $flag, $msg) = $get_memo_full->fetchrow_array) { | |
285 | push @reply, "Memo \002$num\002 not found."; | |
286 | next; | |
287 | } | |
288 | $set_flag->execute(1, $from, $root, $chan, $time); | |
289 | push @reply, "Memo \002$num\002 from \002$from\002 ". | |
290 | ($chan ? "to \002$chan\002 " : "to \002$root\002 "). | |
291 | "at ".gmtime2($time), ' ', ' '.$msg, ' --'; | |
292 | } | |
293 | notice($user, @reply); | |
294 | } | |
295 | ||
296 | sub ms_list($) { | |
297 | my ($user) = @_; | |
298 | my ($i, @data, $mnlen, $mclen); | |
299 | my $src = get_user_nick($user); | |
300 | ||
301 | my $root = auth($user) or return; | |
302 | ||
303 | $get_memo_list->execute($root); | |
304 | while(my ($from, $chan, $time, $flag, $msg) = $get_memo_list->fetchrow_array) { | |
305 | $i++; | |
306 | ||
307 | push @data, [ | |
308 | ($flag ? '' : "\002") . $i, | |
309 | $from, $chan, gmtime2($time), | |
310 | (length($msg) > 20 ? substr($msg, 0, 17) . '...' : $msg) | |
311 | ]; | |
312 | } | |
313 | ||
314 | unless(@data) { | |
315 | notice($user, "You have no memos."); | |
316 | return; | |
317 | } | |
318 | ||
319 | notice($user, columnar( { TITLE => "Memo list for \002$root\002. To read, type \002/ms read <num>\002", | |
320 | NOHIGHLIGHT => nr_chk_flag_user($user, NRF_NOHIGHLIGHT) }, @data)); | |
321 | } | |
322 | ||
323 | sub ms_delete($@) { | |
324 | my ($user, @args) = @_; | |
325 | my $src = get_user_nick($user); | |
326 | ||
327 | my $root = auth($user) or return; | |
328 | ||
329 | if(scalar(@args) == 1 and lc($args[0]) eq 'all') { | |
330 | $delete_all_memos->execute($root); | |
331 | notice($user, 'All of your memos have been deleted.'); | |
332 | return; | |
333 | } | |
334 | my (@deleted, @notDeleted); | |
335 | foreach my $num (reverse makeSeqList(@args)) { | |
336 | if(int($num) ne $num) { # can this happen, given makeSeqList? | |
337 | notice($user, "\002$num\002 is not an integer number"); | |
338 | next; | |
339 | } | |
340 | my ($from, $chan, $time); | |
341 | $get_memo->execute($root, $num-1); | |
342 | if(my ($from, $chan, $time) = $get_memo->fetchrow_array) { | |
343 | $delete_memo->execute($from, $root, $chan, $time); | |
344 | push @deleted, $num; | |
345 | } else { | |
346 | push @notDeleted, $num; | |
347 | } | |
348 | } | |
349 | if(scalar(@deleted)) { | |
350 | my $plural = (scalar(@deleted) == 1); | |
351 | my $msg = sprintf("Memo%s deleted: ".join(', ', @deleted), ($plural ? '' : 's')); | |
352 | notice($user, $msg); | |
353 | } | |
354 | if(scalar(@notDeleted)) { | |
355 | my $msg = sprintf("Memos not found: ".join(', ', @notDeleted)); | |
356 | notice($user, $msg); | |
357 | } | |
358 | } | |
359 | ||
360 | sub ms_ignore_add($$) { | |
361 | my ($user, $nick) = @_; | |
362 | my $src = get_user_nick($user); | |
363 | ||
364 | unless(is_identified($user, $src) or adminserv::can_do($user, 'SERVOP')) { | |
365 | notice($user, $err_deny); | |
366 | return; | |
367 | } | |
368 | ||
369 | my $nickroot = nickserv::get_root_nick($nick); | |
370 | unless ($nickroot) { | |
371 | notice($user, "$nick is not registered"); | |
372 | return; | |
373 | } | |
374 | ||
375 | my $srcroot = nickserv::get_root_nick($src); | |
376 | ||
377 | $add_ignore->execute($srcroot, $nickroot); | |
378 | ||
379 | notice($user, "\002$nick\002 (\002$nickroot\002) added to \002$src\002 (\002$srcroot\002) memo ignore list."); | |
380 | } | |
381 | ||
382 | sub ms_ignore_del($$) { | |
383 | my ($user, $entry) = @_; | |
384 | my $src = get_user_nick($user); | |
385 | ||
386 | unless(is_identified($user, $src) or adminserv::can_do($user, 'SERVOP')) { | |
387 | notice($user, $err_deny); | |
388 | return; | |
389 | } | |
390 | my $srcroot = nickserv::get_root_nick($src); | |
391 | ||
392 | my $ignorenick; | |
393 | if (misc::isint($entry)) { | |
394 | $get_ignore_num->execute($srcroot, $entry - 1); | |
395 | ($ignorenick) = $get_ignore_num->fetchrow_array(); | |
396 | $get_ignore_num->finish(); | |
397 | } | |
398 | my $ret = $del_ignore_nick->execute($srcroot, ($ignorenick ? $ignorenick : $entry)); | |
399 | if($ret == 1) { | |
400 | notice($user, "Delete succeeded for ($srcroot): $entry"); | |
401 | } | |
402 | else { | |
403 | notice($user, "Delete failed for ($srcroot): $entry. entry does not exist?"); | |
404 | } | |
405 | } | |
406 | ||
407 | sub ms_ignore_list($) { | |
408 | my ($user) = @_; | |
409 | my $src = get_user_nick($user); | |
410 | ||
411 | unless(is_identified($user, $src) or adminserv::can_do($user, 'SERVOP')) { | |
412 | notice($user, $err_deny); | |
413 | return; | |
414 | } | |
415 | my $srcroot = nickserv::get_root_nick($src); | |
416 | ||
417 | my @data; | |
418 | $list_ignore->execute($srcroot); | |
419 | while (my ($nick, $time) = $list_ignore->fetchrow_array) { | |
420 | push @data, [$nick, '('.gmtime2($time).')']; | |
421 | } | |
422 | ||
423 | notice($user, columnar({TITLE => "Memo ignore list for \002$src\002:", | |
424 | NOHIGHLIGHT => nr_chk_flag_user($user, NRF_NOHIGHLIGHT)}, @data)); | |
425 | } | |
426 | ||
427 | sub notify($;$) { | |
428 | my ($user, $root) = @_; | |
429 | my (@nicks); | |
430 | ||
2eef9154 | 431 | unless(ref($user) eq "HASH") { |
5975999e | 432 | $user = { NICK => $user }; |
433 | } | |
434 | ||
435 | if($root) { @nicks = ($root) } | |
436 | else { @nicks = nickserv::get_id_nicks($user) } | |
437 | ||
438 | my $hasmemos; | |
439 | foreach my $n (@nicks) { | |
440 | $get_unread_memo_count->execute($n); | |
441 | my ($c) = $get_unread_memo_count->fetchrow_array; | |
442 | next unless $c; | |
443 | notice($user, "You have \002$c\002 unread memo(s). " . (@nicks > 1 ? "(\002$n\002) " : '')); | |
444 | $hasmemos = 1; | |
445 | } | |
446 | ||
447 | notice($user, "To view them, type: \002/ms list\002") if $hasmemos; | |
448 | } | |
449 | ||
450 | ### DATABASE UTILITY FUNCTIONS ### | |
451 | ||
452 | sub send_memo($$$) { | |
453 | my ($src, $dst, $msg) = @_; | |
454 | ||
455 | # This construct is intended to allow agents to send memos. | |
456 | # Unfortunately this is raceable against %nickserv::enforcers. | |
457 | # I don't want to change the %nickserv::enforcers decl tho, s/my/our/ | |
458 | $src = (is_agent($src) ? $src : nickserv::get_root_nick($src)); | |
459 | $dst = nickserv::get_root_nick($dst); | |
460 | ||
461 | $send_memo->execute($src, $msg, $dst); | |
462 | notice_all_nicks($dst, "You have a new memo from \002$src\002. To read it, type: \002/ms read last\002"); | |
463 | } | |
464 | ||
465 | sub send_chan_memo($$$$) { | |
466 | my ($src, $chan, $msg, $level) = @_; | |
467 | my $cn = $chan->{CHAN}; | |
468 | $src = (is_agent($src) ? $src : nickserv::get_root_nick($src)); | |
469 | ||
470 | $send_chan_memo->execute($src, $cn, time(), $msg, $cn, $level); | |
471 | # "INSERT INTO memo SELECT ?, nick, ?, ?, 0, ? FROM chanacc WHERE chan=? AND level >= ?" | |
472 | ||
473 | $get_chan_recipients->execute($cn, $level); | |
474 | while(my ($u) = $get_chan_recipients->fetchrow_array) { | |
2eef9154 | 475 | notice({ NICK => $u, AGENT => $msuser }, |
5975999e | 476 | "You have a new memo from \002$src\002 to \002$cn\002. To read it, type: \002/ms read last\002"); |
477 | } | |
478 | } | |
479 | ||
480 | sub notice_all_nicks($$) { | |
481 | my ($nick, $msg) = @_; | |
482 | ||
483 | foreach my $u (get_nick_user_nicks $nick) { | |
2eef9154 | 484 | notice({ NICK => $u, AGENT => $msuser }, $msg); |
5975999e | 485 | } |
486 | } | |
487 | ||
488 | sub auth($) { | |
489 | my ($user) = @_; | |
490 | my $src = get_user_nick($user); | |
491 | ||
492 | my $root = nickserv::get_root_nick($src); | |
493 | unless($root) { | |
494 | notice($user, "Your nick is not registered."); | |
495 | return 0; | |
496 | } | |
497 | ||
498 | unless(is_identified($user, $root)) { | |
499 | notice($user, $err_deny); | |
500 | return 0; | |
501 | } | |
502 | ||
503 | return $root; | |
504 | } | |
505 | ||
506 | ### IRC EVENTS ### | |
507 | ||
508 | 1; |