]> jfr.im git - irc/SurrealServices/srsv.git/commitdiff
sucky code for /cs set noclones; /cs tempban; /cs set bantime don't expect it to...
authorerry <redacted>
Sun, 4 Sep 2011 17:22:55 +0000 (17:22 +0000)
committererry <redacted>
Sun, 4 Sep 2011 17:22:55 +0000 (17:22 +0000)
git-svn-id: http://svn.tabris.net/repos/srsv@3564 70d4eda1-72e9-0310-a436-91e5bd24443c

branches/0.4.3/help/chanserv.txt
branches/0.4.3/help/chanserv/set.txt
branches/0.4.3/help/chanserv/set/bantime.txt [new file with mode: 0644]
branches/0.4.3/help/chanserv/tempban.txt [new file with mode: 0644]
branches/0.4.3/modules/serviceslibs/botserv.pm
branches/0.4.3/modules/serviceslibs/chanserv.pm

index d1738b5cd60917f93afe7ca9725f35fb72141238..684b6df06c9c0ccae1ea07cbfe4dea5953c1d6a2 100644 (file)
@@ -23,9 +23,9 @@ Commands to change or check channel status:
 Other available commands:
    DICE   INVITE   GETKEY   CLOSE
    CLEAR  WELCOME  DRONE    KICKMASK
-   KICK   KICKBAN  MLOCK    KICKBANMASK
-   JOIN   COPY     BANLIST
-   TOPIC  TOPICAPPEND TOPICPREPEND
+   KICK   KICKBAN  KICKMASK KICKBANMASK 
+   TEMPBAN MLOCK   JOIN     COPY
+   BANLIST TOPIC  TOPICAPPEND
 
 Note that channels will be dropped after 21 days of inactivity.
  
index 480a668209f4ddfd4ede08bce92e40a1d907caeb..4a31ed645eb3165620dc43aa4acd11f1a9ba139a 100644 (file)
@@ -18,6 +18,7 @@ Settings:
   BANTYPE        Selects the ban-type to be used for KICKBAN and AKICKs
   TOPICLOCK      Restricts who can change the topic in the channel.
   NOCLONES       Bans people who bring clones into the channel.
+  BANTIME               Time until bans are automatically removed.
 Oper only flags:
   HOLD         Prevent channel from expiring
   FREEZE       Suspend access in this channel
