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