# Sebastian Zaiser <szcode@arcor.de> (upload status)
#
+BEGIN { ($ENV{PERLINIT}||'') =~ /(.+)/s and eval $1 }
+
use Encode;
use Fcntl qw':flock :seek :mode';
use IO::Handle;
use Digest::MD5 qw'md5_hex';
-use CGI::Carp qw'fatalsToBrowser';
use Cwd qw'abs_path';
-use constant DS => 60*60*24;
-use constant M => 1024*1024;
-
# add fex lib
-die "$0: no \$FEXLIB\n" unless $ENV{FEXLIB};
(our $FEXLIB) = $ENV{FEXLIB} =~ /(.+)/;
-die "$0: no $FEXLIB\n" unless -d $FEXLIB;
$| = 1;
# import from fex.pp
our ($FEXHOME);
-our ($spooldir,$durl,$tmpdir,$logdir,$docdir,$hostname,$admin,$fra);
-our ($keep_default,$recipient_quota,$sender_quota);
+our ($spooldir,$durl,$tmpdir,@logdir,$logdir,$docdir,$hostname,$admin,$fra);
+our ($keep_default,$recipient_quota,$sender_quota,$fex_yourself);
our ($sendmail,$mdomain,$fop_auth,$mail_auth,$faillog);
our ($dkeydir,$ukeydir,$akeydir,$skeydir,$gkeydir,$xkeydir);
+our ($MB,$DS);
+our $RB; # read POST bytes (total)
our $akey = '';
our $dkey = '';
our $skey = '';
my $data;
my $boundary;
-my $rb = 0; # read bytes, totally
my $rid = ''; # real ID
my @header; # HTTP entity header
my $fileid; # file ID
my $muser; # main user fur sub or group user
# load common code, local config: $FEXLIB/fex.ph
-require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n";
+require "$FEXLIB/fex.pp";
# load fup local config
our ($info_1,$info_2,$info_login);
$locale = $ENV{LOCALE} || 'english';
-foreach my $pl (
+foreach (
"/var/lib/fex/locale/$locale/lib/fup.pl",
"$FEXLIB/fup.pl",
) {
- if (-f $pl) {
- require $pl or die "$0: cannot load $FEXLIB/fup.pl - $!\n";
+ if (-f) {
+ require;
last;
}
}
chdir $spooldir or http_die("$spooldir - $!\n");
-my $log = "$logdir/fup.log";
+my $log = 'fup.log';
my $http_client = $ENV{HTTP_USER_AGENT} || '';
my $cl = $ENV{X_CONTENT_LENGTH} || $ENV{CONTENT_LENGTH} || 0;
$to = join(',',@to);
+if ($from eq $to and $fex_yourself =~ /^no|0$/i) {
+ http_die("fexing to yourself is not allowed");
+}
+
$uid = randstring(8) unless $uid; # upload ID
# user requests for forgotten ID
}
}
+# optional $auth_hook() in fup.pl
+if ($auth_hook and ($akey or $skey or $gkey) and $from and -d $from) {
+ &$auth_hook;
+}
+
# forward a copy of a file to another recipient
if ($akey and $dkey and $command eq 'FORWARD') {
my $file = untaint(readlink "$dkeydir/$dkey"||'');
next if $file =~ m:(.+?)/: and -l $1;
$size = -s "$file/data";
next unless $size;
- $size = int($size/M+0.5);
+ $size = int($size/$MB+0.5);
$filename = $comment = '';
my $rto = $file;
$rto =~ s:/.*::;
close $file;
}
my $rkeep = untaint(readlink "$file/keep"||$keep_default)
- - int((time-mtime("$file/filename"))/DS);
+ - int((time-mtime("$file/filename"))/$DS);
if ($comment =~ /NOMAIL/ or
(readlink "$to/\@NOTIFICATION"||'') =~ /^no/i) {
printf "%8s MB [%s d] %s/%s/%s\n",
next if $file =~ m:(.+?)/: and -l $1;
$size = -s "$file/data";
next unless $size;
- $size = int($size/M+0.5);
+ $size = int($size/$MB+0.5);
$filename = $comment = '';
my $rto = $file;
$rto =~ s:/.*::;
if ($dkey = readlink "$file/dkey") {
+ # die $file if -s "$file/data" and $file =~ /^$from/;
if ($rto ne $to) {
$to = $rto;
print "\nto $to :\n";
close $file;
}
my $rkeep = untaint(readlink "$file/keep"||$keep_default)
- - int((time-mtime("$file/filename"))/DS);
+ - int((time-mtime("$file/filename"))/$DS);
printf "%8s MB [%s d] <a href=\"%s\">%s</a>%s\n",
$size,
$rkeep,
$filename = $comment = '';
$size = -s "$file/data";
next unless $size;
- $size = int($size/M+0.5);
+ $size = int($size/$MB+0.5);
if ($dkey = readlink "$file/dkey") {
print "\nfrom $from :\n" unless $url;
$file =~ m:.*/(.+):;
close $file;
}
my $rkeep = untaint(readlink "$file/keep"||$keep_default)
- - int((time-mtime("$file/filename"))/DS);
+ - int((time-mtime("$file/filename"))/$DS);
printf "[<a href=\"/fup?akey=%s&dkey=%s&command=DELETE\">delete</a>] ",
$akey,$dkey;
printf "[<a href=\"/fup?akey=%s&dkey=%s&command=COPY\">forward</a>] ",
if ($command eq 'RECEIVEDLOG') {
http_die("illegal command \"$command\"") if $public or $anonymous;
- if (open my $fuplog,"$logdir/fup.log") {
+ if (open my $log,"$logdir/fup.log") {
http_header('200 OK');
- while (<$fuplog>) {
+ while (<$log>) {
next if /\sSTDFEX\s/;
if (/\d+$/) {
my @F = split;
if ($command eq 'SENDLOG') {
http_die("illegal command \"$command\"") if $public or $anonymous;
- if (open my $fuplog,"$logdir/fup.log") {
+ if (open my $log,"$logdir/fup.log") {
http_header('200 OK');
- while (<$fuplog>) {
+ while (<$log>) {
next if /\sSTDFEX\s/;
if (/(\S+\@\S+)/ and $1 eq $from) {
s/ \[[\d_]+\]//;
# check sender quota
($quota,$du) = check_sender_quota($muser||$from);
- if ($quota and $du+$cl/M > $quota) {
+ if ($quota and $du+$cl/$MB > $quota) {
http_die("you are overquota");
}
# check recipient quota
foreach my $to (@to) {
($quota,$du) = check_recipient_quota($to);
- if ($quota and $du+$cl/M > $quota) {
+ if ($quota and $du+$cl/$MB > $quota) {
http_die("$to cannot receive files: is overquota");
}
}
# (= has a F*EX ID)
if (not $addto and $fop_auth and $id and $id eq $rid and $from and @to) {
my ($to_reg,$idf,$subuser);
- foreach (@to) {
- my $to = $_;
+ foreach my $to (my @loop = @to) {
$to =~ s/:\w+=.*//; # remove options from address
$to_reg = 0;
# full user?
}
}
- # save default locale for this user
if (($akey or $skey or $gkey) and $from and -d $from) {
+ # save default locale for this user
if (not $locale and ($ENV{HTTP_COOKIE}||'') =~ /\blocale=(\w+)/) {
$locale = $1;
}
@ab = ("<option></option>");
# select menu from server address book
- if (open my $ab,'<',"$from/\@ADDRESS_BOOK") {
- while (<$ab>) {
+ if (open my $AB,'<',"$from/\@ADDRESS_BOOK") {
+ while (<$AB>) {
s/#.*//g;
if (/(\S+)[=\s]+(\S+@[\w.-]+\S*)/) {
$_ = "$1 <$2>";
push @ab,"<option>$_</option>";
}
}
- close $ab;
+ close $AB;
}
unless (@to) {
print "</pre><p>\n";
close $rr;
}
- pq(qq(
- ' <input type="submit" name="submit" value="check recipient(s) and continue">'
- ' or <input type="submit" name="fexyourself" value="fex yourself">'
- '</form>'
- '<p>'
- ));
+ print qq' <input type="submit" name="submit" value="check recipient(s) and continue">';
+ if ($fex_yourself =~ /^yes|1/i) {
+ print qq' or <input type="submit" name="fexyourself" value="fex yourself">'
+ }
+ print "\n</form>\n<p>\n";
if ($akey and -f "$from/\@" and not $captive ) {
pq(qq(
'<a href="/foc?akey=$akey">user config & operation control</a>'
if ($from and ($id or $okey)) {
$to = $group if $group;
present_locales($ENV{REQUEST_URI}) if $skey or $gkey or $okey;
+# " '$ENV{PROTO}://$ENV{HTTP_HOST}/$cgi?showstatus=$uid',"
pq(qq(
'<script type="text/javascript">'
' function showstatus() {'
' var file = document.forms["upload"].elements["file"].value;'
' if (file != "") {'
' window.open('
- " '$ENV{PROTO}://$ENV{HTTP_HOST}/$cgi?showstatus=$uid',"
+ " '/$cgi?showstatus=$uid',"
" 'fup_status',"
" 'width=700,height=500'"
' );'
? "<tr><td>sender quota (used):<td>$quota ($du) MB</tr>"
: '';
- $bwl = qq'<td><input type="text" name="bwlimit" size="8" value="$bwlimit"> kB/s';
+ $bwl = qq'<input type="text" name="bwlimit" size="8" value="$bwlimit"> kB/s';
if (@throttle) {
foreach (@throttle) {
if (/\[?(.+?)\]?:(\d+)$/) {
# throttle ip address?
if ($throttle =~ /^[\w:.-]+$/) {
if (ipin($ra,$throttle)) {
- $bwl = qq'<td><input type="hidden" name="bwlimit" value="$limit"> $limit kB/s';
+ $bwl = qq'<input type="hidden" name="bwlimit" value="$limit"> $limit kB/s';
last;
}
}
$throttle =~ quotemeta $throttle;
$throttle =~ s/\*/.*/g;
if ($from =~ /^$throttle$/i) {
- $bwl = qq'<td><input type="hidden" name="bwlimit" value="$limit"> $limit kB/s';
+ $bwl = qq'<input type="hidden" name="bwlimit" value="$limit"> $limit kB/s';
last;
}
}
elsif (/delay/i) { $adt = 'delete file after download with delay' }
elsif (/^\d+$/) { $adt = "delete file $autodelete days after download" }
}
+ $adt .= qq'<input type="hidden" name="autodelete" value="$autodelete">';
my $ctr = my $ktr = '';
if ($nomail) {
- $ctr = qq'<td><input type="hidden" name="comment" value="$comment">'
- .qq'<em>no notification e-mail will be send</em>';
- $ktr = qq'<input type="text" name="keep" size="2" value="$keep"> days</tr>';
- $ktr = qq'$keep days<input type="hidden" name="keep" value="$keep"></tr>';
+ $ctr = qq'<em>no notification e-mail will be send</em>';
} else {
- $ctr = qq'<td><input type="text" name="comment" size="80" value="$comment">';
- $ktr = qq'$keep days<input type="hidden" name="keep" value="$keep"></tr>';
+ $ctr = qq'<input type="text" name="comment" size="80" value="$comment">';
}
if ($captive) {
- $ktr = qq'$keep days<input type="hidden" name="keep" value="$keep"></tr>';
+ $ktr = qq'$keep days<input type="hidden" name="keep" value="$keep">';
+ } else {
+ $ktr = qq'$keep days<input type="hidden" name="keep" value="$keep">';
}
-
pq(qq(
- ' <tr title="$adt"><td>autodelete:<td>$adt</tr>'
- ' <input type="hidden" name="autodelete" value="$autodelete">'
- ' <tr title="keep file max $keep days, then delete it"><td>keep:<td>'
- ' $ktr'
+ ' <tr><td>autodelete:'
+ ' <td>$adt'
+ ' </tr>'
+ ' <tr title="keep file max $keep days, then delete it"><td>keep:'
+ ' <td>$ktr'
+ ' </tr>'
' $quota'
' <tr title="optional, full speed if empty"><td>bandwith limit:'
- ' $bwl'
+ ' <td>$bwl'
' </tr>'
' <tr title="optional, will be included in notification e-mail"><td>comment:'
- ' $ctr'
+ ' <td>$ctr'
' </tr>'
- ' <tr title="If you want to send more than one file, then put them in a zip or tar archive">'
- ' <td>file:'
- ' <td><input type="file" name="file" size="80" value="$file" onchange="reportsize();">'
+ ' <tr title="If you want to send more than one file, then put them in a zip or tar archive"><td>file:'
+ ' <td><input type="file" name="file" size="80" value="$file" onchange="reportsize();">'
' </tr>'
' <tr><td>file size:<td id="filesize"></td></tr>'
' </table>'
}
# additional last check
-foreach $to (@to) {
- checkaddress($to) or
- http_die("<code>$to</code> is not a valid e-mail address");
+unless (@group or $gkey or $skey or $public or $okey) {
+ foreach $to (@to) {
+ checkaddress($to) or
+ http_die("<code>$to</code> is not a valid e-mail address");
+ }
}
+
$to = join(',',@to);
# file overwriting for anonymous is only possible if his client has the
rename $upload,$save or http_die("cannot rename $upload to $save - $!\n");
# log dkey
- my $dlog = "$logdir/dkey.log";
- if (open $dlog,'>>',$dlog) {
- flock $dlog,LOCK_EX;
- seek $dlog,0,SEEK_END;
- printf {$dlog} "%s %s %s %s %s\n",
- isodate(time),$dkey{$to},$from,$to,$fkey;
- close $dlog;
- }
+ my $msg = sprintf "%s %s %s %s %s\n",
+ isodate(time),$dkey{$to},$from,$to,$fkey;
+ writelog('dkey.log',$msg);
# send notification e-mails if necessary
if (not $nomail and (readlink "$to/\@NOTIFICATION"||'') !~ /^no/i
print html_header($head);
if ($nostore) {
- printf "%s (%s MB) received\n",$file,$ndata/M;
+ printf "%s (%s MB) received\n",$file,int($ndata/$MB);
} elsif (not $restricted and ($anonymous or $from eq $to)) {
my $size = $ndata<2*1024 ? sprintf "%s B",$ndata:
- $ndata<2*M ? sprintf "%s kB",int($ndata/1024):
- sprintf "%s MB",int($ndata/M);
+ $ndata<2*$MB ? sprintf "%s kB",int($ndata/1024):
+ sprintf "%s MB",int($ndata/$MB);
pq(qq(
'<code>$file</code> ($size) received and saved<p>'
'Download URL for copy & paste:'
if (not $boring and not $seek) {
print "Ehh... $ndata <b>BYTES</b>?! You are kidding?<p>\n";
}
- } elsif ($ndata<2*M) {
+ } elsif ($ndata<2*$MB) {
$ndata = int($ndata/1024);
print "<code>$file</code> ($ndata kB) received and saved<p>\n";
if ($ndata<1024 and not ($boring or $seek)) {
"ever heard of MIME e-mail? ☺<p>\n";
}
} else {
- $ndata = int($ndata/M);
+ $ndata = int($ndata/$MB);
print "<code>$file</code> ($ndata MB) received and saved<p>\n";
}
print "<ul>\n";
}
if ($from) {
- $from .= '@'.$mdomain if $mdomain and $from !~ /@/;
- if ($from ne 'anonymous' and not checkaddress($from)) {
- http_die("<code>$from</code> is not a valid e-mail address");
+ unless ($skey or $gkey or $okey) {
+ $from .= '@'.$mdomain if $mdomain and $from !~ /@/;
+ if ($from ne 'anonymous' and not checkaddress($from)) {
+ http_die("<code>$from</code> is not a valid e-mail address");
+ }
}
$from = untaint($from);
}
# look for recipient's options and eliminate dupes
%to = ();
- foreach (@to) {
- my $to = $_;
+ foreach my $to (my @loop = @to) {
# address book alias?
- if ($ab{$to}) {
- foreach (@{$ab{$to}}) {
- my $address = $_;
+ if ($to !~ /@/ and $ab{$to}) {
+ foreach my $address (my @loop = @{$ab{$to}}) {
$address .= '@'.$mdomain if $mdomain and $address !~ /@/;
$to{$address} = $address; # ignore dupes
if ($specific{'autodelete'}) {
$autodelete{$address} = readlink "$address/\@AUTODELETE"
|| $autodelete;
}
- if ($_ = readlink "$address/\@LOCALE") {
- $locale{$address} = $_;
+ if (my $locale = readlink "$address/\@LOCALE") {
+ $locale{$address} = $locale;
} elsif ($locale{$to}) {
$locale{$address} = $locale{$to};
} else {
http_die("You cannot send to more than one group") if @to > 1;
http_die("Group <code>$to</code> does not exist") unless -f "$from/\@GROUP/$1";
} else {
- $to .= '@'.$mdomain if $mdomain and $to !~ /@/;
- if (checkaddress($to)) {
+ if ($skey or $gkey or $okey or checkaddress($to)) {
+ $to .= '@'.$mdomain if $mdomain and $to !~ /@/;
$to{$to} = untaint($to);
} else {
http_die("<code>$to</code> is not a valid e-mail address");
"$filed/speed",
"$filed/replyto",
"$filed/useragent",
+ "$filed/uurl",
"$filed/comment",
"$filed/notify";
unlink "$filed/size" unless $seek;
close $fh;
if ($::filesize > 0 or $cl > 0) {
if ($::filesize > 0) { $filesize = $fpsize || $::filesize }
- else { $filesize = $cl-$rb-$ebl+$seek }
+ else { $filesize = $cl-$RB-$ebl+$seek }
# new file
unless ($seek) {
if ($::filesize > 0) {
}
}
- $autodelete{$to} = $autodelete unless $autodelete{$to};
- if ($autodelete{$to} =~ /^(DELAY|NO|\d+)$/i) {
- mksymlink("$filed/autodelete",$autodelete{$to});
+ if ($from eq "@to") {
+ # special "fex yourself"
+ mksymlink("$filed/autodelete",'NO');
+ } else {
+ $autodelete{$to} = $autodelete unless $autodelete{$to};
+ if ($autodelete{$to} =~ /^(DELAY|NO|\d+)$/i) {
+ mksymlink("$filed/autodelete",$autodelete{$to});
+ }
}
if (my $keep = $keep{$to} || $::keep) {
}
mksymlink("$filed/id",$fileid) if $fileid;
mksymlink("$filed/ip",$ra) if $ra;
+ if (my $uurl = $ENV{REQUEST_URL}) {
+ mksymlink("$filed/uurl",$uurl);
+ }
if ($http_client and open $http_client,'>',"$filed/useragent") {
print {$http_client} $http_client,"\n";
close $http_client;
if ($cl == -1) {
alarm($timeout*2);
# read until EOF, including MIME end boundary
+ # note: cannot use sysread because of previous buffered read!
while ($n = read(STDIN,$_,$bs)) {
- $rb += $n;
+ $RB += $n;
$fb += $n;
syswrite $upload,$_ unless $nostore;
alarm($timeout*2);
if ($fpsize) {
debuglog(sprintf("still awaiting %d+%d = %d bytes",
$fpsize,$ebl,$fpsize+$ebl));
- $cl = $rb+$fpsize+$ebl; # recalculate CONTENT_LENGTH
+ $cl = $RB+$fpsize+$ebl; # recalculate CONTENT_LENGTH
} else {
if ($::filesize) {
- $cl = $rb+$::filesize+$ebl; # recalculate CONTENT_LENGTH
+ $cl = $RB+$::filesize+$ebl; # recalculate CONTENT_LENGTH
}
debuglog(sprintf("still awaiting %d-%d = %d bytes",
- $cl,$rb,$cl-$rb));
+ $cl,$RB,$cl-$RB));
}
# read until end boundary, not EOF
- while ($rb < $cl-$ebl) {
- $b = $cl-$ebl-$rb;
+ while ($RB < $cl-$ebl) {
+ $b = $cl-$ebl-$RB;
$b = $bs if $b > $bs;
# max wait for 1 kB/s, but at least 10 s
# $timeout = $b/1024;
# $timeout = 10 if $timeout < 10;
alarm($timeout);
if ($n = read(STDIN,$_,$b)) {
- $rb += $n;
+ $RB += $n;
$fb += $n;
# syswrite is much faster than print
syswrite $upload,$_ unless $nostore;
if ($bwlimit) {
alarm(0);
$tt = (time-$t0) || 1;
- while ($rb/$tt/1024 > $bwlimit) {
+ while ($RB/$tt/1024 > $bwlimit) {
sleep 1;
$tt = time-$t0;
}
http_die("found no MIME end boundary in upload ($_)");
}
}
- $rb += $ebl;
+ $RB += $ebl;
$ndata = untaint($fb);
}
# truncate $upload,$ndata+$uss if -s $upload > $ndata+$uss;
# incomplete?
- if ($cl != $rb) {
+ if ($cl != $RB) {
fuplog($to,$fkey,$ndata,'(aborted)');
if ($fpsize) {
- http_die("read $rb bytes, but Content-Length announces $fpsize bytes");
+ http_die("read $RB bytes, but Content-Length announces $fpsize bytes");
} else {
- http_die("read $rb bytes, but CONTENT_LENGTH announces $cl bytes");
+ http_die("read $RB bytes, but CONTENT_LENGTH announces $cl bytes");
}
}
my @users = @_;
my @ua;
- foreach (@users) {
- my $u = $_;
+ foreach my $u (my @loop = @users) {
if ($u =~ /^anonymous(_\d+)?$/) {
$u = "$u\@$hostname";
}
}
# collect addresses
- foreach (@to) {
- my $to = $_;
+ foreach my $to (my @loop = @to) {
if ($ab{$to}) {
foreach my $address (@{$ab{$to}}) {
$to{$address} = $address;
@to = keys %to;
- foreach (@to) {
- my $to = $_;
+ foreach my $to (my @loop = @to) {
$to =~ s/:\w+=.*//; # remove options from address
$nfile = $file;
$nfile =~ s:.*?/:$to/:;
}
-# read one line from STDIN (net socket) and assign it to $_
-# returns number of read bytes
-sub nvt_read {
- my $len = 0;
-
- if (defined ($_ = <STDIN>)) {
- debuglog($_);
- $len = length;
- $rb += $len;
- s/\r?\n//;
- }
- return $len;
-}
-
-
-# read forward to given pattern
-sub nvt_skip_to {
- my $pattern = shift;
-
- while (&nvt_read) { return if /$pattern/ }
-}
-
-
# set parameter variables
sub setparam {
my ($v,$vv) = @_;
$from = normalize_email($vv);
$from = untaint(expand($from));
checkchars('from address',$from);
- checkaddress($from) or http_die("FROM $from is no legal e-mail address");
+ # maybe FROM=SUBUSER !
+ # checkaddress($from) or http_die("FROM $from is no legal e-mail address");
} elsif ($v eq 'REPLYTO') {
$replyto = normalize_email($vv);
checkchars('replyto address',$replyto);
while (<$df>) {
if (/^.+?\s+\d+\s+\d+\s+(\d+)/ and $req/1024 > $1) {
$free = int($1/1024);
- $uprq = int($req/M);
+ $uprq = int($req/$MB);
if (not $nomail and open P,"|$sendmail -t") {
pq(P,qq(
'From: $admin'
$msg =~ s/\n/ /g;
$msg =~ s/\s+$//;
-
- if (open $log,'>>',$log) {
- flock $log,LOCK_EX;
- seek $log,0,SEEK_END;
- printf {$log} "%s [%s_%s] %s (%s) %s\n",
- isodate(time),$$,$ENV{REQUESTCOUNT},$from,$fra,$msg;
- close $log;
- }
+ $msg = sprintf "%s [%s_%s] %s (%s) %s\n",
+ isodate(time),$$,$ENV{REQUESTCOUNT},$from,$fra,$msg;
+ writelog($log,$msg);
}
$msg = @_ ? "@_" : '???';
$msg =~ s/\n/ /g;
$msg =~ s/\s+$//;
+ $msg = sprintf "%s %s (%s) %s %s caught SIGNAL %s %s\n",
+ isodate(time),
+ $from||'-',
+ $fra||'-',
+ $to||'-',
+ encode_Q($file||'-'),
+ $msg,
+ $RB?"(after $RB bytes)":"";
+
+ writelog($log,$msg);
- if (open $log,'>>',$log) {
- printf {$log}
- "%s %s (%s) %s %s caught SIGNAL %s %s\n",
- isodate(time),
- $from||'-',
- $fra||'-',
- $to||'-',
- encode_Q($file||'-'),
- $msg,
- $rb?"(after $rb bytes)":"";
- close $log;
- }
if ($sig eq 'DIE') {
shift;
die "$msg\n";
}
-sub mtime {
- my @s = lstat shift;
- return @s ? $s[9] : undef;
-}
-
-
sub present_locales {
my $url = shift;
my @locales = @::locales; # from fex.ph
if (@locales > 1) {
print "<h3>";
- foreach (@locales) {
- $locale = $_;
+ foreach my $locale (my @loop = @locales) {
if (-x "$locale/cgi-bin/fup") {
$lang = "$locale/lang.html";
$locale =~ s:.*/::;