X-Git-Url: https://git.treefish.org/fex.git/blobdiff_plain/e5c93609849bda051fff54b5d5265af5608c6c69..cdeb354c4dbb11b683f9f8c5db2861f3dc572c61:/cgi-bin/fup diff --git a/cgi-bin/fup b/cgi-bin/fup index 97624a0..2a799ac 100755 --- a/cgi-bin/fup +++ b/cgi-bin/fup @@ -10,6 +10,7 @@ BEGIN { ($ENV{PERLINIT}||'') =~ /(.+)/s and eval $1 } +use utf8; use Encode; use Fcntl qw':flock :seek :mode'; use IO::Handle; @@ -57,6 +58,7 @@ my @header; # HTTP entity header my $fileid; # file ID my $captive; my $muser; # main user fur sub or group user +my %specific; # upload specific KEEP and AUTODELETE parameters # load common code, local config: $FEXLIB/fex.ph require "$FEXLIB/fex.pp"; @@ -108,7 +110,8 @@ if ($addto) { my %to; foreach $to (@to) { $to{$to} = 1 } push @to,$addto unless $to{$addto}; - if ($submit and @to == 1) { $addto = '' } + # user has submitted with [select from your address book] ? + # if ($submit and @to == 1) { $addto = '' } } $to = join(',',@to); @@ -151,7 +154,7 @@ if ($from =~ /^anonymous@/ and $id = $rid = $anonymous = 'anonymous'; if ($to =~ /^anonymous/) { @to = ($to); - $autodelete{$to} = $autodelete = 'NO'; + $autodelete{$to} = $autodelete = $specific{'autodelete'}||'NO'; } $nomail = $anonymous; } @@ -199,10 +202,9 @@ if ($from and $id and not ($gkey or $skey or $public or $okey)) { # set akey link for HTTP sessions # (need original id for consistant non-moving akey) if (-d $akeydir and open $idf,'<',"$from/@" and my $id = getline($idf)) { - $akey = untaint(md5_hex("$from:$id")); - mksymlink("$akeydir/$akey","../$from"); - # show URL from fexsend - if ($from eq $to and $comment eq '*') { + # akey for webbrowser or fexsend special + if (not $sid or ($from eq $to and ($comment eq '*')) or $command) { + $akey = untaint(md5_hex("$from:$id")); mksymlink("$akeydir/$akey","../$from"); } } @@ -403,14 +405,14 @@ if (($from and $id and $rid eq $id or $gkey or $skey) and $command) { - int((time-mtime("$file/filename"))/$DS); if ($comment =~ /NOMAIL/ or (readlink "$to/\@NOTIFICATION"||'') =~ /^no/i) { - printf "%8s MB [%s d] %s/%s/%s\n", + printf "%8s MB (%2s d) %s/%s/%s\n", $size, $rkeep, $durl, $dkey, urlencode(basename($file)); } else { - printf "%8s MB [%s d] %s%s %s\n", + printf "%8s MB (%2s d) %s%s %s\n", $size, $rkeep, untaint("/fup?akey=$akey&dkey=$dkey&command=RENOTIFY"), @@ -469,9 +471,10 @@ if (($from and $id and $rid eq $id or $gkey or $skey) and $command) { } my $rkeep = untaint(readlink "$file/keep"||$keep_default) - int((time-mtime("$file/filename"))/$DS); - printf "%8s MB [%s d] %s%s\n", + printf "%8s MB (%2s d) %s %s%s\n", $size, $rkeep, + stat("$file/download")?'+':'-', untaint("/fup?akey=$akey&dkey=$dkey&command=FORWARD"), $filename, $comment?qq( "$comment"):''; @@ -528,7 +531,7 @@ if (($from and $id and $rid eq $id or $gkey or $skey) and $command) { $akey,$dkey; printf "[forward] ", $akey,$dkey; - printf "%8s MB (%s d) %s%s\n", + printf "%8s MB (%2s d) %s%s\n", $size,$rkeep,$url,$filename,$comment; } } @@ -630,11 +633,12 @@ if (($from and $id and $rid eq $id or $gkey or $skey) and $command) { foreach my $to (@group?@group:@to) { # my $options = sprintf "(autodelete=%s,keep=%s,locale=%s)", # readlink "$to/\@LOCALE"||$locale||$locale{$to}||$default_locale; - my $options = sprintf "(autodelete=%s,keep=%s,locale=%s,notification=%s)", + # my $options = sprintf "(autodelete=%s,keep=%s,locale=%s,notification=%s)", + my $options = sprintf "(autodelete=%s,keep=%s,locale=%s)", $autodelete{$to}||$autodelete, $keep{$to}||$keep_default, - readlink("$to/\@LOCALE")||$default_locale, - readlink("$to/\@NOTIFICATION")||'full'; + readlink("$to/\@LOCALE")||$locale{$to}||$default_locale; + # readlink("$to/\@NOTIFICATION")||'full'; nvt_print("X-Recipient: $to $options"); } nvt_print(''); @@ -796,7 +800,7 @@ unless ($file) { my @cookies; if ($logout and my $cookie = $ENV{HTTP_COOKIE}) { while ($cookie =~ s/(\w+key)=\w+//) { - push @cookies,"Set-Cookie: $1=; Max-Age=0; Discard"; + push @cookies,"Set-Cookie: $1=x; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; } } @@ -839,6 +843,8 @@ unless ($file) { { present_locales('/fup'); + # print "[$addto] [$submit] [@to]