diff --git a/branches/0.4.3/help/chanserv/set/bantime.txt b/branches/0.4.3/help/chanserv/set/bantime.txt
new file mode 100644 (file)
index 0000000..8f35fff
--- /dev/null
@@ -0,0 +1,6 @@
+%BChanServ SET BANTIME%B sets the default ban time for /cs (kick)ban and /cs tempban.
+Default is 0 (permanent unless manually removed)
+Examples:
+/cs set #pokemonlake bantime +24h
+/cs set #pokemondeluge bantime +12h
+Syntax: %BSET%B %U#channel%U %BBANTIME%B +<%Utime%U>
diff --git a/branches/0.4.3/help/chanserv/tempban.txt b/branches/0.4.3/help/chanserv/tempban.txt
new file mode 100644 (file)
index 0000000..d171ceb
--- /dev/null
@@ -0,0 +1,9 @@
+%BChanServ TEMPBAN%B Tells ChanServ to set a ban on a person or
+mask for a set amount of time. The ban will be removed automatically after that time has elapsed.
+
+Syntax: %BTEMPBAN%B %U#channel%U <%Bnick|mask%B> <%B+TIME%B> [%BREASON%B]
+
+Examples: TEMPBAN #pokemoncrater erry +1d Enough already!
+TEMPBAN #help ra +365d you're too mean 
+TEMPBAN #surrealchat tabris +1m test
+By default limited to %BHOP%B
index b64c85d13708befb0e8778ca120aec4208f4c9dd..5ac3897bb48ab0d3ef34bc08629ce3470d309e4a 100644 (file)
@@ -575,6 +575,9 @@ sub chan_dispatch($$$) {
                't'             =>      \&topic,
 
                'why'           =>      \&why,
+               'tempban' => \&tempban,
+               'tmpban' => \&tempban,
+               "tb" => \&tempban,
        );
 
        sub give_ops {
@@ -604,6 +607,11 @@ sub chan_dispatch($$$) {
                my $target = shift @args or return;
                chanserv::cs_kick($user, $chan, $target, 0, join(' ', @args));
        }
+       sub tempban {
+               my ($user, $chan, $cmd, undef, @args) = @_;
+               my $target = shift @args or return;
+               chanserv::cs_tempban($user, $chan, $target, join(' ', @args));
+       }
        sub kickban {
                my ($user, $chan, $cmd, undef, @args) = @_;
                my $target = shift @args or return;
index 9f94d8e01daf1d64bfc1308e152a6d4558db2eb0..79e80b7efce3fada3bde0778956bfe735c3e45ae 100644 (file)
@@ -18,12 +18,11 @@ package chanserv;
 use strict;
 
 use SrSv::Timer qw(add_timer);
-
+use Data::Dumper;
 use SrSv::Message qw(current_message);
 use SrSv::IRCd::State qw($ircline synced initial_synced %IRCd_capabilities);
 use SrSv::Message qw(message current_message);
 use SrSv::HostMask qw(normalize_hostmask make_hostmask parse_mask);
-
 #FIXME: This needs to be abstracted into a proper SrSv::IRCd module
 use SrSv::Unreal::Modes qw(@opmodes %opmodes $scm $ocm $acm sanitize_mlockable);
 use SrSv::IRCd::Validate qw( valid_nick validate_chmodes validate_ban );
@@ -214,6 +213,11 @@ our (
        $drop_chantext, $drop_nicktext,
        $get_host,
        $get_host_inchan,
+       $add_tempban,
+       $get_expired_bans,
+       $del_tmpban,
+       $get_bantime,
+       $set_bantime,
 );
 
 sub init() {
@@ -436,7 +440,7 @@ sub init() {
 
 
        $get_info = $dbh->prepare("SELECT chanreg.descrip, chanreg.regd, chanreg.last, chantext.data, 
-               chanreg.topicer, chanreg.modelock, foundernick.nick, successornick.nick, chanreg.bot, chanreg.bantype
+               chanreg.topicer, chanreg.modelock, foundernick.nick, successornick.nick, chanreg.bot, chanreg.bantype, chanreg.bantime
                FROM nickreg AS foundernick, chanreg
                LEFT JOIN nickreg AS successornick ON(successornick.id=chanreg.successorid)
                LEFT JOIN chantext ON (chanreg.chan=chantext.chan AND chantext.type=".CRT_TOPIC().")
@@ -444,13 +448,14 @@ sub init() {
 
        $register = $dbh->prepare("INSERT INTO chanreg
                SELECT ?, ?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), NULL, NULL,
-               NULL, id, NULL, NULL, NULL, ".DEFAULT_BANTYPE()." FROM nickreg WHERE nick=?");
+               NULL, id, NULL, NULL, NULL, ".DEFAULT_BANTYPE().",0 FROM nickreg WHERE nick=?");
        $register->{PrintError} = 0;
        $copy_chanreg = $dbh->prepare("INSERT INTO chanreg
-               (      chan, descrip, regd,             last,             modelock, founderid, successorid, bot, flags, bantype)
-               SELECT ?,    descrip, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), modelock, founderid, successorid, bot, flags, bantype
+               (      chan, descrip, regd,             last,             modelock, founderid, successorid, bot, flags, bantype,bantime)
+               SELECT ?,    descrip, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), modelock, founderid, successorid, bot, flags, bantype,bantime
                FROM chanreg WHERE chan=?");
-
+       $get_bantime = $dbh->prepare ("SELECT bantime FROM chanreg WHERE chan=?");
+       $set_bantime = $dbh->prepare ("UPDATE chanreg set bantime=? WHERE chan=?");
        $drop_acc = $dbh->prepare("DELETE FROM chanacc WHERE chan=?");
        $drop_lvl = $dbh->prepare("DELETE FROM chanlvl WHERE chan=?");
        $drop_akick = $dbh->prepare("DELETE FROM akick WHERE chan=?");
@@ -472,7 +477,7 @@ sub init() {
        $drop_welcome = $dbh->prepare("DELETE FROM welcome WHERE chan=?");
        $count_welcome = $dbh->prepare("SELECT COUNT(*) FROM welcome WHERE chan=?");
        $consolidate_welcome = $dbh->prepare("UPDATE welcome SET id=id-1 WHERE chan=? AND id>?");
-
+       $add_tempban = $dbh->prepare ("INSERT INTO tmpban values (?,?,UNIX_TIMESTAMP()+?,UNIX_TIMESTAMP())");
        $add_ban = $dbh->prepare("INSERT IGNORE INTO chanban SET chan=?, mask=?, setter=?, type=?, time=UNIX_TIMESTAMP()");
        $delete_bans = $dbh->prepare("DELETE FROM chanban WHERE chan=? AND ? LIKE mask AND type=?");
        # likely need a better name for this or for the above.
@@ -514,7 +519,9 @@ sub init() {
        $drop_chantext = $dbh->prepare("DELETE FROM chantext WHERE chan=?");
        $drop_nicktext = $dbh->prepare("DELETE nicktext.* FROM nicktext WHERE nicktext.chan=?");
        $get_host = $dbh->prepare ("SELECT user.host from user where user.nick=?");
-       $get_host_inchan = $dbh->prepare ("select user.nick from user  left join chanuser on (user.id=chanuser.nickid) where user.host=? and chanuser.joined=1 and chanuser.chan=? and user.nick<>?");
+       $get_host_inchan= $dbh->prepare ("select clonedUsers.nick from user as curUser join user as clonedUsers on (curUser.host=clonedUsers.host) join chanuser on (chanuser.nickid=clonedUsers.id) where clonedUsers.id!=curUser.id and curUser.id=? and chanuser.chan=?");
+       $get_expired_bans = $dbh->prepare("select * from tmpban where expiry < UNIX_TIMESTAMP()");
+       $del_tmpban = $dbh->prepare("delete from tmpban where channel=? and banmask like ?");
 }
 
 use SrSv::MySQL::Stub {
@@ -541,7 +548,29 @@ our %high_priority_cmds = (
        kban => 1,
        down => 1,
 );
-
+sub check_expired_bans() {
+       add_timer('ChanServ Expire', 10, __PACKAGE__, 'chanserv::check_expired_bans');
+       $get_expired_bans->execute();
+       while (my ($cn, $ban) = $get_expired_bans->fetchrow_array()) {
+               my $chan = {CHAN=>$cn};
+               ircd::setmode(agent($chan), $cn, '-b', $ban);
+               ircd::flushmodes();
+       }
+}
+sub tempban($$$@) {
+       my ($chan, $user, $mask, $args) = @_;
+       my $expiry = 0;
+       my @argz = split (" ",$args);
+       $expiry = parse_time(shift @argz) if $argz[0] =~ /\+/;
+       #kickban($chan, $user, undef, 'No clones allowed in this channel.');
+       my $reason = join(' ', @argz);
+       $reason =~ s/^\:// if $reason;
+       #sub kickban($$$$;$;$) {
+       #my ($chan, $user, $mask, $reason) = @_;
+       kickban ($chan, $user, $mask, $reason, undef, $expiry);
+       #sub kickban($$$$;$;$;) {
+       #my ($chan, $user, $mask, $reason, $noflush, $expiry) = @_;
+}
 sub clones_exist ($$) {
        my ($user, $chan) = @_;
        my $cn = $chan->{CHAN};
@@ -549,10 +578,9 @@ sub clones_exist ($$) {
                return;
        }
        my $nick = $user->{NICK};
-       $get_host->execute($nick);
-       my ($host) = $get_host->fetchrow_array;
-       $get_host_inchan -> execute ($host,$cn,$nick);
-       my ($joined) = $get_host_inchan->fetchrow_array;
+       my ($id) = get_user_id($user);
+       $get_host_inchan -> execute ($id,$cn);
+       my ($joined) = $get_host_inchan ->fetchrow_array;
        if ($joined) {
                return $joined;
        }
@@ -585,7 +613,16 @@ sub dispatch($$$) {
                        notice($user, 'Syntax: REGISTER <#channel> [password] [description]');
                }
        }
-       
+       elsif ($cmd =~ /^t((e)?mp)?b(an)?$/i) {
+               my @args = split(/\s+/, $msg, 4); shift @args;
+               my ($cn) = $args[0];
+               my ($target) = $args[1];
+               my ($reason) = $args[2];
+               my $chan = {CHAN=>$cn};
+               cs_tempban ($user, $chan, $target, $reason);
+       }
+               
+               
        elsif($cmd =~ /^(?:[uvhas]op|co?f(ounder)?)$/i) {
                my ($cn, $cmd2) = splice(@args, 0, 2);
                my $chan = { CHAN => $cn };
@@ -1014,30 +1051,31 @@ sub dispatch($$$) {
                        cs_join($user, @args);
                }
        }
-       elsif($cmd =~ /^topic/i) {
-               my $cn = shift @args;
-               my $chan = { CHAN => $cn };
-               if($cmd =~ /^topicprepend$/i) {
-                       if (@args == 0) {
-                               notice($user, 'Syntax: TOPICAPPEND <#channel> <message>');
-                       } else {
-                               $msg =~ s/^topicappend $cn //i;
-                               cs_topicappend($user, $chan, 0, $msg);
-                       }
-               } elsif($cmd =~ /^topicprepend$/i) {
-                       if (@args == 0) {
-                               notice($user, 'Syntax: TOPICPREPEND <#channel> <message>');
-                       } else {
-                               $msg =~ s/^topicprepend $cn //i;
-                               cs_topicappend($user, $chan, 1, $msg);
-                       }
-               } elsif($cmd =~ /^topic$/i) {
-                       if (@args == 0) {
-                               notice($user, 'Syntax: TOPIC <#channel> <message|NONE>');
-                       } else {
-                               $msg =~ s/^topic $cn //i;
-                               cs_topic($user, $chan, $msg);
-                       }
+       elsif($cmd =~ /^topic$/i) {
+               my $chan = shift @args;
+               if (@args == 0) {
+                       notice($user, 'Syntax: TOPIC <#channel> <message|NONE>');
+               } else {
+                       $msg =~ s/^topic #(?:\S+)? //i;
+                       cs_topic($user, { CHAN => $chan }, $msg);
+               }
+       }
+       elsif($cmd =~ /^topicappend$/i) {
+               my $chan = shift @args;
+               if (@args == 0) {
+                       notice($user, 'Syntax: TOPICAPPEND <#channel> <message>');
+               } else {
+                       $msg =~ s/^topicappend #(?:\S+)? //i;
+                       cs_topicappend($user, $chan, $msg);
+               }
+       }
+       elsif($cmd =~ /^topicprepend$/i) {
+               my $chan = shift @args;
+               if (@args == 0) {
+                       notice($user, 'Syntax: TOPICPREPEND <#channel> <message>');
+               } else {
+                       $msg =~ s/^topicprepend #(?:\S+)? //i;
+                       cs_topicprepend($user, $chan, $msg);
                }
        }
        else {
@@ -1707,7 +1745,7 @@ sub cs_info($@) {
                        next;
                }
 
-               my ($descrip, $regd, $last, $topic, $topicer, $modelock, $founder, $successor, $bot, $bantype) = @result;
+               my ($descrip, $regd, $last, $topic, $topicer, $modelock, $founder, $successor, $bot, $bantype,$bantime) = @result;
 
                $modelock = modes::sanitize($modelock) unless can_do($chan, 'GETKEY', $user, { NOREPLY => 1 });
 
@@ -1731,6 +1769,7 @@ sub cs_info($@) {
                push @opts, 'Verbose' if cr_chk_flag($chan, CRF_VERBOSE);
                push @opts, 'NeverOp' if cr_chk_flag($chan, CRF_NEVEROP);
                push @opts, 'Ban type '.$bantype if $bantype;
+               push @opts, 'Ban time '.$bantime . ' seconds'  if $bantype;
                my $opts = join(', ', @opts);
 
                my @data;
@@ -1771,6 +1810,7 @@ sub cs_set_pre($$$$) {
                'autovoice' => 1, 'avoice' => 1,
                'neverop' => 1, 'noop' => 1,
                'noclones' => 1,
+               'bantime' => 1,
        );
        my %override_set = (
                'hold' => 'SERVOP', 'noexpire' => 'SERVOP', 'no-expire' => 'SERVOP',
@@ -1939,7 +1979,22 @@ sub cs_set($$$;$) {
 
                return;
        }
-       
+       if($set =~ /^bantime$/i) {
+               if ( ( my $p = substr($parm, 0, 1) ) != '+' ) {
+                       $parm = '+' . $parm;
+               }
+               my $time = $parm;
+               unless ($time == 0) {
+                $time = parse_time ($parm);
+                       if (!$time) {
+                               notice ($user, "Invalid bantime. See /msg chanserv help set bantime for examples.");
+                               return;
+                       }
+               }
+               $set_bantime->execute($time, $cn);
+               notice($user, "Ban time for \002$cn\002 now set to \002$time\002 seconds.");
+               return;
+       }
        my $val;
        if($parm =~ /^(?:no|off|false|0)$/i) { $val = 0; }
        elsif($parm =~ /^(?:yes|on|true|1)$/i) { $val = 1; }
@@ -2287,6 +2342,78 @@ sub cs_drop($$) {
        undef($enforcers{lc $cn});
        botserv::bot_part_if_needed(undef(), $chan, "Channel dropped.");
 }
+sub cs_tempban($$$;$) {
+       my ($user, $chan, $target, $reason) = @_;
+       if(ref($chan) ne 'HASH' || !defined($chan->{CHAN})) {
+               notice($user, "Invalid tempban command, no channel specified");
+               return;
+       }
+       my @argz = split (" ",$reason);
+       my $expiry;
+       $expiry = shift @argz if $argz[0] =~ /\+/;
+       $reason = join (" ", @argz);
+       my $srclevel = get_best_acc($user, $chan);
+       my ($nick, $override) = can_do($chan, 'BAN', $user, { ACC => $srclevel });
+       return unless $nick;
+       my $src = get_user_nick($user);
+       my $cn = $chan->{CHAN};
+       $reason = "$expiry Requested by $src".($reason?": $reason":'' ) . " ($expiry)";
+       my @errors = (
+               ["I'm sorry, $src, I'm afraid I can't do that."],
+               ["They are not in \002$cn\002."],
+               [$err_deny],
+               ["User not found"],
+       );
+       my $peace = ({modes::splitmodes(get_modelock($chan))}->{Q}->[0] eq '+');
+       my @targets = split(/\,/, $target);
+       foreach $target (@targets) {
+               if($target =~ /[!@]+/) {
+                       ircd::debug("normalizing hostmask $target");
+                       #$target = normalize_hostmask($target);
+#=cut
+                       my ($nick, $ident, $host) = parse_mask($target);
+                       $nick = '*' unless length($nick);
+                       $ident = '*' unless length($ident);
+                       $host = '*' unless length($host);
+                       $target = "$nick\!$ident\@$host";
+#=cut
+                       ircd::debug("normalized hostmask: $target");
+                       tempban ($chan, undef, $target, $reason);
+                       next;
+               }
+               my $tuser = { NICK => $target };
+               my $targetlevel = get_best_acc($tuser, $chan);
+               if(lc $target eq lc agent($chan) or adminserv::is_service($tuser)) {
+                       push @{$errors[0]}, $target;
+                       next;
+               }
+               if(!get_user_id($tuser)) {
+                       push @{$errors[3]}, $target;
+                       next;
+               }
+
+               if( ( ($peace and $targetlevel > 0) or ($srclevel <= $targetlevel) ) 
+                       and not ($override && check_override($user, 'BAN', "tempban $cn $target")) )
+               {
+                       push @{$errors[2]}, $target;
+                       next;
+               }
+               tempban ($chan, $tuser, undef, $reason);
+       }
+       foreach my $errlist (@errors) {
+               if(@$errlist > 1) {
+                       my $msg = shift @$errlist;
+                       
+                       foreach my $e (@$errlist) { $e = "\002$e\002" }
+                       
+                       notice($user,
+                               "Cannot tempban ".
+                               enum("or", @$errlist).
+                               ": $msg"
+                       );
+               }
+       }
+}
 
 sub cs_kick($$$;$$) {
        my ($user, $chan, $target, $ban, $reason) = @_;
@@ -3361,24 +3488,7 @@ sub cs_topic($$@) {
        my ($chan, $msg) = ($cn->{CHAN}, join(" ", @args));
        can_do($cn, 'SETTOPIC', $user) or return undef;
        ircd::settopic(agent($cn), $chan, get_user_nick($user), time, ($msg =~ /^none/i ? "" : $msg));
-}
-
-sub cs_topicappend {
-       my ($user, $chan, $front, $topicappend) = @_;
-       my $cn = $chan->{CHAN};
-       $get_topic->execute($cn);
-       my ($cur_topic, undef, undef) = $get_topic->fetchrow_array;
-       $get_topic->finish();
-       my $new_topic = $cur_topic;
-       if ($cur_topic) {
-               if($front) {
-                       $new_topic = $topicappend . ' | ' . $cur_topic;
-               } else {
-                       $new_topic .= ' | ' . $topicappend;
-               }
-       }
-       cs_topic ($user, $chan, $new_topic);
-}
+}   
 
 ### MISCELLANEA ###
 
@@ -3483,23 +3593,34 @@ sub make_banmask($$;$) {
        return $type."$nick!$ident\@$vhost";
 }
 
-sub kickban($$$$;$) {
-       my ($chan, $user, $mask, $reason, $noflush) = @_;
+sub kickban($$$$;$;$;) {
+       my ($chan, $user, $mask, $reason, $noflush, $expiry) = @_;
        my $cn = $chan->{CHAN};
-       my $nick = get_user_nick($user);
-
-       return 0 if adminserv::is_service($user);
+       my $nick;
+       $nick = get_user_nick($user) if ($user);
+       if (!$user && !$mask) {
+               ircd::debug ("No user or mask given for /cs kickban!");
+               return;
+       }
+       return 0 if $user && adminserv::is_service($user);
 
        my $agent = agent($chan);
 
        unless($mask) {
                $mask = make_banmask($chan, $user);
        }
-
+       
        enforcer_join($chan) if (get_user_count($chan) <= 1);
        ircd::setmode($agent, $cn, '+b', $mask);
+       if (!$expiry) {
+               $get_bantime -> execute ($cn);
+               ($expiry) = $get_bantime -> fetchrow_array();
+       }
+       if ($expiry) {
+               $add_tempban->execute ($cn, $mask, $expiry);
+       }
        ircd::flushmodes() unless $noflush;
-       ircd::kick($agent, $cn, $nick, $reason);
+       ircd::kick($agent, $cn, $nick, $reason) if ($nick);
        return 1;
 }
 
@@ -3754,7 +3875,7 @@ sub do_status($$;$) {
        my ($accnick, $override) = can_do($chan, 'JOIN', $user, { ACC => $acc, NOREPLY => 1 });
        unless ($acc > 0 || $override) {
                if (clones_exist ($user, $chan)) {
-                       kickban($chan, $user, undef, 'No clones allowed in this channel.')
+                       tempban($chan, $user, undef, "+60s No clones allowed in this channel.");
                }
        }
        
@@ -4926,16 +5047,39 @@ sub process_ban($$$$) {
                $add_ban->execute($cn, $arg, $src, $type);
        } else {
                $delete_ban->execute($cn, $arg, $type);
+               $del_tmpban -> execute ($cn, $arg);
        }
 }
-
+sub cs_topicappend {
+       my ($user, $cn, $topicappend) = @_;
+       $get_topic->execute($cn);
+       my ($ntopic, $nsetter, $ntime) = $get_topic->fetchrow_array;
+       my $newtopic;
+       if ($ntopic) {
+               $newtopic = $ntopic . " | " . $topicappend;
+       }
+       else { $newtopic = $topicappend; }
+       cs_topic ($user, { CHAN => $cn }, $newtopic);
+}
+sub cs_topicprepend {
+       my ($user, $cn, $topicprepend) = @_;
+       $get_topic->execute($cn);
+       my ($ntopic, $nsetter, $ntime) = $get_topic->fetchrow_array;
+       my $newtopic;
+       if ($ntopic) {
+               $newtopic = $topicprepend . " | " . $ntopic;
+       }
+       else { $newtopic = $topicprepend; }
+       cs_topic ($user, { CHAN => $cn }, $newtopic);
+}
 sub chan_topic {
        my ($src, $cn, $setter, $time, $topic) = @_;
        my $chan = { CHAN => $cn };
        my $suser = { NICK => $setter, AGENT => agent($chan) };
 
+       
        return if cr_chk_flag($chan, CRF_CLOSE, 1);
-
+       
        if(current_message->{SYNC}) {  # We don't need to undo our own topic changes.
                $set_topic1->execute($setter, $time, $cn);
                $set_topic2->execute($cn, $topic);
@@ -5015,6 +5159,7 @@ sub eos(;$) {
 
        set_user_flag_all(UF_FINISHED());
        $unlock_tables->execute(); $unlock_tables->finish;
+       check_expired_bans();
 }
 
 1;