]>
jfr.im git - irc/SurrealServices/srsv.git/blob - branches/0.5.0/modules/serviceslibs/botserv.pm
1 # This file is part of SurrealServices.
3 # SurrealServices is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # SurrealServices is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with SurrealServices; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 use SrSv
::IRCd
::State
qw($ircline synced initial_synced %IRCd_capabilities);
24 use SrSv
::Process
::Worker
'ima_worker'; #FIXME
26 use SrSv
::Text
::Format
qw(columnar);
30 use SrSv
::Conf2Consts
qw( main services );
32 use SrSv
::User
qw(get_user_nick get_user_id :flood);
33 use SrSv
::User
::Notice
;
34 use SrSv
::Help
qw( sendhelp );
35 use SrSv
::ChanReg
::Flags
;
36 use SrSv
::NickReg
::Flags
qw(NRF_NOHIGHLIGHT nr_chk_flag_user);
38 use SrSv
::MySQL
'$dbh';
45 our $bsnick_default = 'BotServ';
46 our $bsnick = $bsnick_default;
48 our $bsuser = { NICK
=> $bsnick, ID
=> ircd
::getAgentUuid
($bsnick) };
50 *agent
= \
&chanserv
::agent
;
52 our $calc_safe = new Safe
;
55 $get_all_bots, $get_botchans, $get_botstay_chans, $get_chan_bot, $get_bots_chans, $get_bot_info,
57 $create_bot, $delete_bot, $delete_bot_allchans, $assign_bot, $unassign_bot,
58 $change_bot, $update_chanreg_bot,
62 $set_flag, $unset_flag, $get_flags
66 $bsuser = { NICK
=> $bsnick, ID
=> ircd
::getAgentUuid
($bsnick) };
67 $get_all_bots = $dbh->prepare("SELECT nick, ident, vhost, gecos, flags FROM bot");
68 $get_botchans = $dbh->prepare("SELECT chan, COALESCE(bot, '$chanserv::csnick') FROM chanreg WHERE bot != '' OR (flags & ". CRF_BOTSTAY
() . ")");
69 $get_botstay_chans = $dbh->prepare("SELECT chan, COALESCE(bot, '$chanserv::csnick') FROM chanreg WHERE (flags & ".
71 $get_chan_bot = $dbh->prepare("SELECT bot FROM chanreg WHERE chan=?");
72 $get_bots_chans = $dbh->prepare("SELECT chan FROM chanreg WHERE bot=?");
73 $get_bot_info = $dbh->prepare("SELECT nick, ident, vhost, gecos, flags FROM bot WHERE nick=?");
75 $create_bot = $dbh->prepare("INSERT INTO bot SET nick=?, ident=?, vhost=?, gecos=?");
76 $delete_bot = $dbh->prepare("DELETE FROM bot WHERE nick=?");
77 $delete_bot_allchans = $dbh->prepare("UPDATE chanreg SET bot='' WHERE bot=?");
78 $change_bot = $dbh->prepare("UPDATE bot SET nick=?, ident=?, vhost=?, gecos=? WHERE nick=?");
79 $update_chanreg_bot = $dbh->prepare("UPDATE chanreg SET bot=? WHERE bot=?");
81 $assign_bot = $dbh->prepare("UPDATE chanreg, bot SET chanreg.bot=bot.nick WHERE bot.nick=? AND chan=?");
82 $unassign_bot = $dbh->prepare("UPDATE chanreg SET chanreg.bot='' WHERE chan=?");
84 $is_bot = $dbh->prepare("SELECT 1 FROM bot WHERE nick=?");
85 $has_bot = $dbh->prepare("SELECT 1 FROM chanreg WHERE chan=? AND bot != ''");
87 $set_flag = $dbh->prepare("UPDATE bot SET flags=(flags | (?)) WHERE nick=?");
88 $unset_flag = $dbh->prepare("UPDATE bot SET flags=(flags & ~(?)) WHERE nick=?");
89 $get_flags = $dbh->prepare("SELECT flags FROM bot WHERE bot.nick=?");
91 register
() unless ima_worker
; #FIXME
95 $bsuser = { NICK
=> $bsnick, ID
=> ircd
::getAgentUuid
($bsnick) };
96 my ($user, $dstUser, $msg) = @_;
97 $user -> {AGENT
} = $bsuser;
98 my $src = $user->{NICK
};
99 my $dst = $dstUser->{NICK
};
100 if(lc $dstUser->{NICK
} eq lc $bsnick or lc $dstUser->{NICK
} eq lc $bsnick_default ) {
101 bs_dispatch
($user, $dstUser, $msg);
103 elsif($dst =~ /^#/) {
105 $has_bot->execute($dst);
106 return unless($has_bot->fetchrow_array);
107 chan_dispatch
($user, $dst, $msg);
109 chan_msg
($src, $dst, $msg);
113 $is_bot->execute($dst);
114 if($is_bot->fetchrow_array) {
115 bot_dispatch
($src, $dst, $msg);
120 ### BOTSERV COMMANDS ###
122 sub bs_dispatch
($$$) {
123 my ($user, $dst, $msg) = @_;
125 my @args = split(/\s+/, $msg);
126 my $cmd = shift @args;
128 $user->{AGENT
} = $dst;
129 my $src = $user->{NICK
};
131 return if flood_check
($user);
133 if($cmd =~ /^assign$/i) {
135 bs_assign
($user, {CHAN
=> $args[0]}, $args[1]);
137 notice
($user, 'Syntax: ASSIGN <#channel> <bot>');
140 elsif ($cmd =~ /^unassign$/i) {
142 bs_assign
($user, {CHAN
=> $args[0]}, '');
144 notice
($user, 'Syntax: UNASSIGN <#channel>');
147 elsif ($cmd =~ /^list$/i) {
151 notice
($user, 'Syntax: LIST');
154 elsif ($cmd =~ /^add$/i) {
156 @args = split(/\s+/, $msg, 5);
157 bs_add
($user, $args[1], $args[2], $args[3], $args[4]);
159 notice
($user, 'Syntax: ADD <nick> <ident> <vhost> <realname>');
162 elsif ($cmd =~ /^change$/i) {
164 @args = split(/\s+/, $msg, 6);
165 bs_change
($user, $args[1], $args[2], $args[3], $args[4], $args[5]);
167 notice
($user, 'Syntax: ADD <oldnick> <nick> <ident> <vhost> <realname>');
170 elsif ($cmd =~ /^del(ete)?$/i) {
172 bs_del
($user, $args[0]);
174 notice
($user, 'Syntax: DEL <botnick>');
177 elsif($cmd =~ /^set$/i) {
179 bs_set
($user, $args[0], $args[1], $args[2]);
181 notice
($user, 'Syntax: SET <botnick> <option> <value>');
184 elsif($cmd =~ /^seen$/i) {
186 nickserv
::ns_seen
($user, @args);
188 notice
($user, 'Syntax: SEEN <nick> [nick ...]');
192 elsif($cmd =~ /^(say|act)$/i) {
194 my @args = split(/\s+/, $msg, 3);
195 my $botmsg = $args[2];
196 $botmsg = "\001ACTION $botmsg\001" if(lc $cmd eq 'act');
197 bot_say
($user, {CHAN
=> $args[1]}, $botmsg);
199 notice
($user, 'Syntax: '.uc($cmd).' <#chan> <message>');
202 elsif($cmd =~ /^info$/i) {
204 bs_info
($user, $args[0]);
206 notice
($user, 'Syntax: INFO <botnick>');
209 elsif($cmd =~ /^help$/i) {
210 sendhelp
($user, 'botserv', @args);
212 elsif($cmd =~ /^d(ice)?$/i) {
213 notice
($user, get_dice
($args[0]));
216 notice
($user, "Unrecognized command. For help, type: \002/bs help\002");
220 # For unassign, set $bot to ''
223 my ($user, $chan, $bot) = @_;
225 chanserv
::chk_registered
($user, $chan) or return;
227 unless (chanserv
::can_do
($chan, 'BotAssign', $user)) {
228 notice
($user, $err_deny);
233 $is_bot->execute($bot);
234 unless($is_bot->fetchrow_array) {
235 notice
($user, "\002$bot\002 is not a bot.");
240 $get_flags->execute($bot);
241 my ($botflags) = $get_flags->fetchrow_array;
242 if (($botflags & F_PRIVATE
) && !adminserv
::can_do
($user, 'BOT')) {
243 notice
($user, $err_deny);
248 my $cn = $chan->{CHAN
};
249 my $src = get_user_nick
($user);
251 if ($oldbot = get_chan_bot
($chan)) {
252 agent_part
($oldbot, $cn, "Unassigned by \002$src\002.");
256 $assign_bot->execute($bot, $cn);
257 my $botUser = { NICK
=>$bot, ID
=>ircd
::getAgentUuid
($bot) };
258 bot_join
($chan, $botUser);
259 notice
($user, "\002$bot\002 now assigned to \002$cn\002.");
261 $unassign_bot->execute($cn);
262 notice
($user, "\002$oldbot\002 removed from \002$cn\002.");
269 my $is_oper = adminserv
::is_svsop
($user, adminserv
::S_HELP
());
271 $get_all_bots->execute();
272 while (my ($botnick, $botident, $bothost, $botgecos, $flags) = $get_all_bots->fetchrow_array) {
274 push @data, [$botnick, "($botident\@$bothost)", $botgecos,
275 (($flags & F_PRIVATE
) ? "Private":"Public")];
277 next if($flags & F_PRIVATE
);
278 push @data, [$botnick, "($botident\@$bothost)", $botgecos];
282 notice
($user, columnar
({TITLE
=> "The following bots are available:",
283 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)}, @data));
287 my ($user, $botnick, $botident, $bothost, $botgecos) = @_;
289 unless (adminserv
::can_do
($user, 'BOT')) {
290 notice
($user, $err_deny);
294 if (my $ret = is_invalid_agentname
($botnick, $botident, $bothost)) {
299 if(nickserv
::is_registered
($botnick)) {
300 notice
($user, "The nick \002$botnick\002 is already registered.");
304 if(nickserv
::is_online
($botnick)) {
305 notice
($user, "The nick \002$botnick\002 is currently in use.");
309 $is_bot->execute($botnick);
310 if($is_bot->fetchrow_array) {
311 notice
($user, "\002$botnick\002 already exists.");
315 $create_bot->execute($botnick, $botident, $bothost, $botgecos);
316 ircd
::sqline
($botnick, $services::qlreason
);
317 agent_connect
($botnick, $botident, $bothost, '+pqBSrz', $botgecos);
318 agent_join
($botnick, main_conf_diag
);
319 my $bot = { NICK
=> $botnick};
321 my $rsuser = { NICK
=> $main::rsnick
};
322 get_user_id
($rsuser);
323 $rsuser->{ID
} = ($rsuser->{ID
});
324 ircd
::setmode
($rsuser, main_conf_diag
, '+h', $bot);
325 notice
($user, "Bot $botnick connected.");
329 my ($user, $botnick) = @_;
331 unless (adminserv
::can_do
($user, 'BOT')) {
332 notice
($user, $err_deny);
335 $is_bot->execute($botnick);
336 if (!$is_bot->fetchrow_array) {
337 notice
($user, "\002$botnick\002 is not a bot.");
341 my $src = get_user_nick
($user);
342 $delete_bot->execute($botnick);
343 agent_quit
($botnick, "Deleted by \002$src\002.");
344 ircd
::unsqline
($botnick);
346 $delete_bot_allchans->execute($botnick);
347 notice
($user, "Bot \002$botnick\002 disconnected.");
351 my ($user, $botnick, $set, $parm) = @_;
353 unless (adminserv
::can_do
($user, 'BOT')) {
354 notice
($user, $err_deny);
357 if($set =~ /^private$/i) {
358 if ($parm =~ /^(on|true)$/i) {
359 set_flag
($botnick, F_PRIVATE
());
360 notice
($user, "\002$botnick\002 is now private.");
362 elsif ($parm =~ /^(off|false)$/i) {
363 unset_flag
($botnick, F_PRIVATE
());
364 notice
($user, "\002$botnick\002 is now public.");
367 notice
($user, 'Syntax: SET <botnick> PRIVATE <ON|OFF>');
370 if($set =~ /^deaf$/i) {
371 if ($parm =~ /^(on|true)$/i) {
372 set_flag
($botnick, F_DEAF
());
373 setagent_umode
($botnick, '+d');
374 notice
($user, "\002$botnick\002 is now deaf.");
376 elsif ($parm =~ /^(off|false)$/i) {
377 unset_flag
($botnick, F_DEAF
());
378 setagent_umode
($botnick, '-d');
379 notice
($user, "\002$botnick\002 is now undeaf.");
382 notice
($user, 'Syntax: SET <botnick> DEAF <ON|OFF>');
388 my ($user, $botnick) = @_;
390 unless (adminserv
::can_do
($user, 'HELP')) {
391 notice
($user, $err_deny);
394 $is_bot->execute($botnick);
395 unless($is_bot->fetchrow_array) {
396 notice
($user, "\002$botnick\002 is not a bot.");
400 $get_bot_info->execute($botnick);
401 my ($nick, $ident, $vhost, $gecos, $flags) = $get_bot_info->fetchrow_array;
402 $get_bot_info->finish();
403 $get_bots_chans->execute($botnick);
405 while (my $chan = $get_bots_chans->fetchrow_array) {
408 $get_bots_chans->finish();
410 notice
($user, columnar
({TITLE
=> "Information for bot \002$nick\002:",
411 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)},
412 ['Mask:', "$ident\@$vhost"], ['Realname:', $gecos],
413 ['Flags:', (($flags & F_PRIVATE
())?'Private ':'').(($flags & F_DEAF
())?'Deaf ':'')],
415 'Assigned to '. @chans.' channel(s):',
416 ' ' . join(' ', @chans)
421 sub bs_change
($$$$$$) {
422 my ($user, $oldnick, $botnick, $botident, $bothost, $botgecos) = @_;
424 if (lc $oldnick eq lc $botnick) {
425 notice
($user, "Error: $oldnick is the same (case-insensitive) as $botnick",
426 "At this time, you cannot change only the ident, host, gecos, or nick-case of a bot.");
430 unless (adminserv
::can_do
($user, 'BOT')) {
431 notice
($user, $err_deny);
435 if (my $ret = is_invalid_agentname
($botnick, $botident, $bothost)) {
440 if(nickserv
::is_registered
($botnick)) {
441 notice
($user, "The nick \002$botnick\002 is already registered.");
445 if(nickserv
::is_online
($botnick)) {
446 notice
($user, "The nick \002$botnick\002 is currently in use.");
450 $is_bot->execute($botnick);
451 if($is_bot->fetchrow_array) {
452 notice
($user, "\002$botnick\002 already exists.");
456 #Create bot first, join it to its chans
457 # then finally delete the old bot
458 # This is to prevent races.
459 $create_bot->execute($botnick, $botident, $bothost, $botgecos);
460 ircd
::sqline
($botnick, $services::qlreason
);
461 agent_connect
($botnick, $botident, $bothost, '+pqBSrz', $botgecos);
462 agent_join
($botnick, main_conf_diag
);
463 my $rsnick = $main::rsnick
;
464 my $rsuser = { NICK
=> $main::rsnick
};
465 get_user_id
($rsuser);
466 $rsuser->{ID
} = ($rsuser->{ID
});
467 my $bot = { NICK
=> $botnick };
469 ircd
::setmode
($rsuser, main_conf_diag
, '+h', $bot);
471 notice
($user, "Bot $botnick connected.");
473 $get_bots_chans->execute($oldnick);
474 while(my ($cn) = $get_bots_chans->fetchrow_array()) {
475 my $chan = { CHAN
=> $cn };
476 my $botUser = { NICK
=>$botnick, ID
=>ircd
::getAgentUuid
($botnick) };
477 bot_join
($chan, $botUser)
478 if chanserv
::get_user_count
($chan) or cr_chk_flag
($chan, CRF_BOTSTAY
(), 1);
480 $get_bots_chans->finish();
482 $update_chanreg_bot->execute($botnick, $oldnick); $update_chanreg_bot->finish();
484 my $src = get_user_nick
($user);
485 $delete_bot->execute($oldnick);
486 agent_quit
($oldnick, "Deleted by \002$src\002.");
487 ircd
::unsqline
($oldnick);
488 notice
($user, "Bot \002$oldnick\002 disconnected.");
491 ### CHANNEL COMMANDS ###
493 sub chan_dispatch
($$$) {
494 my ($user, $cn, $msg) = @_;
495 my $src = $user->{NICK
};
496 my @args = split(/\s+/, $msg);
497 my $cmd = lc(shift @args);
499 my $chan = { CHAN
=> $cn };
500 $user->{AGENT
} = agent
($chan);
501 my $chan = { CHAN
=> $cn };
504 'voice' => \
&give_ops
,
505 'devoice' => \
&give_ops
,
507 'halfop' => \
&give_ops
,
508 'dehop' => \
&give_ops
,
509 'dehalfop' => \
&give_ops
,
511 'deop' => \
&give_ops
,
512 'protect' => \
&give_ops
,
513 'admin' => \
&give_ops
,
514 'deprotect' => \
&give_ops
,
515 'deadmin' => \
&give_ops
,
522 'invite' => \
&invite
,
528 'kickb' => \
&kickban
,
530 'kickban' => \
&kickban
,
532 'bkick' => \
&kickban
,
534 'bankick' => \
&kickban
,
536 'kickmask' => \
&kickmask
,
538 'kmask' => \
&kickmask
,
540 'kickbanmask' => \
&kickbanmask
,
541 'kickbmask' => \
&kickbanmask
,
542 'kickbm' => \
&kickbanmask
,
543 'kbm' => \
&kickbanmask
,
544 'kbanm' => \
&kickbanmask
,
545 'kbanmask' => \
&kickbanmask
,
546 'kbmask' => \
&kickbanmask
,
552 #We really need something that is mostly obvious
553 # and won't be used by any other bots.
554 #TriviaBot I added !trivhelp
555 # I guess anope uses !commands
557 'commands' => \
&help
,
561 'abbreviations' => \
&help
,
569 'banlist' => \
&banlist
,
570 'blist' => \
&banlist
,
583 'resync' => \
&resync
,
592 my ($user, $chan, $cmd, undef, @args) = @_;
594 chanserv
::cs_setmodes
($user, $cmd, $chan, @args);
597 my ($user, $chan, $cmd, undef, @args) = @_;
598 chanserv
::cs_updown
($user, $cmd, $chan->{CHAN
}, @args);
601 my ($user, $chan, $cmd, undef, @args) = @_;
602 if(lc $cmd eq 'molest') {
603 chanserv
::unset_modes
($user, $chan);
605 chanserv
::cs_updown
($user, $cmd, $chan->{CHAN
}, @args);
610 my ($user, $chan, $cmd, undef, @args) = @_;
611 chanserv
::cs_invite
($user, $chan, @args) unless @args == 0;
615 my ($user, $chan, $cmd, undef, @args) = @_;
616 my $target = shift @args or return;
617 chanserv
::cs_kick
($user, $chan, $target, 0, join(' ', @args));
620 my ($user, $chan, $cmd, undef, @args) = @_;
621 my $target = shift @args or return;
622 chanserv
::cs_kick
($user, $chan, $target, 1, join(' ', @args));
626 my ($user, $chan, $cmd, undef, @args) = @_;
627 my $target = shift @args or return;
628 chanserv
::cs_kickmask
($user, $chan, $target, 0, join(' ', @args));
631 my ($user, $chan, $cmd, undef, @args) = @_;
632 my $target = shift @args or return;
633 chanserv
::cs_kickmask
($user, $chan, $target, 1, join(' ', @args));
637 my ($user, $chan, $cmd, undef, @args) = @_;
638 my $msg = join(' ', @args);
641 s/[^*.+0-9&|)(x\/^-]//g
;
642 s/([*+\\.\/x-])\1*/$1/g;
647 my $answer = $calc_safe->reval("($msg) || 0");
648 $answer = 'ERROR' unless defined $answer;
650 notice
($user, ($@ ? "$msg = ERROR (${\ (split / at/, $@, 2)[0]})" : "$msg = $answer"));
654 my ($user, $chan, $cmd, undef, @args) = @_;
657 nickserv
::ns_seen
($user, @args);
659 notice
($user, 'Syntax: SEEN <nick> [nick ...]');
664 my ($user, $chan, $cmd, undef, @args) = @_;
665 if($cmd =~ /^abbrev(iation)?s?$/) {
666 sendhelp
($user, 'chanbot', 'abbreviations');
668 sendhelp
($user, 'chanbot');
673 my ($user, $chan, $cmd, undef, @args) = @_;
674 chanserv
::cs_alist
($user, $chan);
678 my ($user, $chan, $cmd, undef, @args) = @_;
680 chanserv
::cs_unban
($user, $chan, get_user_nick
($user));
683 chanserv
::cs_unban
($user, $chan, @args);
688 my ($user, $chan, $cmd, undef, @args) = @_;
689 $cmd =~ /^(q|n)?ban$/; my $type = $1;
691 chanserv
::cs_ban
($user, $chan, $type, @args);
696 my ($user, $chan, $cmd, undef, @args) = @_;
697 chanserv
::cs_banlist
($user, $chan);
701 # FIXME: If dice is disabled, don't count towards flooding.
702 my ($user, $chan, $cmd, undef, @args) = @_;
704 if(chanserv
::can_do
($chan, 'DICE', $user)) {
705 ircd
::privmsg
(agent
($chan), $chan->{CHAN
},
711 my ($user, $chan, $cmd, undef, @args) = @_;
713 chanserv
::cs_mode
($user, $chan, shift @args, @args);
718 my ($user, $chan, $cmd) = @_;
719 chanserv
::cs_resync
($user, $chan->{CHAN
});
723 my ($user, $chan, $cmd, $msg) = @_;
726 chanserv
::cs_topic
($user, $chan, $msg);
731 my ($user, $chan, $cmd, undef, @args) = @_;
734 chanserv
::cs_why
($user, $chan, @args);
736 notice
($user, 'Syntax: WHY <nick> [nick ...]');
739 if(defined($cmdhash{$cmd})) {
740 return if flood_check
($user);
742 &{$cmdhash{$cmd}}($user, $chan, $cmd, $msg, @args);
747 my ($user, $chan, $botmsg) = @_;
748 my $cn = $chan->{CHAN
};
750 if(chanserv
::can_do
($chan, 'BotSay', $user)) {
751 ircd
::notice
(agent
($chan), '%'.$cn, get_user_nick
($user).' used BotSay')
752 if cr_chk_flag
($chan, CRF_VERBOSE
());
753 ircd
::privmsg
(agent
($chan), $cn, $botmsg);
755 # can_do will give the $err_deny for us.
756 #notice($user, $err_deny);
762 sub bot_dispatch
($$$) {
763 my ($user, $bot, $msg) = @_;
764 my ($cmd, $cn, $botmsg) = split(/ /, $msg, 3);
765 my $src = $user->{NICK
};
766 my $chan = { CHAN
=> $cn };
767 return if flood_check
($user);
768 if ($cmd =~ /^join$/i) {
769 if (adminserv
::can_do
($user, 'BOT')) {
770 agent_join
($bot, $cn);
772 notice
($user, $err_deny);
775 elsif ($cmd =~ /^part$/i) {
776 if (adminserv
::can_do
($user, 'BOT')) {
777 agent_part
($bot, $cn, "$src requested part");
779 notice
($user, $err_deny);
782 elsif ($cmd =~ /^say$/i) {
783 bot_say
($user, $chan, $botmsg);
785 elsif ($cmd =~ /^act$/i) {
786 bot_say
($user, $chan, "\001ACTION $botmsg\001");
788 elsif ($cmd =~ /^help$/i) {
789 #my @help; @help = ($cn) if $cn; push @help, split(/\s+/, $botmsg);
790 sendhelp
($user, 'botpriv');
795 my ($count, $sides) = map int($_), ($_[0] ? split('d', $_[0]) : (1, 6));
797 if ($sides < 1 or $sides > 1000 or $count < 0 or $count > 100) {
798 return "Sorry, you can't have more than 100 dice, or 1000 sides, or less than 1 of either.";
800 $count = 1 if $count == 0;
804 if($count == 1 or $count > 25) {
805 for(my $i = 1; $i <= $count; $i++) {
806 $sum += int(rand($sides)+1);
809 return "${count}d$sides: $sum";
814 for(my $i = 1; $i <= $count; $i++) {
815 my $n = int(rand($sides)+1);
820 return "${count}d$sides: $sum [" . join(' ', sort {$a <=> $b} @dice) . "]";
827 #We don't do chanmsg processing yet, like badwords.
831 $get_all_bots->execute();
832 while(my ($nick, $ident, $vhost, $gecos, $flags) = $get_all_bots->fetchrow_array) {
833 agent_connect
($nick, $ident, $vhost, '+pqBSrz'.(($flags & F_DEAF
())?'d':''), $gecos);
834 ircd
::sqline
($nick, $services::qlreason
);
835 my $bot = { NICK
=> $nick, ID
=>ircd
::getAgentUuid
($nick) };
836 agent_join
($nick, main_conf_diag
);
837 my $rsuser = { NICK
=> $main::rsnick
};
838 get_user_id
($rsuser);
839 ircd
::setmode
($rsuser, main_conf_diag
, '+h', $bot);
844 $get_botchans->execute();
845 while(my ($cn, $nick) = $get_botchans->fetchrow_array) {
846 my $chan = { CHAN
=> $cn };
847 if(chanserv
::get_user_count
($chan)) {
848 my $botUser = { NICK
=>$nick };
849 get_user_id
($botUser);
850 bot_join
($chan, $botUser);
852 elsif(cr_chk_flag
($chan, CRF_BOTSTAY
(), 1)) {
853 my $botUser = { NICK
=>$nick, ID
=>ircd
::getAgentUuid
($nick) };
854 bot_join
($chan, $botUser);
855 my $modelock = chanserv
::get_modelock
($chan);
856 ircd
::setmode
(main_conf_local
, $cn, $modelock) if $modelock;
861 ### Database Functions ###
864 my ($bot, $flag) = @_;
866 $set_flag->execute($flag, $bot);
870 my ($bot, $flag) = @_;
872 $unset_flag->execute($flag, $bot);
876 my ($chan, $bot) = @_;
877 my $cn = $chan->{CHAN
};
878 $bot = agent
($chan) unless $bot;
879 my $nick = $bot->{NICK
};
880 unless(is_agent_in_chan
($nick, $cn)) {
881 agent_join
($bot, $cn);
882 my $bot2 = { NICK
=> $nick, ID
=> ircd
::getAgentUuid
($nick), UID
=>ircd
::getAgentUuid
($nick) };
883 print "FOUNDERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR " . $IRCd_capabilities{"FOUNDER"};
884 if(!ircd
::PREFIXAQ_DISABLE
() && $IRCd_capabilities{"FOUNDER"} ne "" && $IRCd_capabilities{"ADMIN"} ne "") {
889 ircd
::setmode
($bot2, $cn, $botchmode, $bot2 );
893 sub bot_part_if_needed
($$$;$) {
894 my ($nick, $chan, $reason, $empty) = @_;
895 my $cn = $chan->{CHAN
};
896 my $bot = get_chan_bot
($chan);
897 $nick = agent
($chan) unless $nick;
898 return if (lc $chanserv::enforcers
{lc $cn} eq lc $nick);
900 if(is_agent_in_chan
($nick, $cn)) {
901 if(lc $bot eq lc $nick) {
902 if(cr_chk_flag
($chan, CRF_BOTSTAY
(), 1) or ($empty != 1 or chanserv
::get_user_count
($chan))) {
907 agent_part
($nick, $cn, $reason);
911 sub get_chan_bot
($) {
913 my $cn = $chan->{CHAN
};
914 $botserv::get_chan_bot-
>execute($cn);
916 my ($bot) = $botserv::get_chan_bot-
>fetchrow_array();
917 $botserv::get_chan_bot-
>finish();