]>
jfr.im git - irc/SurrealServices/srsv.git/blob - branches/0.4.3/modules/serviceslibs/botserv.pm
c4c59fdaf389a47659b89a438261377bd2c3c941
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
24 use SrSv
::Process
::Worker
'ima_worker'; #FIXME
26 use SrSv
::Text
::Format
qw(columnar);
29 use SrSv
::Conf2Consts
qw( main services );
31 use SrSv
::User
qw(get_user_nick get_user_id :flood);
32 use SrSv
::User
::Notice
;
33 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 if(!ircd
::PREFIXAQ_DISABLE
()) {
54 *agent
= \
&chanserv
::agent
;
56 our $calc_safe = new Safe
;
59 $get_all_bots, $get_botchans, $get_botstay_chans, $get_chan_bot, $get_bots_chans, $get_bot_info,
61 $create_bot, $delete_bot, $delete_bot_allchans, $assign_bot, $unassign_bot,
62 $change_bot, $update_chanreg_bot,
66 $set_flag, $unset_flag, $get_flags
70 $get_all_bots = $dbh->prepare("SELECT nick, ident, vhost, gecos, flags FROM bot");
71 $get_botchans = $dbh->prepare("SELECT chan, COALESCE(bot, '$chanserv::csnick') FROM chanreg WHERE bot != '' OR (flags & ". CRF_BOTSTAY
() . ")");
72 $get_botstay_chans = $dbh->prepare("SELECT chan, COALESCE(bot, '$chanserv::csnick') FROM chanreg WHERE (flags & ".
74 $get_chan_bot = $dbh->prepare("SELECT bot FROM chanreg WHERE chan=?");
75 $get_bots_chans = $dbh->prepare("SELECT chan FROM chanreg WHERE bot=?");
76 $get_bot_info = $dbh->prepare("SELECT nick, ident, vhost, gecos, flags FROM bot WHERE nick=?");
78 $create_bot = $dbh->prepare("INSERT INTO bot SET nick=?, ident=?, vhost=?, gecos=?");
79 $delete_bot = $dbh->prepare("DELETE FROM bot WHERE nick=?");
80 $delete_bot_allchans = $dbh->prepare("UPDATE chanreg SET bot='' WHERE bot=?");
81 $change_bot = $dbh->prepare("UPDATE bot SET nick=?, ident=?, vhost=?, gecos=? WHERE nick=?");
82 $update_chanreg_bot = $dbh->prepare("UPDATE chanreg SET bot=? WHERE bot=?");
84 $assign_bot = $dbh->prepare("UPDATE chanreg, bot SET chanreg.bot=bot.nick WHERE bot.nick=? AND chan=?");
85 $unassign_bot = $dbh->prepare("UPDATE chanreg SET chanreg.bot='' WHERE chan=?");
87 $is_bot = $dbh->prepare("SELECT 1 FROM bot WHERE nick=?");
88 $has_bot = $dbh->prepare("SELECT 1 FROM chanreg WHERE chan=? AND bot != ''");
90 $set_flag = $dbh->prepare("UPDATE bot SET flags=(flags | (?)) WHERE nick=?");
91 $unset_flag = $dbh->prepare("UPDATE bot SET flags=(flags & ~(?)) WHERE nick=?");
92 $get_flags = $dbh->prepare("SELECT flags FROM bot WHERE bot.nick=?");
94 register
() unless ima_worker
; #FIXME
98 my ($src, $dst, $msg) = @_;
100 if(lc $dst eq lc $bsnick or lc $dst eq lc $bsnick_default ) {
101 bs_dispatch
($src, $dst, $msg);
103 elsif($dst =~ /^#/) {
105 $has_bot->execute($dst);
106 return unless($has_bot->fetchrow_array);
107 chan_dispatch
($src, $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 ($src, $dst, $msg) = @_;
125 my @args = split(/\s+/, $msg);
126 my $cmd = shift @args;
128 my $user = { NICK
=> $src, AGENT
=> $dst };
130 return if flood_check
($user);
132 if($cmd =~ /^assign$/i) {
134 bs_assign
($user, {CHAN
=> $args[0]}, $args[1]);
136 notice
($user, 'Syntax: ASSIGN <#channel> <bot>');
139 elsif ($cmd =~ /^unassign$/i) {
141 bs_assign
($user, {CHAN
=> $args[0]}, '');
143 notice
($user, 'Syntax: UNASSIGN <#channel>');
146 elsif ($cmd =~ /^list$/i) {
150 notice
($user, 'Syntax: LIST');
153 elsif ($cmd =~ /^add$/i) {
155 @args = split(/\s+/, $msg, 5);
156 bs_add
($user, $args[1], $args[2], $args[3], $args[4]);
158 notice
($user, 'Syntax: ADD <nick> <ident> <vhost> <realname>');
161 elsif ($cmd =~ /^change$/i) {
163 @args = split(/\s+/, $msg, 6);
164 bs_change
($user, $args[1], $args[2], $args[3], $args[4], $args[5]);
166 notice
($user, 'Syntax: ADD <oldnick> <nick> <ident> <vhost> <realname>');
169 elsif ($cmd =~ /^del(ete)?$/i) {
171 bs_del
($user, $args[0]);
173 notice
($user, 'Syntax: DEL <botnick>');
176 elsif($cmd =~ /^set$/i) {
178 bs_set
($user, $args[0], $args[1], $args[2]);
180 notice
($user, 'Syntax: SET <botnick> <option> <value>');
183 elsif($cmd =~ /^seen$/i) {
185 nickserv
::ns_seen
($user, @args);
187 notice
($user, 'Syntax: SEEN <nick> [nick ...]');
191 elsif($cmd =~ /^(say|act)$/i) {
193 my @args = split(/\s+/, $msg, 3);
194 my $botmsg = $args[2];
195 $botmsg = "\001ACTION $botmsg\001" if(lc $cmd eq 'act');
196 bot_say
($user, {CHAN
=> $args[1]}, $botmsg);
198 notice
($user, 'Syntax: '.uc($cmd).' <#chan> <message>');
201 elsif($cmd =~ /^info$/i) {
203 bs_info
($user, $args[0]);
205 notice
($user, 'Syntax: INFO <botnick>');
208 elsif($cmd =~ /^help$/i) {
209 sendhelp
($user, 'botserv', @args);
211 elsif($cmd =~ /^d(ice)?$/i) {
212 notice
($user, get_dice
($args[0]));
215 notice
($user, "Unrecognized command. For help, type: \002/bs help\002");
219 # For unassign, set $bot to ''
222 my ($user, $chan, $bot) = @_;
224 chanserv
::chk_registered
($user, $chan) or return;
226 unless (chanserv
::can_do
($chan, 'BotAssign', $user)) {
227 notice
($user, $err_deny);
232 $is_bot->execute($bot);
233 unless($is_bot->fetchrow_array) {
234 notice
($user, "\002$bot\002 is not a bot.");
239 $get_flags->execute($bot);
240 my ($botflags) = $get_flags->fetchrow_array;
241 if (($botflags & F_PRIVATE
) && !adminserv
::can_do
($user, 'BOT')) {
242 notice
($user, $err_deny);
247 my $cn = $chan->{CHAN
};
248 my $src = get_user_nick
($user);
250 if ($oldbot = get_chan_bot
($chan)) {
251 agent_part
($oldbot, $cn, "Unassigned by \002$src\002.");
257 $assign_bot->execute($bot, $cn);
258 bot_join
($chan, $bot);
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 ircd
::setmode
($main::rsnick
, main_conf_diag
, '+h', $botnick);
321 notice
($user, "Bot $botnick connected.");
325 my ($user, $botnick) = @_;
327 unless (adminserv
::can_do
($user, 'BOT')) {
328 notice
($user, $err_deny);
331 $is_bot->execute($botnick);
332 if (!$is_bot->fetchrow_array) {
333 notice
($user, "\002$botnick\002 is not a bot.");
337 my $src = get_user_nick
($user);
338 $delete_bot->execute($botnick);
339 agent_quit
($botnick, "Deleted by \002$src\002.");
340 ircd
::unsqline
($botnick);
342 $delete_bot_allchans->execute($botnick);
343 notice
($user, "Bot \002$botnick\002 disconnected.");
347 my ($user, $botnick, $set, $parm) = @_;
349 unless (adminserv
::can_do
($user, 'BOT')) {
350 notice
($user, $err_deny);
353 if($set =~ /^private$/i) {
354 if ($parm =~ /^(on|true)$/i) {
355 set_flag
($botnick, F_PRIVATE
());
356 notice
($user, "\002$botnick\002 is now private.");
358 elsif ($parm =~ /^(off|false)$/i) {
359 unset_flag
($botnick, F_PRIVATE
());
360 notice
($user, "\002$botnick\002 is now public.");
363 notice
($user, 'Syntax: SET <botnick> PRIVATE <ON|OFF>');
366 if($set =~ /^deaf$/i) {
367 if ($parm =~ /^(on|true)$/i) {
368 set_flag
($botnick, F_DEAF
());
369 setagent_umode
($botnick, '+d');
370 notice
($user, "\002$botnick\002 is now deaf.");
372 elsif ($parm =~ /^(off|false)$/i) {
373 unset_flag
($botnick, F_DEAF
());
374 setagent_umode
($botnick, '-d');
375 notice
($user, "\002$botnick\002 is now undeaf.");
378 notice
($user, 'Syntax: SET <botnick> DEAF <ON|OFF>');
384 my ($user, $botnick) = @_;
386 unless (adminserv
::can_do
($user, 'HELP')) {
387 notice
($user, $err_deny);
390 $is_bot->execute($botnick);
391 unless($is_bot->fetchrow_array) {
392 notice
($user, "\002$botnick\002 is not a bot.");
396 $get_bot_info->execute($botnick);
397 my ($nick, $ident, $vhost, $gecos, $flags) = $get_bot_info->fetchrow_array;
398 $get_bot_info->finish();
399 $get_bots_chans->execute($botnick);
401 while (my $chan = $get_bots_chans->fetchrow_array) {
404 $get_bots_chans->finish();
406 notice
($user, columnar
({TITLE
=> "Information for bot \002$nick\002:",
407 NOHIGHLIGHT
=> nr_chk_flag_user
($user, NRF_NOHIGHLIGHT
)},
408 ['Mask:', "$ident\@$vhost"], ['Realname:', $gecos],
409 ['Flags:', (($flags & F_PRIVATE
())?'Private ':'').(($flags & F_DEAF
())?'Deaf ':'')],
411 'Assigned to '. @chans.' channel(s):',
412 ' ' . join(' ', @chans)
417 sub bs_change
($$$$$$) {
418 my ($user, $oldnick, $botnick, $botident, $bothost, $botgecos) = @_;
420 if (lc $oldnick eq lc $botnick) {
421 notice
($user, "Error: $oldnick is the same (case-insensitive) as $botnick",
422 "At this time, you cannot change only the ident, host, gecos, or nick-case of a bot.");
426 unless (adminserv
::can_do
($user, 'BOT')) {
427 notice
($user, $err_deny);
431 if (my $ret = is_invalid_agentname
($botnick, $botident, $bothost)) {
436 if(nickserv
::is_registered
($botnick)) {
437 notice
($user, "The nick \002$botnick\002 is already registered.");
441 if(nickserv
::is_online
($botnick)) {
442 notice
($user, "The nick \002$botnick\002 is currently in use.");
446 $is_bot->execute($botnick);
447 if($is_bot->fetchrow_array) {
448 notice
($user, "\002$botnick\002 already exists.");
452 #Create bot first, join it to its chans
453 # then finally delete the old bot
454 # This is to prevent races.
455 $create_bot->execute($botnick, $botident, $bothost, $botgecos);
456 ircd
::sqline
($botnick, $services::qlreason
);
457 agent_connect
($botnick, $botident, $bothost, '+pqBSrz', $botgecos);
458 agent_join
($botnick, main_conf_diag
);
459 ircd
::setmode
($main::rsnick
, main_conf_diag
, '+h', $botnick);
461 notice
($user, "Bot $botnick connected.");
463 $get_bots_chans->execute($oldnick);
464 while(my ($cn) = $get_bots_chans->fetchrow_array()) {
465 my $chan = { CHAN
=> $cn };
466 bot_join
($chan, $botnick)
467 if chanserv
::get_user_count
($chan) or cr_chk_flag
($chan, CRF_BOTSTAY
(), 1);
469 $get_bots_chans->finish();
471 $update_chanreg_bot->execute($botnick, $oldnick); $update_chanreg_bot->finish();
473 my $src = get_user_nick
($user);
474 $delete_bot->execute($oldnick);
475 agent_quit
($oldnick, "Deleted by \002$src\002.");
476 ircd
::unsqline
($oldnick);
477 notice
($user, "Bot \002$oldnick\002 disconnected.");
480 ### CHANNEL COMMANDS ###
482 sub chan_dispatch
($$$) {
483 my ($src, $cn, $msg) = @_;
485 my @args = split(/\s+/, $msg);
486 my $cmd = lc(shift @args);
489 my $chan = { CHAN
=> $cn };
490 my $user = { NICK
=> $src, AGENT
=> agent
($chan) };
493 'voice' => \
&give_ops
,
494 'devoice' => \
&give_ops
,
496 'halfop' => \
&give_ops
,
497 'dehop' => \
&give_ops
,
498 'dehalfop' => \
&give_ops
,
500 'deop' => \
&give_ops
,
501 'protect' => \
&give_ops
,
502 'admin' => \
&give_ops
,
503 'deprotect' => \
&give_ops
,
504 'deadmin' => \
&give_ops
,
511 'invite' => \
&invite
,
517 'kickb' => \
&kickban
,
519 'kickban' => \
&kickban
,
521 'bkick' => \
&kickban
,
523 'bankick' => \
&kickban
,
525 'kickmask' => \
&kickmask
,
527 'kmask' => \
&kickmask
,
529 'kickbanmask' => \
&kickbanmask
,
530 'kickbmask' => \
&kickbanmask
,
531 'kickbm' => \
&kickbanmask
,
532 'kbm' => \
&kickbanmask
,
533 'kbanm' => \
&kickbanmask
,
534 'kbanmask' => \
&kickbanmask
,
535 'kbmask' => \
&kickbanmask
,
541 #We really need something that is mostly obvious
542 # and won't be used by any other bots.
543 #TriviaBot I added !trivhelp
544 # I guess anope uses !commands
546 'commands' => \
&help
,
550 'abbreviations' => \
&help
,
558 'banlist' => \
&banlist
,
559 'blist' => \
&banlist
,
572 'resync' => \
&resync
,
578 'tempban' => \
&tempban
,
579 'tmpban' => \
&tempban
,
584 my ($user, $chan, $cmd, undef, @args) = @_;
585 chanserv
::cs_setmodes
($user, $cmd, $chan, @args);
588 my ($user, $chan, $cmd, undef, @args) = @_;
589 chanserv
::cs_updown
($user, $cmd, $chan->{CHAN
}, @args);
592 my ($user, $chan, $cmd, undef, @args) = @_;
593 if(lc $cmd eq 'molest') {
594 chanserv
::unset_modes
($user, $chan);
596 chanserv
::cs_updown
($user, $cmd, $chan->{CHAN
}, @args);
601 my ($user, $chan, $cmd, undef, @args) = @_;
602 chanserv
::cs_invite
($user, $chan, @args) unless @args == 0;
606 my ($user, $chan, $cmd, undef, @args) = @_;
607 my $target = shift @args or return;
608 chanserv
::cs_kick
($user, $chan, $target, 0, join(' ', @args));
611 my ($user, $chan, $cmd, undef, @args) = @_;
613 my $cn = $chan->{CHAN
};
617 print ("ARGS " . Dumper
(@args));
618 chanserv
::cs_tempban
($user, join(' ', @args));
621 my ($user, $chan, $cmd, undef, @args) = @_;
622 my $target = shift @args or return;
623 chanserv
::cs_kick
($user, $chan, $target, 1, join(' ', @args));
627 my ($user, $chan, $cmd, undef, @args) = @_;
628 my $target = shift @args or return;
629 chanserv
::cs_kickmask
($user, $chan, $target, 0, join(' ', @args));
632 my ($user, $chan, $cmd, undef, @args) = @_;
633 my $target = shift @args or return;
634 chanserv
::cs_kickmask
($user, $chan, $target, 1, join(' ', @args));
638 my ($user, $chan, $cmd, undef, @args) = @_;
639 my $msg = join(' ', @args);
642 $stripped =~ s/[^a-zA-Z ]//g;
644 if ( $stripped =~ /answer to life the universe and e(?:ve|r)rything/i ) {
645 notice
($user, "$msg = 42");
651 s/[^*.+0-9&|)(x\/^-]//g
;
652 s/([*+\\.\/x-])\1*/$1/g;
657 my $answer = $calc_safe->reval("($msg) || 0");
658 $answer = 'ERROR' unless defined $answer;
660 notice
($user, ($@ ? "$msg = ERROR (${\ (split / at/, $@, 2)[0]})" : "$msg = $answer"));
664 my ($user, $chan, $cmd, undef, @args) = @_;
667 nickserv
::ns_seen
($user, @args);
669 notice
($user, 'Syntax: SEEN <nick> [nick ...]');
674 my ($user, $chan, $cmd, undef, @args) = @_;
675 if($cmd =~ /^abbrev(iation)?s?$/) {
676 sendhelp
($user, 'chanbot', 'abbreviations');
678 sendhelp
($user, 'chanbot');
683 my ($user, $chan, $cmd, undef, @args) = @_;
684 chanserv
::cs_alist
($user, $chan);
688 my ($user, $chan, $cmd, undef, @args) = @_;
690 chanserv
::cs_unban
($user, $chan, get_user_nick
($user));
693 chanserv
::cs_unban
($user, $chan, @args);
698 my ($user, $chan, $cmd, undef, @args) = @_;
699 $cmd =~ /^(q|n)?ban$/; my $type = $1;
701 chanserv
::cs_ban
($user, $chan, $type, @args);
706 my ($user, $chan, $cmd, undef, @args) = @_;
707 chanserv
::cs_banlist
($user, $chan);
711 # FIXME: If dice is disabled, don't count towards flooding.
712 my ($user, $chan, $cmd, undef, @args) = @_;
714 if(chanserv
::can_do
($chan, 'DICE', $user)) {
715 ircd
::privmsg
(agent
($chan), $chan->{CHAN
},
721 my ($user, $chan, $cmd, undef, @args) = @_;
723 chanserv
::cs_mode
($user, $chan, shift @args, @args);
728 my ($user, $chan, $cmd) = @_;
729 chanserv
::cs_resync
($user, $chan->{CHAN
});
733 my ($user, $chan, $cmd, @args) = @_;
737 chanserv
::cs_topic
($user, $chan, @args);
742 my ($user, $chan, $cmd, undef, @args) = @_;
745 chanserv
::cs_why
($user, $chan, @args);
747 notice
($user, 'Syntax: WHY <nick> [nick ...]');
750 if(defined($cmdhash{$cmd})) {
751 return if flood_check
($user);
753 &{$cmdhash{$cmd}}($user, $chan, $cmd, $msg, @args);
758 my ($user, $chan, $botmsg) = @_;
759 my $cn = $chan->{CHAN
};
761 if(chanserv
::can_do
($chan, 'BotSay', $user)) {
762 ircd
::notice
(agent
($chan), '%'.$cn, get_user_nick
($user).' used BotSay')
763 if cr_chk_flag
($chan, CRF_VERBOSE
());
764 ircd
::privmsg
(agent
($chan), $cn, $botmsg);
766 # can_do will give the $err_deny for us.
767 #notice($user, $err_deny);
773 sub bot_dispatch
($$$) {
774 my ($src, $bot, $msg) = @_;
776 my ($cmd, $cn, $botmsg) = split(/ /, $msg, 3);
778 my $user = { NICK
=> $src, AGENT
=> $bot };
779 my $chan = { CHAN
=> $cn };
781 return if flood_check
($user);
783 if ($cmd =~ /^join$/i) {
784 if (adminserv
::can_do
($user, 'BOT')) {
785 agent_join
($bot, $cn);
787 notice
($user, $err_deny);
790 elsif ($cmd =~ /^part$/i) {
791 if (adminserv
::can_do
($user, 'BOT')) {
792 agent_part
($bot, $cn, "$src requested part");
794 notice
($user, $err_deny);
797 elsif ($cmd =~ /^say$/i) {
798 bot_say
($user, $chan, $botmsg);
800 elsif ($cmd =~ /^act$/i) {
801 bot_say
($user, $chan, "\001ACTION $botmsg\001");
803 elsif ($cmd =~ /^help$/i) {
804 #my @help; @help = ($cn) if $cn; push @help, split(/\s+/, $botmsg);
805 sendhelp
($user, 'botpriv');
810 my ($count, $sides) = map int($_), ($_[0] ? split('d', $_[0]) : (1, 6));
812 if ($sides < 1 or $sides > 1000 or $count < 0 or $count > 100) {
813 return "Sorry, you can't have more than 100 dice, or 1000 sides, or less than 1 of either.";
815 $count = 1 if $count == 0;
819 if($count == 1 or $count > 25) {
820 for(my $i = 1; $i <= $count; $i++) {
821 $sum += int(rand($sides)+1);
824 return "${count}d$sides: $sum";
829 for(my $i = 1; $i <= $count; $i++) {
830 my $n = int(rand($sides)+1);
835 return "${count}d$sides: $sum [" . join(' ', sort {$a <=> $b} @dice) . "]";
842 #We don't do chanmsg processing yet, like badwords.
846 $get_all_bots->execute();
847 while(my ($nick, $ident, $vhost, $gecos, $flags) = $get_all_bots->fetchrow_array) {
848 agent_connect
($nick, $ident, $vhost, '+pqBSrz'.(($flags & F_DEAF
())?'d':''), $gecos);
849 ircd
::sqline
($nick, $services::qlreason
);
850 agent_join
($nick, main_conf_diag
);
851 ircd
::setmode
($main::rsnick
, main_conf_diag
, '+h', $nick);
856 $get_botchans->execute();
857 while(my ($cn, $nick) = $get_botchans->fetchrow_array) {
858 my $chan = { CHAN
=> $cn };
859 if(chanserv
::get_user_count
($chan)) {
860 bot_join
($chan, $nick);
862 elsif(cr_chk_flag
($chan, CRF_BOTSTAY
(), 1)) {
863 bot_join
($chan, $nick);
864 my $modelock = chanserv
::get_modelock
($chan);
865 ircd
::setmode
(main_conf_local
, $cn, $modelock) if $modelock;
870 ### Database Functions ###
873 my ($bot, $flag) = @_;
875 $set_flag->execute($flag, $bot);
879 my ($bot, $flag) = @_;
881 $unset_flag->execute($flag, $bot);
885 my ($chan, $nick) = @_;
887 my $cn = $chan->{CHAN
};
889 $nick = agent
($chan) unless $nick;
891 unless(is_agent_in_chan
($nick, $cn)) {
892 agent_join
($nick, $cn);
893 ircd
::setmode
($nick, $cn, $botchmode, $nick.(ircd
::PREFIXAQ_DISABLE
() ? ' '.$nick : '') );
897 sub bot_part_if_needed
($$$;$) {
898 my ($nick, $chan, $reason, $empty) = @_;
899 my $cn = $chan->{CHAN
};
900 my $bot = get_chan_bot
($chan);
901 $nick = agent
($chan) unless $nick;
903 return if (lc $chanserv::enforcers
{lc $cn} eq lc $nick);
905 if(is_agent_in_chan
($nick, $cn)) {
906 if(lc $bot eq lc $nick) {
907 if(cr_chk_flag
($chan, CRF_BOTSTAY
(), 1) or ($empty != 1 or chanserv
::get_user_count
($chan))) {
912 agent_part
($nick, $cn, $reason);
916 sub get_chan_bot
($) {
918 my $cn = $chan->{CHAN
};
919 $botserv::get_chan_bot-
>execute($cn);
921 my ($bot) = $botserv::get_chan_bot-
>fetchrow_array();
922 $botserv::get_chan_bot-
>finish();