chiark / gitweb /
Improvements - now pretty much everything except password handling.
authorijackson <ijackson>
Tue, 22 Jun 1999 02:05:07 +0000 (02:05 +0000)
committerijackson <ijackson>
Tue, 22 Jun 1999 02:05:07 +0000 (02:05 +0000)
.cvsignore
bcp5-registry.pl
cgi-lib.pl
config.pl
database.pl
template.html
utils.pl [new file with mode: 0644]

index 9ddd1e0fd94702a5db4cc59811dc898143002e99..8f7cb21c7b45a950a01fa4c8b2a6f34a6acd2227 100644 (file)
@@ -1,3 +1,4 @@
 t.html
 list
 lockfile
+debug.txt
index 8d0a0b1c9a6a68e74320a8a40b05c9fb350c7246..038b7e281704c55dbddc86f6e859016f1b340eac 100755 (executable)
@@ -1,37 +1,51 @@
 #!/usr/bin/perl
 
-use POSIX;
+system '(date;env) >debug.txt';
 
-$|=1;
-print "Content-Type: text/html\n\n" or die $!;
-$|=0;
+use POSIX;
 
 if ($ENV{'BCP5REGISTRY_NOCGI'}) {
     $scriptdir= '.';
     $invokestyle= 'manual';
     open DEBUG,">&STDERR" or die $!;
-    foreach $x (@ARGV) {
-       $x =~ m/^(\w+)\=/ or die "$x ?";
-       $in{$1}= $';
-       print DEBUG "$1 -> \"$'\"\n";
-    }
 } else {
+    $ct= 'BCP5REGISTRY_CONTENTTYPEDONE';
+    if (!$ENV{$ct}) {
+       $|=1;
+       print "Content-Type: text/html\n\n" or die $!;
+       $|=0;
+       $ENV{$ct}= 1;
+    }
+
     if ($ENV{'SERVER_SOFTWARE'} =~ m/Lynx/) {
+       open DEBUG,">>debug.txt" or die $!;
        $scriptdir= '.';
        $invokestyle= 'lynxcgi';
     } else {
+       open DEBUG,"/dev/null" or die $!;
        $scriptdir= $ENV{'SCRIPT_FILENAME'};
        $scriptdir =~ s,/[^/]+$,,;
        $invokestyle= 'cgi';
     }
-    require 'cgi-lib.pl';
-    &ReadParse;
-    open DEBUG,"/dev/null" or die $!;
 }
 
 chdir($scriptdir) or die $!;
 require 'config.pl';
 require 'database.pl';
