--- /dev/null
+#!/usr/bin/perl -w
+use strict;
+our $pgm = $0; $pgm =~ s#.*/##;
+our $usage = <<'END';
+usage:
+ $pgm [<opts>] update <number>|<localpart>@[domain] [<reason>] [<comment>]
+ $pgm [<opts>] assign <number>|<localpart>@[domain] <comment>
+ $pgm [<opts>] show <count> } will generate more aliases
+ $pgm [<opts>] range [<from>-[<to>]] } if necessary
+opts:
+ -G<generator> generator/lister program
+ -N do not generate more aliases
+ -l.., -d.., -F.., -m.. passed to generator
+notes:
+ Always use $pgm to edit the comment of a pregen alias;
+ otherwise we may lose track of the next number alias to pregenerate
+ and reuse numbers.
+ <comment> must always start with #, and you will need to quote the
+ whole comment to protect it from your shell
+END
+
+our $generator;
+our @genopts;
+
+sub fetch_list {
+ open P, "-!", $generator, qw(list) or die $!;
+ while (<P>) {
+ my ($alias,$user);
+ if (m/^\# user/) {
+ next;
+ } elsif (m/^\# reject (\S+) (\#.*)$/) {
+ ($alias,$comment) = ($1,$2);
+ } elsif (m/^\#/) {
+ next; # future extension
+ } elsif (m/^([^#: ])\: [^#]* (\#.*)$/) {
+ ($alias,$comment) = ($1,$2);
+ } else {
+ die "generator output $_ ?";
+ }
+ my $localpart = $alias;
+ $localpart =~ s/\@.*//;
+ my $row = { Alias => $alias, LocalPart => $localpart };
+ if ($comment =~ m/^### PREGEN ([1-9]\d{0,8})$/) {
+ $row->{Number}= $1;
+ }
+ $by_localpart{$row->{LocalPart}} = $row;
+ $by_number[$row->{Number}] = $row if defined $row->{Number};
+ }
+ $?=0; $!=0; close P or die "$generator $! $?";
+
+}
+
+sub parse_target {
+ @ARGV or badusage "missing specification for alias to change";
+ my $spec = shift @ARGV;
+ my $target;
+ if ($spec =~ m/^(\d{1,9})$/) {
+ $target = $by_number[$spec];
+ die "no alias number $target\n" unless $target;
+ } elsif ($spec =~ m/^(.*)\@[^\@]*/) {
+ $target = $by_localpart{$1};
+ die "no alias with local part \`$1'\n" unless $target;
+ die "incorrect or unchecked domain: \`$target->{Alias}' != \`$spec'\n"
+ unless $spec eq $target->{Alias} ||
+ $spec eq $target->{LocalPart}.'@';
+ } else {
+ badusage "bad specification for alias to change";
+ }
+}
+
+sub action_update {
+ my $target = parse_target;
+ @ARGV or badusage "missing update info\n";
+ if (defined $target->{Number} && $target->{Number} == $#by_number) {
+ generate $target->{Number}+1;
+ }
+ exec $generator, qw(update), $target->{Alias}, @ARGV;
+ die "$generator: $!";
+}
+
+sub action_assign {
+ (@ARGV==2 &&
+ $ARGV[1] =~ m/^#/) or
+ badusage "invalid arguments to assign - forgot to quote it properly?";
+ action_update;
+}
+
+
+ (@ARGV==1 && $ARGV[0] =~ or badusage "missing assignment info (new comment)";
+ $ARGV[0]=~
+
+for (;;) {
+ last unless @ARGV;
+ last unless $ARGV[0] =~ m/^-/;
+ my $arg = shift @ARGV;
+ last if $arg =~ m/^--?$/;
+ if ($arg =~ m/^-[ldFm]/) {
+ push @genopts, $arg;
+ } elsif ($arg =~ m/^-G/) {
+ $generator = $'; #';
+ } else {
+ badusage "unknown option \`$arg'";
+ }
+}
+
+our $child = $pgm;
+$child =~ s/-pregen/; fixme fixme this should be defaulting generator
+
+@ARGV or badusage "missing action\n";
+my $action = shift @ARGV;
+$action =~ y/-/_/;
+{ no strict qw(refs); &{"action_$action"}; }