+#! /usr/bin/perl
+
+use warnings;
+use strict;
+
+
+use IO::File;
+use Getopt::Std;
+
+my $conf = {bans => 'bans.txt',
+ bans_to_remove => 'bans_to_remove.txt',
+ bans_to_keep => 'bans_to_keep.txt',
+ minimum_age => 1209600, # two weeks
+ max_ubans => 4,
+ };
+
+my $options = {};
+getopt('b:k:r:a:',$options);
+
+$conf->{bans} = $options->{b} || $conf->{bans};
+$conf->{bans_to_remove} = $options->{r} || $conf->{bans_to_remove};
+$conf->{bans_to_keep} = $options->{k} || $conf->{bans_to_keep};
+$conf->{minimum_age} = $options->{a} || $conf->{minimum_age};
+
+my $bans_fh = new IO::File $conf->{bans}, 'r' or die "Unable to open file $conf->{bans} for reading: $!";;
+
+my $bans_r_fh = new IO::File $conf->{bans_to_remove}, 'w' or
+ die "Unable to open file $conf->{bans_to_remove} for writing: $!";
+
+my $bans_k_fh = new IO::File $conf->{bans_to_keep}, 'w' or
+ die "Unable to open file $conf->{bans_to_keep} for writing: $!";
+
+my @bans_to_remove;
+
+while (<$bans_fh>) {
+ # pull the ban and the times.
+ print {$bans_k_fh} $_ and next unless my ($channel, $banmask, $time) =
+ $_ =~ /(\#\w+)\:\s+ban\s+([\w\d\*\@\%\!\-\_\.]+)\s+\[by\s*.*?\,\s+(\d+)\s+secs/;
+ print {$bans_k_fh} $_ and next unless $time > $conf->{minimum_age};
+
+ # Ignore bans against specific users.
+ print {$bans_k_fh} $_ and next if $banmask =~ /^\%?\w/;
+
+ # Ignore wide bans
+ print {$bans_k_fh} $_ and next if $banmask =~ /\*\!.*?\@.*\*.*/;
+
+ push @bans_to_remove, $banmask;
+}
+
+
+while (my @unbans = splice(@bans_to_remove,0,$conf->{max_ubans})) {
+ print {$bans_r_fh} q(/mode -), q(b) x ($#unbans+1), q( ), join(' ',@unbans);
+ print {$bans_r_fh} qq(\n);
+}