+sub pending
+{
+ print_messages("where retries is not null");
+}
+
+sub dump
+{
+ print_messages("");
+}
+
+sub clean
+{
+my($keyword,$interval)=@_;
+
+ # FIXME: SQL "now()" is raced against the block above
+ my $sth=DBI()->prepare("select id,time,retries from $DB_table where time>now()");
+ $sth->execute();
+ while (my $row=$sth->fetchrow_hashref()) {
+ warn "Message time in future: ".join(",",map(
+ "$_=".(!defined $row->{$_} ? "NULL" : $row->{$_})
+ ,keys(%$row)));
+ }
+
+ return if $interval eq "";
+ local $_=$interval;
+ my $print=s/^print://;
+ s/(\d+)y/($1*12)."m"/ge;
+ s/(\d+)m/($1*30)."d"/ge;
+ s/(\d+)d/($1*24)."h"/ge;
+ s/(\d+)h/($1*60)."M"/ge;
+ s/(\d+)M/($1*60)."s"/ge;
+ my $sec=0;
+ $sec+=$1 while s/(\d+)s//g;
+ die "Interval parse error; left \"$_\", parsed: $interval" if $_ ne "";
+ $sth=DBI()->prepare(($print ? "select id" : "delete")
+ ." from $DB_table where retries is null and time<from_unixtime(unix_timestamp()-$sec)");
+ $sth->execute();
+ if (!$print) {
+ print $sth->rows()."\n";
+ }
+ else {
+ while (my $row=$sth->fetchrow_hashref()) {
+ print $row->{"id"},"\n";
+ }
+ }
+}
+
+my $optwrap_err;
+sub optwrap
+{
+my($func,@args)=@_;
+
+ # Prevent successful return due to --forkoff in the case of failed --store when using:
+ # perlmail-submit --store --forkoff --submit
+ if (!eval { &{$func}(@args); 1; }) {
+ $optwrap_err||=$@||$!;
+ die "!FINISH";
+ die "NOTREACHED";
+ }
+}