\n"; + @ab = (""); # select menu from server address book @@ -848,6 +854,7 @@ unless ($file) { if (/(\S+)[=\s]+(\S+@[\w.-]+\S*)/) { $_ = "$1 <$2>"; s/,.*/,.../g; + s/:.*/>/; push @ab,""; } } @@ -876,7 +883,7 @@ unless ($file) { ' ' ' ' ' ' - ' ' + ' ' '
sender: $from
sender: $from
recipient(s):' '
' )); @@ -908,6 +915,11 @@ unless ($file) { foreach my $rd (@local_rdomains) { print "*\@$rd\n"; } + } elsif (/^\@LOCAL_USERS/) { + foreach (glob "*/@") { + s:/.::; + print "$_\n"; + } } else { print "$_\n"; } @@ -942,20 +954,20 @@ unless ($file) { print "Alternate Java client (for files > 2 GB or sending of more than one file)\n"; } print &logout; - if (-x "$FEXHOME/cgi-bin/login") { - print $info_login||$info_1; - } pq(qq( '


' '' - 'Warning: the recipient must not be a mailing list, because after' - 'download the file will be no more available!' + 'Warning: the recipient must not be a mailing list,' + 'because after download the file will be no more available!' '
' - 'Contact fexmaster' - 'if you want to fex to a mailing list,' + 'Contact fexmaster if you want to fex to a mailing list,' 'he can allow multiple downloads for specific addresses.' + '

' + 'Use a F*EX client if you want to send more than one file or resume an interrupted upload.' '' - )); + '

' + )); + print $info_1; exit; } @@ -1052,7 +1064,7 @@ unless ($file) { pq(qq( ' ' ' ' - ' ' + ' ' )); if ($anonymous) { pq(qq( @@ -1185,7 +1197,7 @@ unless ($file) { pq(qq( '' '
sender:$from
sender:$from
' '
sender:' @@ -1232,7 +1244,7 @@ unless ($file) { # } print "\n"; - print $info_1; + print $info_login||$info_1; if ($debug and $debug>1) { print "
\n
\n";
@@ -1409,11 +1421,12 @@ if ($nostore) {
     my $to = $_;
     $to =~ s/:\w+=.*//; # remove options from address
     my $file = "$to/$from/$fkey";
-    my $options = sprintf "(autodelete=%s,keep=%s,locale=%s,notification=%s)",
+    # my $options = sprintf "(autodelete=%s,keep=%s,locale=%s,notification=%s)",
+    my $options = sprintf "(autodelete=%s,keep=%s,locale=%s)",
       readlink("$file/autodelete")||$autodelete,
       readlink("$file/keep")||readlink("$to/\@KEEP")||$keep_default,
-      readlink("$to/\@LOCALE")||readlink("$file/locale")||$default_locale,
-      readlink("$to/\@NOTIFICATION")||'full';
+      readlink("$to/\@LOCALE")||readlink("$file/locale")||$default_locale;
+      # readlink("$to/\@NOTIFICATION")||'full';
     nvt_print("X-Recipient: $to $options");
     nvt_print("X-Location: $durl/$dkey{$to}/$fkey") unless $restricted;
   }
