chiark / gitweb /
break out local_part_inuse
[d.git] / service
diff --git a/service b/service
index c5dbfe498874e928155fcd3ab1fe3e2ad9419374..a966409b8da72bc043b42c9a52506cbf689f6aac 100755 (executable)
--- a/service
+++ b/service
@@ -12,8 +12,8 @@ END
 our $usage2 = <<'END';
 actions
   create [REDIRECT] [#COMMENT]    (default for REDIRECT is your username)
-  update LOCAL-PART [REDIRECT] [#COMMENT]
-  show LOCAL-PART
+  update ADDR [REDIRECT] [#COMMENT]
+  show ADDR
   list
   list-actions
 empty string for REDIRECT means reject
@@ -21,10 +21,11 @@ END
 our $usage3 = <<'END';
 privileged actions
   list-user USER
-  insert-exact LOCAL-PART USER REDIRECT COMMENT
-  donate LOCAL-PART USER
+  insert-exact ADDR USER REDIRECT COMMENT
+  donate ADDR USER
   enable-user|disable-user USER
 END
+#/
 
 use strict;
 
@@ -47,6 +48,17 @@ sub nextarg () {
     return $v;
 }
 
+sub addr2localpart ($) {
+    my ($addr) = @_;
+    return $addr if $addr !~ m/\@/;
+    die "address not in correct domain (\@$dom)\n" unless $' eq $dom; #';
+    return $`; #`;
+}
+
+sub nextarg_addr () {
+    return addr2localpart nextarg;
+}
+
 sub nomoreargs () {
     die "too many arguments\n" if @ARGV;
 }
@@ -133,16 +145,16 @@ sub rhsargs ($) {
     return $row;
 }
 
-sub action_create {
-    my $newrow = rhsargs({'redirect'=>$user, 'comment'=>''});
-    open R, "/dev/urandom" or die $!;
-    binmode R;
-    my $countq = $dbh->prepare("SELECT count(*) FROM addrs WHERE user=?");
-    $countq->execute($user);
-    my ($count) = $countq->fetchrow_array();
-    die unless defined $count;
-    die "too many aliases for this user\n" if $count >= $maxperuser;
-    my $q = $dbh->prepare("SELECT localpart FROM addrs WHERE localpart=?");
+sub local_part_inuse ($) {
+    my ($s) = @_;
+    our $checkexist_q ||=
+       $dbh->prepare("SELECT localpart FROM addrs WHERE localpart=?");
+    $checkexist_q->execute($s);
+    my $row = $checkexist_q->fetchrow_arrayref();
+    return !!$row;
+}
+
+sub generate_local_part () {
     my $s;
     for (;;) {
        $s = chr(ord('a')+goodrand(26));
@@ -153,13 +165,26 @@ sub action_create {
                      : ord('0')+($v-26));
        }
 #      print STDERR "$s\n";
-       $q->execute($s);
-       my $row = $q->fetchrow_arrayref();
-       last if !$row;
-       $dbh->abort();
+       last if !local_part_inuse($s);
     }
+    return $s;
+}
+
+sub prepare_create () {
+    my $countq = $dbh->prepare("SELECT count(*) FROM addrs WHERE user=?");
+    $countq->execute($user);
+    my ($count) = $countq->fetchrow_array();
+    die unless defined $count;
+    die "too many aliases for this user\n" if $count >= $maxperuser;
+    open R, "/dev/urandom" or die $!;
+    binmode R;
+}
+
+sub action_create {
+    my $newrow = rhsargs({'redirect'=>$user, 'comment'=>''});
+    prepare_create();
     $newrow->{'user'} = $user;
-    $newrow->{'localpart'} = $s;
+    $newrow->{'localpart'} = generate_local_part();
     insertrow($newrow);
     $dbh->commit();
     prow($newrow);
@@ -182,7 +207,7 @@ sub begin_row ($) {
 }
 
 sub action_update {
-    my $localpart = nextarg;
+    my $localpart = nextarg_addr;
     my $updrow = rhsargs({});
     nomoreargs;
     begin_row($localpart);
@@ -198,7 +223,7 @@ sub action_update {
 }
 
 sub action_show {
-    my $localpart = nextarg;
+    my $localpart = nextarg_addr;
     nomoreargs;
     my $row = begin_row($localpart);
     prow($row);
@@ -238,7 +263,7 @@ sub action_list_all {
 sub action_insert_exact {
     die unless $priv;
     my $row = { };
-    $row->{'localpart'} = nextarg;
+    $row->{'localpart'} = nextarg_addr;
     $row->{'user'} = $user = nextarg;
     $row->{'redirect'} = nextarg;
     $row->{'comment'} = nextarg;
@@ -249,7 +274,7 @@ sub action_insert_exact {
 
 sub action_donate {
     die unless $priv;
-    my $localpart = nextarg;
+    my $localpart = nextarg_addr;
     my $newuser = nextarg;
     nomoreargs;
     begin_row($localpart);
@@ -313,8 +338,9 @@ if (defined $ENV{'USERV_USER'}) {
     $user = ((getpwuid $<)[0]) or die;
 }
 
-$usage2 .= "LOCAL-PART is implicitly qualified with \@$dom\n"
-    if defined $qualdom;
+$usage2 .= defined $dom
+    ? "ADDR may be a local part, implicitly qualified with \@$dom\n"
+    : "ADDR must be a local part (only)\n";
 $usage2 .= "REDIRECT is implicitly qualified with \@$qualdom if it has no \@\n"
     if defined $qualdom;