+require 'utils.pl';
+
+if ($invokestyle ne 'manual') {
+    lock_database();
+    require 'cgi-lib.pl';
+    &ReadParse;
+    foreach $k (keys %in) { print DEBUG "$k -> \"$in{$k}\"\n"; }
+} else {
+    foreach $x (@ARGV) {
+       $x =~ m/^(\w+)\=/ or die "$x ?";
+       $in{$1}= $';
+       print DEBUG "$1 -> \"$'\"\n";
+    }
+}
 
 if ($invokestyle eq 'lynxcgi') {
     defined($pwd= getcwd) or die $!;
@@ -44,13 +58,20 @@ if ($invokestyle eq 'lynxcgi') {
 $rec_areai= 1;
 
 $current_areai= $rec_areai;
-$list_areai= -1;
+$list_areai= '';
 $listoverlap= '';
 
+$listing= '';
 $intro= 0;
 $error= 0;
 $registernew= 0;
 $pick= 0;
+$pickvarsubnet= 8;
+$pickvarprefix= 24;
+$pick28check= '';
+$pick24check= 'checked';
+$pickvarsubnetcheck= '';
+$pickvarprefixcheck= '';
 $details= 0;
 $fulldetails= 0;
 $justcreated= 0;
@@ -62,15 +83,15 @@ $list= 0;
 $notfound= 0;
 $id= '';
 $name= '';
+$contact= '';
 $email= '';
 $net= '';
 $emailhidechecked= '';
 $hiddenemail= 0;
 
-$listingarea= $list_areai>=0;
+$listingarea= length $list_areai;
 $listingoverlap= length $listoverlap;
 
-open RAND,"/dev/urandom" or die $!;
 defined($now= time) or die $!;
 
 if (length $in{'register'}) {
@@ -87,6 +108,8 @@ if (length $in{'register'}) {
     set_entry();
 
     $justcreated= 1;
+    send_password();
+
     show_entry();
     finish();
     
@@ -94,9 +117,10 @@ if (length $in{'register'}) {
 
     read_database();
     get_entry();
-    send_password();
 
     $passwordsent= 1;
+    send_password();
+
     finish();
     
 } elsif (length $in{'view'}) {
@@ -112,6 +136,7 @@ if (length $in{'register'}) {
 } elsif (length $in{'update'}) {
     
     lock_database();
+    read_database();
     get_entry();
     check_password();
     check_generation();
@@ -127,6 +152,7 @@ if (length $in{'register'}) {
 } elsif (length $in{'delete'}) {
 
     lock_database();
+    read_database();
     get_entry();
     check_password();
     check_generation();
@@ -139,6 +165,7 @@ if (length $in{'register'}) {
 
 } elsif (length $in{'pick'}) {
 
+    read_database();
     pick_net();
     $picked= 1;
     $pick= 1;
@@ -148,8 +175,8 @@ if (length $in{'register'}) {
 } elsif (length $in{'list'}) {
 
     read_database();
-    list_database();
-    $list= 1;
+    $list_areai= $in{'listareai'};
+    list_database($in{'list'});
     finish();
 
 } elsif (length $in{'id'}) {
@@ -159,7 +186,6 @@ if (length $in{'register'}) {
     $details= 1;
     show_entry();
     $list= 1;
-    $pick= 1;
     finish();
 
 } else {
@@ -167,20 +193,17 @@ if (length $in{'register'}) {
     $intro= 1;
     $list= 1;
     $pick= 1;
+    $displayemail= 1;
     $registernew= 1;
     finish();
 
 }
 
-sub set_entry () {
-    my $v, $b, @b, $val, $mask;
-    $name= $in{'name'};
-    foreach $v (qw(name email)) {
-       length $$v or finish_error("no$v");
-       finish_error("badchar") unless $$v =~ m/^[ -\176\240\376]+$/; $$v= $&;
-    }
-    $hiddenemail= !!length $in{'hiddenemail'};
-    $net= $in{'net'};
+sub parse_netrange ($) {
+    my ($net) = @_;
+    my ($prefix,$network,@b,$b,$val,$mask);
+
+    length $net or finish_error('nonet');
 print DEBUG "got $net\n";
     $net =~ s,/(\d+)$,, or finish_error("badnet");
 print DEBUG "prefix $1\n";
@@ -196,17 +219,32 @@ print DEBUG "@b\n";
        $b>=0 && $b<=255 or finish_error("badnet");
        $network .= sprintf("%02x",$b);
     }
-print DEBUG "$network\n";
     ($val,$mask) = net_valuemask($network,$prefix);
 printf DEBUG "%08x %08x %08x\n", $val,$mask,~$mask;
     !($val & ~$mask) or finish_error("badnet");
 print DEBUG "ok\n";
+    return ($network,$prefix,$val,$mask);
+}
+
+sub set_entry () {
+    my ($v, $b, @b, $val, $mask);
+    $net= $in{'net'};
+
+    ($network,$prefix,$val,$mask) = parse_netrange($net);
+print DEBUG "set_entry parsed netrange $network $prefix\n";
     $current_areai= find_areai($network,$prefix);
 print DEBUG "$current_areai\n";
     $current_areai>=0 or finish_error("wrongnet");
 print DEBUG "ok\n";
+    
+    foreach $v (qw(name contact email)) {
+       $$v= $in{$v} unless $v eq 'email';
+       length $$v or finish_error("no$v");
+       finish_error("badchar") unless $$v =~ m/^[ -\176\240\376]+$/; $$v= $&;
+    }
+    $hiddenemail= !!length $in{'hiddenemail'};
 
-    foreach $k (qw(generation network prefix name email hiddenemail)) {
+    foreach $k (qw(generation network prefix name contact email hiddenemail)) {
        $ent->{$k}= $$k;
     }
 
@@ -215,7 +253,7 @@ print DEBUG "ok\n";
 
 sub find_areai ($$) {
     my ($network,$prefix) = @_;
-    my $i;
+    my ($i);
     for ($i=0; $i<@area_networks; $i++) {
        next unless net_subset($network,$prefix, $area_networks[$i],$area_prefixes[$i]);
        return $i;
@@ -232,9 +270,21 @@ sub net_subset ($$$$) {
     return 1;
 }
 
-sub net_valuemask($$) {
+sub get_mask ($) {
+    my ($prefix) = @_;
+    my ($m, $sh);
+    $m= 0xffffffff;
+    $sh= 32-$prefix;
+    $sh2= 0;
+    if ($sh>=16) { $sh2 += 16; $sh -= 16; }
+    $m <<= $sh;
+    $m <<= $sh2;
+    return $m;
+};
+
+sub net_valuemask ($$) {
     my ($network,$prefix) = @_;
-    return (hex($network), (0xffffffff << (32-$prefix)));
+    return (hex($network), get_mask($prefix));
 }
 
 sub get_entry () {
@@ -245,7 +295,7 @@ sub get_entry () {
 }
 
 sub show_entry () {
-    my $k, $dk;
+    my ($k, $dk);
     foreach $k (@db_fields) {
        $$k= $ent->{$k};
     }
@@ -253,23 +303,29 @@ sub show_entry () {
        $dk= "date$k";
        $$dk= gmtime($$k)." GMT";
     }
+    if ($ent->{'hiddenemail'} && !$justcreated && !$fulldetails && !$justupdated) {
+       $displayemail= 0;
+       $email= '';
+    } else {
+       $displayemail= 1;
+    }
     $net= display_net($network,$prefix);
+    $emailhidechecked= $ent->{'hiddenemail'} ? 'checked' : '';
 }
 
-sub list_database () {
-    my $t, $v, $k, $x;
-    $listing= '';
-    foreach $t (qw(all area overlap)) {
-       $listing= $t if length $in{"list$t"};
-    }
-    die unless $listing;
-    $v= "listing$listing"; $$v= 1;
+sub list_database ($) {
+    my ($instyle) = @_;
+    my ($t, $v, $k, $x);
+print DEBUG "ldb 0 $instyle\n";
+    $instyle =~ m/all|area|overlap/ or die "$instyle ?";
+    $listing= $&;
     &{"dblist_prep_$listing"}();
     @kl= ();
-print DEBUG "ldb 1 @kl\n";
+print DEBUG "ldb 1 $v @kl\n";
     foreach $k (keys %db) {
 print DEBUG "ldb q $k\n";
-       next unless &{"dblist_cond_$listing"}($db{$k});
+        $ent= $db{$k};
+       next unless &{"dblist_cond_$listing"};
        push @kl,$k;
     }
 print DEBUG "ldb 2 @kl\n";
@@ -279,117 +335,129 @@ print DEBUG "ldb 2 @kl\n";
        return -1 if $a eq 'picked' && $b ne 'picked';
        return +1 if $b eq 'picked' && $a ne 'picked';;
        $x= $db{$a}->{'name'} cmp $db{$b}->{'name'}; return $x if $x;
+       $x= $db{$a}->{'contact'} cmp $db{$b}->{'contact'}; return $x if $x;
        return $a cmp $b;
     } @kl;
 print DEBUG "ldb 3 @kl\n";
     $listingnonefound= @kl ? 0 : 1;
 print DEBUG "ldb end $listingnonefound\n";
+    $v= "listing$listing"; $$v= 1;
+    $list= 1;
 }
 
 sub check_generation () {
     $ent->{'generation'} eq $ent->{'generation'} or finish_error('generation');
 }
 
+sub pick_net () {
+    my ($ai, $k, $vn, $rand, $mask, $fixmask, $value);
+    
+    $ai= $in{'from'}; $ai =~ m/\d+/ or die "$ai ?"; $ai= $&;
+    ($ai>=0 && $ai<@area_networks) or die "$ai ?";
+    $current_areai= $ai;
+
+    foreach $k (qw(24 28 prefix subnet)) { $vn= "pick${k}check"; $$vn= ''; }
+    foreach $k (qw(prefix subnet)) { $vn= "pickvar${k}"; $$vn= $in{$vn}; }
+
+    $_= $in{'specsize'};
+    if (m/\d+/) {
+       $specsize= $&+0;
+       $vn= "pick${specsize}check"; $$vn= 'checked';
+    } elsif (m/prefix|subnet/) {
+       $which= $&;
+       $vn= "pickvar${which}check"; $$vn= 'checked';
+       $specsize= $in{"pickvar${which}"};
+       $specsize =~ m/\d+/ or finish_error('badsize');
+       $specsize= $&+0;
+       ($specsize >= 0 && $specsize <= 32) or finish_error('badsize');
+       $specsize= 32-$specsize if $which eq 'subnet';
+    } else {
+       die "$_ ?";
+    }
+
+    $network= $area_networks[$ai];
+    $prefix= $area_prefixes[$ai];
+    $net= display_net($network,$prefix);
+    ($specsize >= $prefix) or finish_error('wrongsize');
+
+    $fixmask= get_mask($prefix);
+    $mask= get_mask($specsize);
+    $rnybs= randnybs(8);
+    $rand= hex($rnybs);
+    $value= hex($network) | ($rand & ($mask & ~$fixmask));
+    $vhex= sprintf '%08x',$value;
+
+    $net= display_net($vhex,$specsize);
+    $displayemail= 1;
+
+printf DEBUG "picking network=$network prefix=$prefix net=$net specsize=$specsize\n";
+printf DEBUG "picking rnybs=%s fixmask=%08x mask=%08x rand=%08x ".
+    "value=%08x vhex=%s net=%s\n",
+    $rnybs,$fixmask,$mask,$rand,$value,$vhex,$net;
+
+    $ent= { };
+    $db{'picked'}= $ent;
+    $ent->{'network'}= $vhex;
+    $ent->{'prefix'}= $specsize;
+    $list_areai= $ai;
+    list_database('area');
+}
+
 sub finish_error ($) {
     my ($type) = @_;
-    my $t, $esel;
-    foreach $t (qw(noemail noname badnet wrongnet notfound generation badchar)) {
+    my ($t, $esel, $f);
+    foreach $t (qw(noemail nonet noname nocontact badsize wrongsize badnet wrongnet
+                  notfound generation badchar)) {
        $esel= "error_$t";
        $$esel= 0;
+       $f=1 if $type eq $t;
     }
-    my $esel= "error_$type";
+    die $type unless $f;
+    $esel= "error_$type";
     $$esel= 1;
     $error= 1;
     finish();
 }
 
 sub finish () {
-    open X, "template.html" or die $!;
-    @x= <X>;
-    close X or die $!;
-
-    $x[$#x] eq "\@\@\@eof:\@\@\@\n" or die $!;
-    $#x--;
-
-    $cl= 0;
-    $level= -1;
-    process(1);
-
+    process_file('template.html');
+    print $out or die $!;
     close STDOUT or die $!;
     exit 0;
 }
 
-sub display_net ($$) {
-    my ($network,$prefix) = @_;
-    return join('.', unpack("C4",pack("H8",$network)))."/".$prefix;
-}
+sub dblist_prep_all { }
+sub dblist_cond_all { 1; }
 
-sub randnybs ($) {
-    my ($nybbles) = @_;
-    my $v;
-    my $bytes= $nybbles/2;
-    read(RAND,$v,$bytes) == $bytes or die $!;
-    return scalar unpack("H$nybbles",$v)
+sub dblist_prep_area {
+    my ($network,$prefix);
+    $network= $area_networks[$list_areai];
+    $prefix= $area_prefixes[$list_areai];
+    $listarea= display_net($network,$prefix);
+    $dbl_mask= get_mask($prefix);
+    $dbl_value= hex($network);
 }
-
-sub out ($) {
-    print $_[0],"\n" or die $!;
+sub dblist_cond_area {
+    my ($v, $r);
+    $v= hex($ent->{'network'});
+    $r= 1 if ($v & $dbl_mask) == $dbl_value;
+print DEBUG "dblist_cond_area $k $v $r\n";
+    return $r;
 }
 
-sub process ($) {
-    my ($doing) = @_;
-    my ($bcl);
-    $level++;
-    for (;;) {
-       return if $cl > $#x;
-       $_= $x[$cl++];
-       s/\n$//; s/\s*$//;
-#      out("<!-- $level $doing $_ -->");
-       last if m/^\@\@\@end\w+\:\@\@\@$/;
-
-       if (m/^\@\@\@(if|ifnot):([0-9a-z_|]+)\@\@\@$/) {
-           $q=$1; $v=$2;
-           $do= 0;
-           if ($doing) {
-               map { $do=1 if getvar($_); } split(/\|/,$v);
-               $do= !$do if $q eq 'ifnot';
-#          out("<!-- $level $doing $do $q $v $_ -->");
-           }
-           process($doing && $do);
-       } elsif (m/^\@\@\@foreach\:(area|db)\@\@\@$/) {
-           if ($doing) {
-               $bcl= $cl;
-               for (&{"foreach_start_$1"};
-                    &{"foreach_cond_$1"};
-                    &{"foreach_incr_$1"}) {
-                   &{"foreach_setvars_$1"};
-                   process($doing);
-                   $cl= $bcl;
-               }
-           }
-           process(0);
-       } elsif (m/\S/) {
-           if ($doing) {
-               s/\@\@\@(\w+)\@\@\@/ getvar("$1") /ge;
-               out($_);
-           } else {
-               s/\@\@\@\w+\@\@\@//g;
-           }           
-           die "$cl:unknown $_\n" if m/\@\@\@/;
-       }
-    }
-    $level--;
+sub dblist_prep_overlap {
+    my ($network,$prefix);
+    ($network,$prefix,$dbl_mask,$dbl_value) = parse_netrange($in{'with'});
+    $listoverlap= display_net($network,$prefix);
 }
-
-sub getvar ($) {
-    my ($vn) = @_;
-    defined $$vn or die "$cl:undefined $vn\n$out";
-    return $$vn;
+sub dblist_cond_overlap {
+    my ($v, $m);
+    $v= hex($ent->{'network'});
+    $m= get_mask($ent->{'prefix'});
+    $m &= $dbl_mask;
+    return ($v & $m) == ($dbl_value & $m);
 }
 
-sub dblist_prep_all { }
-sub dblist_cond_all { 1; }
-
 sub foreach_start_area { $area_i=0; }
 sub foreach_cond_area { return $area_i < @area_networks; }
 sub foreach_incr_area { $area_i++; }
@@ -398,8 +466,8 @@ sub foreach_setvars_area {
     $area= display_net($area_network,$area_prefixes[$area_i]);
     $area_recommended= $area_i==$rec_areai;
     $area_pickchecked= $area_i==$current_areai ? 'checked' : '';
-    $area_listing= $area_i==$list_areai;
-#    out("<!-- setvars_area @area_networks $area_i $area -->");
+    $area_listing= $area_i eq $list_areai;
+    out("<!-- setvars_area @area_networks $area_i $area $list_areai -->");
 }
 
 %saniarray= ('<','lt', '>','gt', '&','amp', '"','quot');
@@ -418,15 +486,17 @@ sub foreach_start_db { $db_i=0; }
 sub foreach_cond_db { return $db_i < @kl; }
 sub foreach_incr_db { $db_i++; }
 sub foreach_setvars_db {
-    my $k, $ent;
+    my ($k, $ent);
     $k= $kl[$db_i];
     $ent= $db{$k};
-    if ($k eq 'picked') {
-       unset $db_id;
+    $db_picked= $k eq 'picked';
+    if ($db_picked) {
+       undef $db_id;
     } else {
        $db_id= $k;
     }
     $db_net= display_net($ent->{'network'}, $ent->{'prefix'});
     $db_name= html_sani($ent->{'name'});
+    $db_contact= html_sani($ent->{'contact'});
     $db_email= $ent->{'hiddenemail'} ? "" : html_sani($ent->{'email'});
 }
index 97e894d1914549386b97eb26d7ec8a3dfb17c973..6175eec340d5160c2d32695b8172dc6362d34d8c 100644 (file)
 
 sub ReadParse {
   local (*in) = @_ if @_;
-  local ($i, $key, $val);
+  local ($i, $key, $val, $cl, $rd);
 
   # Read in text
   if (&MethGet) {
     $in = $ENV{'QUERY_STRING'};
   } elsif (&MethPost) {
-    read(STDIN,$in,$ENV{'CONTENT_LENGTH'});
+    $cl = $ENV{'CONTENT_LENGTH'};
+    $rd= read(STDIN,$in,$cl);
+    $rd == $cl or CgiDie("unable to read POST data ($cl, $rd, $!)");
   }
 
   @in = split(/[&;]/,$in);
index a167a8b360ecd50ead1c6eb7c333ea8d8b1ebed8..b54b921376c45fba608df51554b69e544ec818c3 100644 (file)
--- a/config.pl
+++ b/config.pl
@@ -1,5 +1,9 @@
-$whose= "Cambridge Geeks'";
-$adminemail= 'ijackson+cam-bcp5@chiark.greenend.org.uk';
+$whose= "Cambridge";
+$adminname= 'Ian Jackson';
+$adminemail= 'ijackson+cam-grin@chiark.greenend.org.uk';
 $nameboxlen= 55;
+$contactboxlen= 55;
 $emailboxlen= 55;
 $cgi= 'http://www.chiark.greenend.org.uk/ucgi/~ijackson/bcp5-registry.pl';
+
+$ENV{'PATH'}= '/usr/local/bin:/bin:/usr/bin';
index a9c8295d89fedbc7b47405f0fc797102852ae298..720a6c35629e57da82e3a462c5ec70722701ccf9 100644 (file)
@@ -1,10 +1,10 @@
 #
 
-@db_fields= qw(generation network prefix name email hiddenemail created changed);
+@db_fields= qw(generation network prefix name contact email hiddenemail created changed);
 
 sub read_database () {
 print DEBUG "reading\n";
-    my @v,$id;
+    my (@v,$id);
     open DBF, "list" or die $!;
     for (;;) {
        $_= <DBF>;
@@ -25,7 +25,7 @@ print DEBUG "reading\n";
 $db_lock_env= 'BCP5REGISTRY_LOCKED';
 
 sub write_database () {
-    my $k,$v;
+    my ($k,$v);
 print DEBUG "writing\n";
     die unless $ENV{$db_lock_env};
     open DBF, ">list.new" or die $!;
@@ -44,8 +44,8 @@ print DEBUG "locking\n";
     die if $db_read;
     return if $ENV{$db_lock_env};
     $ENV{$db_lock_env}= '1';
-    exec 'with-lock-ex','-w','lockfile',$0,@ARGV;
-    die $!;
+    exec 'with-lock-ex','-w','lockfile',"$0",@ARGV;
+    die "$ENV{'PATH'}: $!";
 }
 
 1;
index 84e224dc33744bd7d5837c21d3f33ebd559f500c..e0b4befb23d0a1ddf13f6b3feadc1534f46ca46a 100644 (file)
@@ -1,12 +1,11 @@
 <html><head>
 
+<title>@@@whose@@@ G-RIN -
+
 @@@if:intro@@@
-<title>@@@whose@@@ BCP5 (RFC1918) Registry</title>
+BCP5 (RFC1918) Registry
 @@@endif:@@@
 
-@@@ifnot:intro@@@
-<title>@@@whose@@@ BCP5 Registry -
-
 @@@if:picked@@@
 @@@net@@@ picked
 @@@endif:@@@
@@ -31,9 +30,11 @@ updated @@@name@@@
 entire database
 @@@endif:@@@
 
+@@@ifnot:picked@@@
 @@@if:listingarea@@@
 subset for @@@listarea@@@
 @@@endif:@@@
+@@@endif:@@@
 
 @@@if:listingoverlap@@@
 overlapping with @@@listoverlap@@@
@@ -49,16 +50,19 @@ error
 @@@endif:@@@
 
 </title>
-@@@endif:@@@
 
 <link rev="made" href="mailto:@@@adminemail@@@">
 </head>
 <body>
 
-<h1>@@@whose@@@ BCP5 (RFC1918) network numbers registry
+@@@if:intro@@@
+<h1>@@@whose@@@ G-RIN (Geeks' Registry of Internet Numbers)
+<br>
+BCP5 (RFC1918) network numbers registry
+@@@endif:@@@
 
 @@@ifnot:intro@@@
-<br>
+<h1>
 @@@endif:@@@
 
 @@@if:picked@@@
@@ -81,9 +85,11 @@ Database entry updated: @@@name@@@
 Entire database listing
 @@@endif:@@@
 
+@@@ifnot:picked@@@
 @@@if:listingarea@@@
 Database subset listing for @@@listarea@@@
 @@@endif:@@@
+@@@endif:@@@
 
 @@@if:listingoverlap@@@
 Database search, entries overlapping with @@@listoverlap@@@
@@ -139,6 +145,17 @@ quad by a slash, and must be between 0 and 32.  None of the bits in
 the dotted quad beyond the prefix length must be set.
 @@@endif:@@@
 
+@@@if:error_badsize@@@
+You entered an invalid size for your prefix or subnet.
+You must enter a number between 0 and 32.
+@@@endif:@@@
+
+@@@if:error_wrongsize@@@
+The subnet size you requested (@@@specsize@@@-bit prefix) is larger
+(contains more addresses) than the size of the private-use range you
+selected (@@@net@@@).
+@@@endif:@@@
+
 @@@if:error_wrongnet@@@
 The network number you specified does not lie wholly within the
 BCP5-allocated private-use address ranges.
@@ -162,16 +179,79 @@ changes.
 You must provide an email address.
 @@@endif:@@@
 
+@@@if:error_nocontact@@@
+You must provide a contact name.
+@@@endif:@@@
+
+@@@if:error_nonet@@@
+You must provide a network number !
+@@@endif:@@@
+
 @@@if:error_noname@@@
 You must provide a network name for the database.
 @@@endif:@@@
 
 @@@if:error_badchar@@@
-The name or email address you specified contains illegal character(s).
+The name, contact or email address you specified contains illegal character(s).
+@@@endif:@@@
+
+@@@endif:@@@
+
+
+@@@if:pick@@@
+
+@@@ifnot:picked@@@
+<h2>Pick a random subnet</h2>
+@@@endif:@@@
+@@@if:picked@@@
+<h2>Pick another random subnet</h2>
 @@@endif:@@@
 
+<form method="POST" action="@@@cgi@@@">
+
+with prefix length
+<br>
+<input type=radio name="specsize" value="28" @@@pick28check@@@> 28 bits
+ (an 4 bit subnet, with 14 hosts)
+<br>
+<input type=radio name="specsize" value="24" @@@pick24check@@@> 24 bits
+ (an 8 bit subnet, with 254 hosts) - <em>recommended</em>
+<br>
+<input type=radio name="specsize" value="prefix" @@@pickvarprefixcheck@@@>
+ <input type=text name="pickvarprefix" size="24"
+  value="@@@pickvarprefix@@@" size="5"> bits.
+<br>
+<input type=radio name="specsize" value="subnet" @@@pickvarsubnetcheck@@@>
+ <input type=text name="pickvarsubnet" size="8"
+ value="@@@pickvarsubnet@@@" size="5"> bit subnet.
+<p>
+
+from the private-use range
+
+@@@foreach:area@@@
+
+<br>
+<input type=radio name="from" value="@@@area_i@@@" @@@area_pickchecked@@@>
+@@@area@@@
+@@@if:area_recommended@@@
+ - <em>recommended</em>
 @@@endif:@@@
 
+@@@endforeach:@@@
+<p>
+
+@@@ifnot:picked@@@
+<input type=submit name="pick" value="Pick network.">
+@@@endif:@@@
+@@@if:picked@@@
+<input type=submit name="pick" value="Pick another network.">
+@@@endif:@@@
+
+</form>
+
+@@@endif:@@@
+
+
 @@@if:registernew@@@
 <h2>Register a network range you are using</h2>
 You may register an existing network range you are using in our
@@ -179,7 +259,7 @@ database.
 @@@endif:@@@
 
 @@@if:picked@@@
-<h2>Random network range chosen</h2>
+<h2>Random network range chosen - register it ?</h2>
 I have picked the random network numbering range
 <strong>@@@net@@@</strong> for you.  You can see its relationship
 to other entries in the database of networks people are using -
@@ -205,11 +285,13 @@ the entry.
 
 @@@if:justcreated@@@
 <h2>Entry created</h2>
+
 The database entry has been created, but will only persist for a short
-time unless you confirm it.  You have beeen sent an email requesting
-confirmation.  You may use `confirm/update', below, to do the
-confirmation, or return at a later date when you have received the
-email.
+time unless you confirm it.  You have beeen sent an email with your
+password, requesting confirmation.  When you have received the email
+you may use `confirm/update', below, to confirm your database entry.
+If you do not confirm it it will expire in a few days.
+
 @@@endif:@@@
 
 @@@if:justupdated@@@
@@ -226,22 +308,20 @@ The database entry below has been updated/confirmed/renewed.
 <input type=hidden name="id" value="@@@id@@@">
 
 Network range:
-@@@if:picked@@@
-<input type=hidden name="net" value="@@@net@@@">@@@net@@@
-@@@endif:@@@
-@@@ifnot:picked@@@
-<input type=text name="net" value="@@@net@@@" size=20>
-@@@endif:@@@
+<input type=text name="net" value="@@@net@@@" size="20">
 <br>
 
 Network name:
 <input type=text name="name" size="@@@nameboxlen@@@" value="@@@name@@@"><br>
 
-@@@ifnot:hiddenemail@@@
-Contact email address:
+Contact name:
+<input type=text name="contact" size="@@@contactboxlen@@@" value="@@@contact@@@"><br>
+
+@@@if:displayemail@@@
+Email address:
 @@@endif:@@@
-@@@if:hiddenemail@@@
-Contact email address hidden.
+@@@ifnot:displayemail@@@
+Email address hidden.
 New address:
 @@@endif:@@@
 <input type=text name="email" size="@@@emailboxlen@@@" value="@@@email@@@">
@@ -249,9 +329,10 @@ New address:
 
 <input type=checkbox name="hiddenemail" value="yes" @@@emailhidechecked@@@>
 Hide email address from public database.
+<br>
 
 @@@if:registernew|picked@@@
-<input type=submit name="register" value="Register">
+<input type=submit name="register" value="Register.">
 @@@endif:@@@
 
 @@@if:details|fulldetails|justcreated|justupdated@@@
@@ -270,29 +351,38 @@ Not yet confirmed.
 @@@if:details@@@
 <h3>Password request</h3>
 
-Use this to obtain your password.  Passwords expire after a while; if
-you do not have a recent notification of your password, you should
-request a current password: <br>
-<input type=submit name="mailpasswd" value="Mail password">
+Use this to obtain your password, if you do not have it or it doesn't
+seem to work.  The passwords expire after a while; if you do not have
+a recent notification of your password, you should request a current
+password:
+<p>
+
+<input type=submit name="mailpasswd" value="Mail password."><br>
+(The password will be sent to the registered email address for the
+entry.)
+
 @@@endif:@@@
 
 @@@if:details|fulldetails|justcreated|justupdated@@@
-<h3>Modify or manage existing entry</h3>
+<h3>Modify or manage this entry</h3>
 @@@endif:@@@
 
 @@@if:details|justcreated@@@
 Using your password, you can update the details above (if you have
-changed them), confirm or renew your entry (to stop it expiring), and
-view the full details, including any hidden email address: <br>
+changed them) and confirm or renew your entry (to stop it expiring).
+@@@ifnot:displayemail@@@
+You can also view the full details, including the hidden email address.
+@@@endif:@@@
+<p>
 @@@endif:@@@
 
-@@@if:details|justcreated|justupdated@@@
+@@@ifnot:displayemail@@@
 <input type=submit name="view" value="View full details.">
 @@@endif:@@@
 
 @@@if:details|fulldetails|justcreated|justupdated@@@
-<input type=submit name="update" value="Update/confirm/renew">
-<input type=submit name="delete" value="Delete">
+<input type=submit name="update" value="Update/confirm/renew.">
+<input type=submit name="delete" value="Delete.">
 <br>
 @@@endif:@@@
 
@@ -310,60 +400,28 @@ Password: supplied.
 @@@endif:@@@
 
 
-@@@if:pick@@@
-
-<h2>Pick a random network range</h2>
-
-<form method="POST" action="@@@cgi@@@">
-with 24-bit prefix (ie, 254 hosts)
-
-from
-<br>
-
-@@@foreach:area@@@
-
-<input type=radio name=from value="@@@area@@@" @@@area_pickchecked@@@>
-@@@area@@@
-@@@if:area_recommended@@@
-<em>recommended</em>
-@@@endif:@@@
-<br>
-
-@@@endforeach:@@@
-
-@@@ifnot:picked@@@
-<input type=submit name="pick" value="Pick network">
-@@@endif:@@@
-@@@if:picked@@@
-<input type=submit name="pick" value="Pick another network">
-@@@endif:@@@
-
-</form>
-
-@@@endif:@@@
-
-
 @@@if:list@@@
 
 <h2>View database</h2>
 
-<form method="GET" action="@@@cgi@@@">
-<input type=hidden name="list" value="yes">
+<ul>
 
+<li>
 @@@ifnot:listingall@@@
-
-<input type=submit name="listall" value="Entire database">
-
+<a href="@@@cgi@@@?list=all">Entire database</A>
+@@@endif:@@@
+@@@if:listingall@@@
+Entire database
 @@@endif:@@@
 
-<h3>Entries allocated from</h3>
+<li>Entries allocated from:
 
 <ul>
 @@@foreach:area@@@
 
 <li>
 @@@ifnot:area_listing@@@
-<a href="@@@cgi@@@?listarea=@@@area@@@">@@@area@@@</A>
+<a href="@@@cgi@@@?list=area&listareai=@@@area_i@@@">@@@area@@@</A>
 @@@endif:@@@
 @@@if:area_listing@@@
 @@@area@@@
@@ -372,15 +430,16 @@ from
 @@@endforeach:@@@
 </ul>
 
-@@@endif:@@@
-
-@@@if:list@@@
-<h3>Entries overlapping with</h3>
+<li>Entries overlapping with
 
+<form method="GET" action="@@@cgi@@@">
+<input type=hidden name="list" value="overlap">
 <input type=text name="with" value="@@@listoverlap@@@" size="30">
-<input type=submit name="listoverlap" value="Search">
-
+<input type=submit name="listoverlap" value="Search.">
 </form>
+
+</ul>
+
 @@@endif:@@@
 
 @@@if:listingall|listingarea|listingoverlap@@@
@@ -400,7 +459,7 @@ Database for entries allocated from @@@listarea@@@
 </h3>
 
 @@@if:picked@@@
-The range picked for you has been <em>emphasized</em> below.
+The range picked for you has been <strong>emphasized</strong> below.
 @@@endif:@@@
 <p>
 
@@ -410,13 +469,20 @@ You can get details about an existing entry by clicking on its address
 range; this can also be used to modify it.
 
 <table>
-<tr><td>Range <td>Name <td>Contact email
-</tr><br>
+<tr><td>Range <td>Name <td>Contact <td>Email
+</tr><p>
 @@@foreach:db@@@
+@@@if:db_picked@@@
+<tr><td><a name="picked"><strong>@@@db_net@@@</strong></a>
+<td colspan=3><strong>network randomly picked as requested</strong>
+@@@endif:@@@
+@@@ifnot:db_picked@@@
 <tr><td><A href="@@@cgi@@@?id=@@@db_id@@@">@@@db_net@@@</A>
 <td>@@@db_name@@@
+<td>@@@db_contact@@@
 <td>@@@db_email@@@
-</tr><br>
+@@@endif:@@@
+</tr><p>
 @@@endforeach:@@@
 </table>
 
@@ -428,6 +494,11 @@ There are no matching entries in the database.
 
 @@@endif:@@@
 
+<address>
+<a href="@@@cgi@@@">@@@whose@@@ G-RIN</a><br>
+Queries or problems ?  Contact the administrator,
+<a href="mailto:@@@adminemail@@@">@@@adminname@@@</a>.
+
 </body>
 </html>
 @@@eof:@@@
diff --git a/utils.pl b/utils.pl
new file mode 100644 (file)
index 0000000..1134e00
--- /dev/null
+++ b/utils.pl
@@ -0,0 +1,91 @@
+#
+
+open RAND,"/dev/urandom" or die $!;
+
+sub process_file ($) {
+    my ($filename) = @_;
+    
+    open X, "$filename" or die "$filename: $!";
+    @x= <X>;
+    close X or die $!;
+
+    $x[$#x] eq "\@\@\@eof:\@\@\@\n" or die $!;
+    $#x--;
+
+    $cl= 0;
+    $out= '';
+    $level= -1;
+    process(1);
+}
+
+sub display_net ($$) {
+    my ($network,$prefix) = @_;
+    return join('.', unpack("C4",pack("H8",$network)))."/".$prefix;
+}
+
+sub randnybs ($) {
+    my ($nybbles) = @_;
+    my ($v, $r, $bytes);
+    $bytes= $nybbles/2;
+    read(RAND,$v,$bytes) == $bytes or die $!;
+    $r= scalar unpack("H$nybbles",$v);
+print DEBUG "randnybs($nybbles) -> $r\n";
+    return $r;
+}
+
+sub out ($) {
+    $out.= $_[0]."\n";
+}
+
+sub process ($) {
+    my ($doing) = @_;
+    my ($bcl);
+    $level++;
+    for (;;) {
+       return if $cl > $#x;
+       $_= $x[$cl++];
+       s/\n$//; s/\s*$//;
+#      out("<!-- $level $doing $_ -->");
+       last if m/^\@\@\@end\w+\:\@\@\@$/;
+
+       if (m/^\@\@\@(if|ifnot):([0-9a-z_|]+)\@\@\@$/) {
+           $q=$1; $v=$2;
+           $do= 0;
+           if ($doing) {
+               map { $do=1 if getvar($_); } split(/\|/,$v);
+               $do= !$do if $q eq 'ifnot';
+#              out("<!-- $level $doing $do $q $v $_ -->");
+           }
+           process($doing && $do);
+       } elsif (m/^\@\@\@foreach\:(area|db)\@\@\@$/) {
+           if ($doing) {
+               $bcl= $cl;
+               for (&{"foreach_start_$1"};
+                    &{"foreach_cond_$1"};
+                    &{"foreach_incr_$1"}) {
+                   &{"foreach_setvars_$1"};
+                   process($doing);
+                   $cl= $bcl;
+               }
+           }
+           process(0);
+       } elsif (m/\S/) {
+           if ($doing) {
+               s/\@\@\@(\w+)\@\@\@/ getvar("$1") /ge;
+               out($_);
+           } else {
+               s/\@\@\@\w+\@\@\@//g;
+           }           
+           die "$cl:unknown $_\n" if m/\@\@\@/;
+       }
+    }
+    $level--;
+}
+
+sub getvar ($) {
+    my ($vn) = @_;
+    defined $$vn or die "$cl:undefined $vn\n$out";
+    return $$vn;
+}
+
+1;