@@ -1502,7 +1515,13 @@ if ($okey) {
   print "&bwlimit=$bwlimit&autodelete=$autodelete&keep=$keep\">";
   print "send another file\n";
   if ($http_client !~ /fexsend/ and $http_client =~ /Linux/i) {
-    print qq'

Hi Linux-user, try fexsend! ☺

\n'; + print '

Hi Linux-user, try ', + '', + "fexsend! ☺

\n"; + } + if ($http_client !~ /fexit/ and $http_client =~ /Windows/i) { + print '

Hi Windows-user, try fexit! ', + "☺

\n"; } print &logout; } @@ -1538,11 +1557,21 @@ sub parse_request { # parse HTTP QUERY_STRING (parameter=value pairs) if ($qs) { foreach (split '&',$qs) { - if (s/^(\w+)=//) { - my $x = $1; + if (s/^(\w+)=(.*)//) { + my $p = uc($1); + my $v = $2; # decode URL-encoding - s/%([a-f0-9]{2})/chr(hex($1))/gie; - setparam($x,$_); + $v =~ s/%([a-f0-9]{2})/chr(hex($1))/gie; + setparam($p,$v); + if ($p eq 'AUTODELETE') { + $specific{'autodelete'} = $autodelete = $v; + } + if ($p eq 'KEEP' and /^\d+$/) { + $specific{'keep'} = $keep = $v; + } + # if ($p eq 'LOCALE') { + # $specific{'locale'} = $locale = $v; + # } } } } @@ -1662,27 +1691,43 @@ sub parse_request { # collect multiple addresses and check for aliases (not group) if (@to and "@to" !~ /^@[\w-]+$/ - and not ($gkey or $addto or $command =~ /^LIST(RECEIVED)?$/)) - { - + and not ($gkey or $addto or $command =~ /^LIST(RECEIVED)?$/)) { # read address book if ($from and open my $AB,'<',"$from/\@ADDRESS_BOOK") { - my ($alias,$address,$autodelete,$locale,$keep); + my ($alias,$addresses,$autodelete,$locale,$keep); while (<$AB>) { s/#.*//; $_ = lc $_; if (s/^\s*(\S+)[=\s]+(\S+)//) { - ($alias,$address) = ($1,$2); + ($alias,$addresses) = ($1,$2); + # alias specific options? $autodelete = $locale = $keep = ''; $autodelete = $1 if /autodelete=(\w+)/; $locale = $1 if /locale=(\w+)/; $keep = $1 if /keep=(\d+)/; - foreach my $address (split(",",$address)) { - $address .= '@'.$mdomain if $mdomain and $address !~ /@/; + foreach my $address (split(",",$addresses)) { + # alias address specific :options? + if ($address =~ s/(.+?):(.+)/$1/) { + my @options = split(':',$2); + $address = expand($address); + foreach (@options) { + if (/^keep=(\d+)$/i) { + $alias_keep{$alias}{$address} = $1 + } + if (/^autodelete=(yes|no|delay)$/i) { + $alias_autodelete{$alias}{$address} = $1 + } + if (/^locale=(\w+)$/i) { + $alias_locale{$alias}{$address} = $1 + } + } + } else { + $address = expand($address); + } push @{$ab{$alias}},$address; - $autodelete{$alias} = $autodelete; - $keep{$alias} = $keep; - $locale{$alias} = $locale; + $autodelete{$alias} = $autodelete if $autodelete; + $keep{$alias} = $keep if $keep; + $locale{$alias} = $locale if $locale; } } } @@ -1692,46 +1737,86 @@ sub parse_request { # look for recipient's options and eliminate dupes %to = (); foreach my $to (my @loop = @to) { - # address book alias? - if ($to !~ /@/ and $ab{$to}) { - foreach my $address (my @loop = @{$ab{$to}}) { - $address .= '@'.$mdomain if $mdomain and $address !~ /@/; + # address book alias? + if ($to !~ /@/ and ($ab{$to} or $to =~ /(.+?):(.+)/ and $ab{$1})) { + my $alias = $to; + my @options = (); + $alias =~ s/:(.*)// and @options = split(':',$1); + if (@options) { + # alias with :options + $alias =~ s/:.*//; + foreach my $address (my @loop = @{$ab{$alias}}) { + $to{$address} = $address; # ignore dupes + foreach (@options) { + $keep{$address} = $1 if /^keep=(\d+)$/i; + $autodelete{$address} = $1 if /^autodelete=(yes|no|delay)$/i; + $locale{$address} = $1 if /^locale=(\w+)$/i; + } + } + } + foreach my $address (my @loop = @{$ab{$alias}}) { $to{$address} = $address; # ignore dupes - if ($specific{'autodelete'}) { - $autodelete{$address} = $specific{'autodelete'}; - } elsif ($autodelete{$to}) { - $autodelete{$address} = $autodelete{$to}; - } else { - $autodelete{$address} = readlink "$address/\@AUTODELETE" - || $autodelete; + unless ($keep{$address}) { + $keep{$address} = $keep{$alias} if $keep{$alias}; + if ($specific{'keep'}) { + $keep{$address} = $specific{'keep'} + } elsif (my $keep = $alias_keep{$alias}{$address}) { + $keep{$address} = $keep; + } elsif ($keep{$alias}) { + $keep{$address} = $keep{$alias} + } } - if (my $locale = readlink "$address/\@LOCALE") { - $locale{$address} = $locale; - } elsif ($locale{$to}) { - $locale{$address} = $locale{$to}; - } else { - $locale{$address} = $locale ; + unless ($autodelete{$address}) { + if ($specific{'autodelete'}) { + $autodelete{$address} = $specific{'autodelete'}; + } elsif (my $autodelete = $alias_autodelete{$alias}{$address}) { + $autodelete{$address} = $keep; + } elsif ($autodelete{$alias}) { + $autodelete{$address} = $autodelete{$alias}; + } else { + $autodelete{$address} = readlink "$address/\@AUTODELETE" + || $autodelete; + } } unless ($locale{$address}) { - $locale{$address} = $default_locale || 'english'; + if (my $locale = readlink "$address/\@LOCALE") { + $locale{$address} = $locale; + } elsif ($locale{$alias}) { + $locale{$address} = $locale{$alias}; + } elsif ($locale = $alias_locale{$alias}{$address}) { + $locale{$address} = $locale; + } else { + $locale{$address} = $::locale ; + } + $locale{$address} ||= $default_locale || 'english'; } - if ($specific{'keep'}) { $keep{$address} = $specific{'keep'} } - elsif ($keep{$to}) { $keep{$address} = $keep{$to} } } } else { + # regular address, not an alias + if ($to =~ s/(.+?):(.+)/$1/) { + my @options = split(':',$2); + $to = expand($to); + foreach (@options) { + $keep{$to} = $1 if /^keep=(\d+)$/i; + $autodelete{$to} = $1 if /^autodelete=(yes|no|delay)$/i; + $locale{$to} = $1 if /^locale=(\w+)$/i; + } + } $to = expand($to); $to{$to} = $to; # ignore dupes unless ($autodelete{$to}) { - $autodelete{$to} = readlink "$to/\@AUTODELETE" || $autodelete; + $autodelete{$to} = untaint(readlink("$to/\@AUTODELETE") + ||$autodelete); + if ($specific{'autodelete'}) { + $autodelete{$to} = $specific{'autodelete'}; + } + } + unless ($keep{$to}) { + $keep{$to} = $keep_default; + $keep{$to} = $keep if $keep; + $keep{$to} = untaint(readlink "$to/\@KEEP") if -l "$to/\@KEEP"; + $keep{$to} = $specific{'keep'} if $specific{'keep'}; } - $autodelete{$to} = $specific{'autodelete'} if $specific{'autodelete'}; - $keep{$to} = $keep_default; - $keep{$to} = $keep if $keep; - $keep{$to} = untaint(readlink "$to/\@KEEP") if -l "$to/\@KEEP"; - $keep{$to} = $specific{'keep'} if $specific{'keep'}; - # recipient specific parameters - $keep{$to} = $1 if $to =~ /:keep=(\d+)/i; - $autodelete{$to} = $1 if $to =~ /:autodelete=(\w+)/i; } $autodelete{$to} = 'NO' if $to =~ /$amdl/; # mailing lists, etc if (-e "$to/\@CAPTIVE") { @@ -2056,7 +2141,7 @@ sub get_file { if ($from eq "@to") { # special "fex yourself" - mksymlink("$filed/autodelete",'NO'); + mksymlink("$filed/autodelete",$specific{'autodelete'}||'NO'); } else { $autodelete{$to} = $autodelete unless $autodelete{$to}; if ($autodelete{$to} =~ /^(DELAY|NO|\d+)$/i) { @@ -2320,6 +2405,9 @@ sub check_rr { $ar .= '|[^\@]+\@' . $rd; } $ar .= ')'; + } elsif (/^\@LOCAL_USERS/ and -s "$to/@") { + $allowed = 1; + last; } else { # allow wildcard *, but not regexps $ar = quotemeta $_; @@ -2375,11 +2463,14 @@ sub expand { sub forward { my $file = shift; my ($nfile,$to,$AB); - my ($filename); + my ($filename,$keep); my (%to); http_die("no file data for $file") unless -f "$file/data"; + $keep = $::keep||$keep_default; + if (my $mt = mtime("$file/data")) { $keep += int((time-$mt)/$DS) } + if (@to) { # check recipients restriction @@ -2413,11 +2504,11 @@ sub forward { } } + @to = keys %to; + http_header('200 OK'); print html_header($head); - @to = keys %to; - foreach my $to (my @loop = @to) { $to =~ s/:\w+=.*//; # remove options from address $nfile = $file; @@ -2444,15 +2535,15 @@ sub forward { close $comment; } if ($autodelete =~ /^(DELAY|NO|\d+)$/i) { - symlink($autodelete,"$nfile/autodelete"); - } - symlink($keep||$keep_default, "$nfile/keep"); - copy("$file/id", "$nfile/id"); - copy("$file/ip", "$nfile/ip"); - copy("$file/speed", "$nfile/speed"); - copy("$file/replyto", "$nfile/replyto"); - $filename = copy("$file/filename", "$nfile/filename"); - link "$file/data", "$nfile/data" + symlink $autodelete,"$nfile/autodelete"; + } + symlink $keep, "$nfile/keep"; + copy("$file/id", "$nfile/id"); + copy("$file/ip", "$nfile/ip"); + copy("$file/speed", "$nfile/speed"); + copy("$file/replyto", "$nfile/replyto"); + $filename = copy("$file/filename", "$nfile/filename"); + link "$file/data", "$nfile/data" or die http_die("cannot create $nfile/data - $!"); unless ($dkey = readlink("$nfile/dkey") and -l "$dkeydir/$dkey") { $dkey = randstring(8); @@ -2593,15 +2684,15 @@ sub setparam { $locale = $1; } elsif ($v eq 'REDIRECT' and $vv =~ /^([\w?=]+)$/) { $redirect = $1; - } elsif (($v eq 'KEY' or $v eq 'SKEY') and $vv =~ /^([\w:]+)$/) { + } elsif ($v eq 'SKEY' and $vv =~ /^([\w:]+)/) { $skey = $1; $restricted = $v; - } elsif ($v eq 'GKEY' and $vv =~ /^([\w:]+)$/) { + } elsif ($v eq 'GKEY' and $vv =~ /^([\w:]+)/) { $gkey = $1 unless $nomail; $restricted = $v; - } elsif ($v eq 'DKEY' and $vv =~ /^(\w+)$/) { + } elsif ($v eq 'DKEY' and $vv =~ /^(\w+)/) { $dkey = $1; - } elsif ($v eq 'AKEY' and $vv =~ /^(\w+)$/) { + } elsif ($v eq 'AKEY' and $vv =~ /^(\w+)/) { $akey = $1; } elsif ($v eq 'FROM' or $v eq 'USER') { $from = normalize_email($vv); @@ -2622,6 +2713,7 @@ sub setparam { } elsif ($v eq 'FEXYOURSELF') { $submit = $vv; @to = ($from); + $specific{'autodelete'} = $autodelete = 'no'; } elsif ($v eq 'TO') { # extract AUTODELETE and KEEP options if ($vv =~ s/[\s,]+AUTODELETE=(\w+)//i) { @@ -2637,9 +2729,15 @@ sub setparam { if ($from) { if ($to eq '.') { $to = $from; + unless ($specific{'autodelete'}) { + $specific{'autodelete'} = $autodelete = 'no'; + } } if ($to eq '//') { $to = $from; + unless ($specific{'autodelete'}) { + $specific{'autodelete'} = $autodelete = 'no'; + } $comment = '//'; } } @@ -2693,7 +2791,7 @@ sub setparam { $keep = $keep_max if $keep_max and $keep > $keep_max; $specific{'keep'} = $keep; } elsif ($v eq 'TIMEOUT' and $vv =~ /^(\d+)$/) { - $specific{'timeout'} = $timeout = $1; + $specific{'timeout'} = $timeout = $1; } } @@ -2799,6 +2897,11 @@ sub mail_forgotten { # lookup akey, skey and gkey (full and sub user and group) sub check_keys { + if (@to and "@to" ne '_') { + http_die("you cannot mix TO and SKEY URL parameters") if $skey; + http_die("you cannot mix TO and GKEY URL parameters") if $gkey; + } + # only one key can be valid $akey = $gkey = '' if $skey; $akey = $skey = '' if $gkey;