fex-20160919/0000755000174700017470000000000012770010176010714 5ustar fexfexfex-20160919/lib/0000751000174700017470000000000012770010176011456 5ustar fexfexfex-20160919/lib/fex.ph0000644000174700017470000001467312770010174012606 0ustar fexfex# -*- perl -*- # ## your F*EX server host name (with domain) $hostname = 'MYHOSTNAME.MYDOMAIN'; ## admin email address used in notification emails ## to change it, you MUST call: fac -/ admin-email-address auth-id $admin = 'fex@'.$hostname; ## server admin email address shown on web page $ENV{SERVER_ADMIN} = $admin; ## restrict web administration to ip range(s) @admin_hosts = qw(127.0.0.1 10.0.0.0-10.10.255.255); ## Bcc address for notification emails, must not be empty $bcc = 'fex'; ## send notifications about new F*EX releases (bugfixes!) $notify_newrelease = $admin; ## optional: download-URLs sent in notification emails # @durl = qw( # http://MYFEXSERVER/fop # https://MYFEXSERVER/fop # http://MYPROXY/fex/fop # ); ## On AUTO mode the fexserver sends notification emails automatically. ## On MANUAL mode the user must notify the recipients manually. # $mailmode = 'MANUAL'; $mailmode = 'AUTO'; ## optional: your mail domain ## if set it will be used as domain for every user without domain ## local_user ==> local_user@$mdomain ## if not set, addresses without domain produce an error # $mdomain = 'MY.MAIL.DOMAIN'; # $admin = 'fexmaster@'.$mdomain; ## optional: static address (instead of F*EX user) in notification email From ## BEWARE: if set, mail error bounces will not go to the real sender, but ## to this address! # $sender_from = $admin; ## optional HTML header extra link and logo # @H1_extra = qw(http://www.MY.ORG http://www.MY.ORG/logo.gif); ## disclaimer to be appended to every notification email # $disclaimer = 'powered by camelcraft!'; ## optional: suppress funny messages # $boring = 1; ## optional: suppress warning messages about incompatible web browsers # $nowarning = 'YES'; # locales to present (must be installed!) # if empty, present all installed locales # @locales = qw(english swabian); ## default locale: which languange is used in first place # $default_locale = 'swabian'; ## where to store the files and logs, must be writable for user fex! # $spooldir = "$ENV{HOME}/spool"; # $logdir = $spooldir; ## default quota in MB for recipient; 0 means "no quota" $recipient_quota = 0; ## default quota in MB for sender; 0 means "no quota" $sender_quota = 0; ## expiration: keep files that number of days (default) $keep = 5; ## expiration: keep files that number of days (maximum) $keep_max = 99; ## autodelete: delete files after download (automatically) ## YES ==> immediatelly (1 minute grace time) ## DELAY ==> after download at next fex_cleanup cronjob run ## 2 ==> 2 days after download (can be any number!) ## NO ==> keep until expiration date (see $keep) $autodelete = 'YES'; ## purge: purge files after that number of days after their deletion ## (purge deletes file meta-information) $purge = '3*$keep'; ## if the file has been already downloaded then subsequentials ## downloads are only allowed from the same client (uses cookies) ## to prevent unwanted file sharing $limited_download = 'YES'; ## allow RECIPIENT = SENDER ## in this case subsequentials downloads from any ip are possible until ## regular file expiration (KEEP); exception for $limited_download $fex_yourself = 'YES'; ## allow overwriting of files $overwrite = 'YES'; ## allow user requests for forgotten auth-IDs (then send by email) $mail_authid = 'YES'; ## optional: from which hosts and for which mail domains users may ## register themselves as full users (must set both!) # @local_hosts = qw(127.0.0.1 ::1 10.10.100.0-10.10.200.255 129.69.1.129); # @local_domains = qw(uni-stuttgart.de flupp.org); # @local_domains = qw(uni-stuttgart.de *.uni-stuttgart.de); ## optional: external users may register themselves as restricted users ## for local receiving domains and hosts (must set both!) # @local_rdomains = qw(flupp.org *.flupp.org); # @local_rhosts = qw(10.0.0.0-10.0.255.255 129.69.1.129); ## optional: allow restricted user registration only by certain domains # @registration_domains = qw(belwue.de ietf.org); ## optional: allow restricted user registration only by certain hosts # @registration_hosts = qw(129.69.0.0-129.69.255.255 176.9.84.26); ## optional: for certain remote domains do not use sender address in ## notfication email From, because their MTA will probably ## reject it if From and To contain their domain name. ## Instead use $admin for From. See also $sender_from # @remote_domains = qw(flupp.org); ## optional: allow public upload via http://$hostname/pup for # @public_recipients = qw(fexmaster@rus.uni-stuttgart.de); ## optional: allow anonymous upload without authentication for these IP ranges # @anonymous_upload = qw(127.0.0.1 ::1 10.10.100.0-10.10.200.255 129.69.1.129); ## optional: mailing list addresses (allows multiple downloads) # @mailing_lists = qw(admin@my.domain *@listserv*); ## optional: forbidden addresses # @forbidden_recipients = qw(nobody@* postmaster@else.where); ## optional: forbidden ip addresses for CGIs # @forbidden_hosts = qw(64.124.0.0-64.125.255.255); # forbidden user agents (sucking "download manager", etc) @forbidden_user_agents = qw( FDM Download.Master Java/[\d\.]+ ); ## optional: restrict upload to these IP ranges # @upload_hosts = qw(127.0.0.1 ::1 10.10.100.0-10.10.200.255 129.69.1.129); ## optional: restrict download to these address ranges # @download_hosts = qw(127.0.0.1 10.10.100.0-10.10.200.255 129.69.1.129); ## optional: throttle bandwith for certain addresses (in kB/s) ## 0 means : full speed ## first match wins # @throttle = qw( # framstag@*:0 microsoft.com:100 # 127.0.0.1:0 202.0.0.0-211.255.255.255:1024 # [::1]:0 [fe00::0-fe00::ffff]:0 # ); ## optional: expire user accounts after x days of inactivity ## delete=wipe out, notify=send mail to fex admin # $account_expire = "100:delete"; # $account_expire = "365:notify"; ## optional: allowed directories for file linking (see fexsend) # @file_link_dirs = qw(/sw /nfs/home/exampleuser); ## optional: allow additional directories with static documents ## $docdir (/home/fex/htdocs) is always allowed implicitly # @doc_dirs = qw(/sw /nfs/home/exampleuser/htdocs); ## optional: text file with your conditions of using ## will be append to registrations request replies # $usage_conditions = "$docdir/usage_conditions.txt"; ## optional: redirect URIs ## URLs with leading ! are active http redirects # %redirect = ( # '/fstools/' => '!http://fex.belwue.de/fstools/', # '/usecases/' => 'http://fex.belwue.de/usecases/', # ); fex-20160919/lib/fup.pl0000644000174700017470000000264412770010174012615 0ustar fexfex# config for F*EX CGI fup $info_1 = $info_login = <

F*EX (File EXchange) is a service to send big (large, huge, giant, ...) files.

The sender (you) uploads the file to the F*EX server and the recipient automatically gets a notification e-mail with a download-URL.
After download or after $keep_default days the server deletes the file. F*EX is not an archive!

See also questions & answers and use cases.


$ENV{SERVER_ADMIN}
EOD $info_2 = <

After submission you will see an upload progress bar (if you have javascript enabled and popups allowed).

NOTE: Many web browsers cannot upload files > 2 GB!
If your file is larger you have to use a special F*EX client or Firefox or Google Chrome which have no size limit.
You also need a F*EX client for resuming interrupted uploads. Your web browser cannot do this.

If you want to send more than one file, then put them in a zip or tar archive, e.g. with 7-Zip.

See also the FAQ and use cases.


$ENV{SERVER_ADMIN}
EOD fex-20160919/lib/fex.pp0000600000174700017470000011240312770010174012574 0ustar fexfex# -*- perl -*- use 5.008; use utf8; use Fcntl qw':flock :seek :mode'; use IO::Handle; use IPC::Open3; use Encode; use Digest::MD5 qw'md5_hex'; use File::Basename; use Sys::Hostname; use Symbol qw'gensym'; # set and untaint ENV if not in CLI (fexsrv provides clean ENV) unless (-t) { foreach my $v (keys %ENV) { ($ENV{$v}) = ($ENV{$v} =~ /(.*)/s) if defined $ENV{$v}; } $ENV{PATH} = '/usr/local/bin:/bin:/usr/bin'; $ENV{IFS} = " \t\n"; $ENV{BASH_ENV} = ''; } unless ($FEXLIB = $ENV{FEXLIB} and -d $FEXLIB) { die "$0: found no FEXLIB - fexsrv needs full path\n" } $FEXLIB =~ s:/+:/:g; $FEXLIB =~ s:/$::; # $FEXHOME is top-level directory of F*EX installation or vhost # $ENV{HOME} is login-directory of user fex # in default-installation both are equal, but they may differ $FEXHOME = $ENV{FEXHOME} or $ENV{FEXHOME} = $FEXHOME = dirname($FEXLIB); umask 077; # defaults $hostname = gethostname(); $tmpdir = $ENV{TMPDIR} || '/var/tmp'; $spooldir = $FEXHOME.'/spool'; $docdir = $FEXHOME.'/htdocs'; $logdir = $spooldir; $autodelete = 'YES'; $overwrite = 'YES'; $limited_download = 'YES'; # multiple downloads only from same client $fex_yourself = 'YES'; # allow SENDER = RECIPIENT $keep = 5; # days $recipient_quota = 0; # MB $sender_quota = 0; # MB $timeout = 30; # seconds $bs = 2**16; # I/O blocksize $DS = 60*60*24; # seconds in a day $MB = 1024*1024; # binary Mega $use_cookies = 1; $sendmail = '/usr/lib/sendmail'; $sendmail = '/usr/sbin/sendmail' unless -x $sendmail; $mailmode = 'auto'; $bcc = 'fex'; $default_locale = ''; $fop_auth = 0; $mail_authid = 'yes'; $force_https = 0; $debug = 0; @forbidden_user_agents = ('FDM'); # https://securityheaders.io/ # https://scotthelme.co.uk/hardening-your-http-response-headers/ # http://content-security-policy.com/ @extra_header = ( # "Content-Security-Policy: sandbox allow-forms allow-scripts", "Content-Security-Policy: script-src 'self' 'unsafe-inline'", "X-Frame-Options: SAMEORIGIN", "X-XSS-Protection: 1; mode=block", "X-Content-Type-Options: nosniff", ); $FHS = -f '/etc/fex/fex.ph' and -d '/usr/share/fex/lib'; # Debian FHS if ($FHS) { $ENV{FEXHOME} = $FEXHOME = '/usr/share/fex'; $spooldir = '/var/spool/fex'; $logdir = '/var/log/fex'; $docdir = '/var/lib/fex/htdocs'; $notify_newrelease = ''; } # allowed download managers (HTTP User-Agent) $adlm = '^(Axel|fex)'; # local config require "$FEXLIB/fex.ph" or die "$0: cannot load $FEXLIB/fex.ph - $!"; $fop_auth = 0 if $fop_auth =~ /no/i; $mail_authid = 0 if $mail_authid =~ /no/i; $force_https = 0 if $force_https =~ /no/i; $debug = 0 if $debug =~ /no/i; @logdir = ($logdir) unless @logdir; $logdir = $logdir[0]; # allowed multi download recipients: from any ip, any times if (@mailing_lists) { $amdl = '^('.join('|',map { quotewild($_) } @mailing_lists).')$'; } else { $amdl = '^-$'; } # check for name based virtual host $vhost = vhost($ENV{'HTTP_HOST'}); $RB = 0; # read POST bytes push @doc_dirs,$docdir; foreach my $ld (glob "$FEXHOME/locale/*/htdocs") { push @doc_dirs,$ld; } $nomail = ($mailmode =~ /^MANUAL|nomail$/i); if (not $nomail and not -x $sendmail) { http_die("found no sendmail"); } http_die("cannot determine the server hostname") unless $hostname; $ENV{PROTO} = 'http' unless $ENV{PROTO}; $keep = $keep_default ||= $keep || 5; $purge ||= 3*$keep; $fra = $ENV{REMOTE_ADDR} || ''; $sid = $ENV{SID} || ''; $dkeydir = "$spooldir/.dkeys"; # download keys $ukeydir = "$spooldir/.ukeys"; # upload keys $akeydir = "$spooldir/.akeys"; # authentification keys $skeydir = "$spooldir/.skeys"; # subuser authentification keys $gkeydir = "$spooldir/.gkeys"; # group authentification keys $xkeydir = "$spooldir/.xkeys"; # extra download keys $lockdir = "$spooldir/.locks"; # download lock files if (my $ra = $ENV{REMOTE_ADDR} and $max_fail) { mkdirp("$spooldir/.fail"); $faillog = "$spooldir/.fail/$ra"; } unless ($admin) { $admin = $ENV{SERVER_ADMIN} ? $ENV{SERVER_ADMIN} : 'fex@'.$hostname; } # $ENV{SERVER_ADMIN} may be set empty in fex.ph! $ENV{SERVER_ADMIN} = $admin unless defined $ENV{SERVER_ADMIN}; $mdomain ||= ''; if ($use_cookies) { if (my $cookie = $ENV{HTTP_COOKIE}) { if ($cookie =~ /\bakey=(\w+)/) { $akey = $1 } # elsif ($cookie =~ /\bskey=(\w+)/) { $skey = $1 } } } if (@locales) { if ($default_locale and not grep /^$default_locale$/,@locales) { push @locales,$default_locale; } if (@locales == 1) { $default_locale = $locales[0]; } } $default_locale ||= 'english'; # $durl is first default fop download URL # @durl is optional mandatory fop download URL list (from fex.ph) unless ($durl) { my $host = ''; my $port = 80; my $xinetd = '/etc/xinetd.d/fex'; if (@durl) { $durl = $durl[0]; } elsif ($ENV{HTTP_HOST} and $ENV{PROTO}) { ($host,$port) = split(':',$ENV{HTTP_HOST}||''); $host = $hostname; unless ($port) { $port = 80; if (open $xinetd,$xinetd) { while (<$xinetd>) { if (/^\s*port\s*=\s*(\d+)/) { $port = $1; last; } } close $xinetd; } } # use same protocal as uploader for download if ($ENV{PROTO} eq 'https' and $port == 443 or $port == 80) { $durl = "$ENV{PROTO}://$host/fop"; } else { $durl = "$ENV{PROTO}://$host:$port/fop"; } } else { if (open $xinetd,$xinetd) { while (<$xinetd>) { if (/^\s*port\s*=\s*(\d+)/) { $port = $1; last; } } close $xinetd; } if ($port == 80) { $durl = "http://$hostname/fop"; } else { $durl = "http://$hostname:$port/fop"; } } } @durl = ($durl) unless @durl; sub reexec { exec($FEXHOME.'/bin/fexsrv') if $ENV{KEEP_ALIVE}; exit; } sub jsredirect { $url = shift; $cont = shift || 'request accepted: continue'; http_header('200 ok'); print html_header($head||$ENV{SERVER_NAME}); pq(qq( '' '' '' )); &reexec; } sub debug { print header(),"
\n";
  print "file = $file\n";
  foreach $v (keys %ENV) {
    print $v,' = "',$ENV{$v},"\"\n";
  }
  print "

\n"; } sub nvt_print { foreach (@_) { syswrite STDOUT,"$_\r\n" } } sub html_quote { local $_ = shift; s/&/&/g; s/' '' ' ' ' ' ' $title' '' )); # '' if ($0 =~ /fexdev/) { $head .= "\n" } else { $head .= "\n" } $title =~ s:F\*EX:F*EX:; if (open $header,'<',"$docdir/$header") { $head .= $_ while <$header>; close $header; } $head .= &$prolog($title) if defined($prolog); if (@H1_extra) { $head .= sprintf( '

%s

', $H1_extra[0],$H1_extra[1]||'',$title ); } else { $head .= "

$title

"; } $head .= "\n"; return $head; } sub html_error { my $error = shift; my $msg = "@_"; my @msg = @_; my $isodate = isodate(time); $msg =~ s/[\s\n]+/ /g; $msg =~ s/<.+?>//g; # remove HTML map { s///gi } @msg; errorlog($msg); $SIG{ALRM} = sub { $SIG{__DIE__} = 'DEFAULT'; die "TIMEOUT\n"; }; alarm($timeout); # cannot send standard HTTP Status-Code 400, because stupid # Internet Explorer then refuses to display HTML body! http_header("666 Bad Request - $msg"); print html_header($error); print 'ERROR: ',join("

\n",@msg),"\n"; pq(qq( '


' '

' $ENV{HTTP_HOST}' ' $isodate' ' $ENV{SERVER_ADMIN}' '
' '' )); exit; } sub http_die { # not in CGI mode unless ($ENV{GATEWAY_INTERFACE}) { warn "$0: @_\n"; # must not die, because of fex_cleanup! return; } debuglog(@_); # create special error file on upload if ($uid) { my $ukey = "$spooldir/.ukeys/$uid"; $ukey .= "/error" if -d $ukey; unlink $ukey; if (open $ukey,'>',$ukey) { print {$ukey} join("\n",@_),"\n"; close $ukey; } } html_error($error||'',@_); } sub check_maint { if (my $status = readlink '@MAINTENANCE') { my $isodate = isodate(time); http_header('666 MAINTENANCE'); print html_header($head||''); pq(qq( "
" "

Server is in maintenance mode

" "

($status)

" "
" "


" "

$ENV{HTTP_HOST} $isodate
" "" )); exit; } } sub check_status { my $user = shift; $user = lc $user; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; if (-e "$user/\@DISABLED") { my $isodate = isodate(time); http_header('666 DISABLED'); print html_header($head); pq(qq( "

$user is disabled

" "Contact $ENV{SERVER_ADMIN} for details" "


" "

$ENV{HTTP_HOST} $isodate
" "" )); exit; } } sub isodate { my @d = localtime shift; return sprintf('%d-%02d-%02d %02d:%02d:%02d', $d[5]+1900,$d[4]+1,$d[3],$d[2],$d[1],$d[0]); } sub encode_Q { my $s = shift; $s =~ s{([\=\x00-\x20\x7F-\xA0])}{sprintf("=%02X",ord($1))}eog; return $s; } # from MIME::Base64::Perl sub decode_b64 { local $_ = shift; my $uu = ''; my ($i,$l); tr|A-Za-z0-9+=/||cd; s/=+$//; tr|A-Za-z0-9+/| -_|; return '' unless length; $l = (length)-60; for ($i = 0; $i <= $l; $i += 60) { $uu .= "M" . substr($_,$i,60); } $_ = substr($_,$i); $uu .= chr(32+(length)*3/4) . $_ if $_; return unpack ("u",$uu); } # short base64 encoding sub b64 { local $_ = ''; my $x = 0; pos($_[0]) = 0; $_ = join '',map(pack('u',$_)=~ /^.(\S*)/, ($_[0]=~/(.{1,45})/gs)); tr|` -_|AA-Za-z0-9+/|; $x = (3 - length($_[0]) % 3) % 3; s/.{$x}$//; return $_; } # simulate a "rm -rf", but never removes '..' # return number of removed files sub rmrf { my @files = @_; my $dels = 0; my ($file,$dir); local *D; local $_; foreach (@files) { next if /(^|\/)\.\.$/; /(.*)/; $file = $1; if (-d $file and not -l $file) { $dir = $file; opendir D,$dir or next; while ($file = readdir D) { next if $file eq '.' or $file eq '..'; $dels += rmrf("$dir/$file"); } closedir D; rmdir $dir and $dels++; } else { unlink $file and $dels++; } } return $dels; } sub gethostname { my $hostname = hostname; my $domain; local $_; unless ($hostname) { $_ = `hostname 2>/dev/null`; $hostname = /(.+)/ ? $1 : ''; } if ($hostname !~ /\./ and open my $rc,'/etc/resolv.conf') { while (<$rc>) { if (/^\s*domain\s+([\w.-]+)/) { $domain = $1; last; } if (/^\s*search\s+([\w.-]+)/) { $domain = $1; } } close $rc; $hostname .= ".$domain" if $domain; } if ($hostname !~ /\./ and $admin and $admin =~ /\@([\w.-]+)/) { $hostname .= '.'.$1; } return $hostname; } # strip off path names (Windows or UNIX) sub strip_path { local $_ = shift; s/.*\\// if /^([A-Z]:)?\\/; s:.*/::; return $_; } # substitute all critcal chars sub normalize { local $_ = shift; return '' unless defined $_; # we need perl native utf8 (see perldoc utf8) $_ = decode_utf8($_) unless utf8::is_utf8($_); s/[\r\n\t]+/ /g; s/[\x00-\x1F\x80-\x9F]/_/g; s/^\s+//; s/\s+$//; return encode_utf8($_); } # substitute all critcal chars sub normalize_html { local $_ = shift; return '' unless defined $_; $_ = normalize($_); s/[\"<>]//g; return $_; } # substitute all critcal chars with underscore sub normalize_filename { local $_ = shift; return $_ unless $_; # we need native utf8 $_ = decode_utf8($_) unless utf8::is_utf8($_); $_ = strip_path($_); # substitute all critcal chars with underscore s/[^a-zA-Z0-9_=.+-]/_/g; s/^\./_/; return encode_utf8($_); } sub normalize_email { local $_ = lc shift; s/[^\w_.+=!~#^\@\-]//g; s/^\./_/; /(.*)/; return $1; } sub normalize_user { my $user = shift; $user = lc(urldecode(despace($user))); $user .= '@'.$mdomain if $mdomain and $user !~ /@/; checkaddress($user) or http_die("$user is not a valid e-mail address"); return untaint($user); } sub urldecode { local $_ = shift; s/%([a-f0-9]{2})/chr(hex($1))/gie; return $_; } sub untaint { local $_ = shift; /(.*)/s; return $1; } sub checkchars { my $input = shift; local $_ = shift; if (/^([|+.])/) { http_die("\"$1\" is not allowed at beginning of $input"); } if (/([\/\"\'\\<>;])/) { http_die(sprintf("\"&#%s;\" is not allowed in %s",ord($1),$input)); } if (/(\|)$/) { http_die("\"$1\" is not allowed at end of $input"); } if (/[\000-\037]/) { http_die("control characters are not allowed in $input"); } /(.*)/; return $1; } sub checkaddress { my $a = shift; my $re; local $_; local ($domain,$dns); $a =~ s/:\w+=.*//; # remove options from address return $a if $a eq 'anonymous'; $a .= '@'.$mdomain if $mdomain and $a !~ /@/; $re = '^[.@-]|@.*@|local(host|domain)$|["\'\`\|\s()<>/;,]'; if ($a =~ /$re/i) { debuglog("$a has illegal syntax ($re)"); return ''; } $re = '^[!^=~#_:.+*{}\w\-\[\]]+\@(\w[.\w\-]*\.[a-z]+)$'; if ($a =~ /$re/i) { $domain = $dns = $1; { local $SIG{__DIE__} = sub { die "\n" }; eval q{ use Net::DNS; $dns = Net::DNS::Resolver->new->query($domain)||mx($domain); unless ($dns or mx('uni-stuttgart.de')) { http_die("Internal error: bad resolver"); } } }; if ($dns) { return untaint($a); } else { debuglog("no A or MX DNS record found for $domain"); return ''; } } else { debuglog("$a does not match e-mail regexp ($re)"); return ''; } } # check forbidden addresses sub checkforbidden { my $a = shift; my ($fr,$pr); local $_; $a .= '@'.$mdomain if $mdomain and $a !~ /@/; return $a if -d "$spooldir/$a"; # ok, if user already exists if (@forbidden_recipients) { foreach (@forbidden_recipients) { $fr = quotewild($_); # skip public recipients if (@public_recipients) { foreach $pr (@public_recipients) { return $a if $a eq lc $pr; } } return '' if $a =~ /^$fr$/i; } } return $a; } sub randstring { my $n = shift; my @rc = ('A'..'Z','a'..'z',0..9 ); my $rn = @rc; my $rs; for (1..$n) { $rs .= $rc[int(rand($rn))] }; return $rs; } # emulate mkdir -p sub mkdirp { my $dir = shift; my $pdir; return if -d $dir; $dir =~ s:/+$::; http_die("cannot mkdir /") unless $dir; $pdir = $dir; if ($pdir =~ s:/[^/]+$::) { mkdirp($pdir) unless -d $pdir; } unless (-d $dir) { mkdir $dir,0770 or http_die("mkdir $dir - $!"); } } # hash with SID sub sidhash { my ($rid,$id) = @_; if ($rid and $ENV{SID} and $id =~ /^MD5H:/) { $rid = 'MD5H:'.md5_hex($rid.$ENV{SID}); } return $rid; } # test if ip is in iplist (ipv4/ipv6) # iplist is an array with ips and ip-ranges sub ipin { my ($ip,@list) = @_; my ($i,$ia,$ib); $ipe = lc(ipe($ip)); map { lc } @list; foreach $i (@list) { if ($ip =~ /\./ and $i =~ /\./ or $ip =~ /:/ and $i =~ /:/) { if ($i =~ /(.+)-(.+)/) { ($ia,$ib) = ($1,$2); $ia = ipe($ia); $ib = ipe($ib); return $ip if $ipe ge $ia and $ipe le $ib; } else { return $ip if $ipe eq ipe($i); } } } return ''; } # ip expand (ipv4/ipv6) sub ipe { local $_ = shift; if (/^\d+\.\d+\.\d+\.\d+$/) { s/\b(\d\d?)\b/sprintf "%03d",$1/ge; } elsif (/^[:\w]+:\w+$/) { s/\b(\w+)\b/sprintf "%04s",$1/ge; s/^:/0000:/; while (s/::/::0000:/) { last if length > 39 } s/::/:/; } else { $_ = ''; } return $_; } sub filename { my $file = shift; my $filename; if (open $file,'<',"$file/filename") { $filename = <$file>||''; chomp $filename; close $file; } unless ($filename) { $filename = $file; $filename =~ s:.*/::; } return $filename; } sub urlencode { local $_ = shift; s/(^[.~]|[^\w.,=:~^+-])/sprintf "%%%X",ord($1)/ge; return $_; } # file and document log sub fdlog { my ($log,$file,$s,$size) = @_; my $ra = $ENV{REMOTE_ADDR}||'-'; my $msg; $ra .= '/'.$ENV{HTTP_X_FORWARDED_FOR} if $ENV{HTTP_X_FORWARDED_FOR}; $ra =~ s/\s//g; $file =~ s:/data$::; $msg = sprintf "%s [%s_%s] %s %s %s/%s\n", isodate(time),$$,$ENV{REQUESTCOUNT},$ra,encode_Q($file),$s,$size; writelog($log,$msg); } # extra debug log sub debuglog { my $prg = $0; local $_; return unless $debug and @_; unless ($debuglog and fileno $debuglog) { my $ddir = "$spooldir/.debug"; mkdir $ddir,0770 unless -d $ddir; $prg =~ s:.*/::; $prg = untaint($prg); $debuglog = sprintf("%s/%s_%s_%s.%s", $ddir,time,$$,$ENV{REQUESTCOUNT}||0,$prg); $debuglog =~ s/\s/_/g; # http://perldoc.perl.org/perlunifaq.html#What-is-a-%22wide-character%22%3f # open $debuglog,'>>:encoding(UTF-8)',$debuglog or return; open $debuglog,'>>',$debuglog or return; # binmode($debuglog,":utf8"); autoflush $debuglog 1; # printf {$debuglog} "\n### %s ###\n",isodate(time); } while ($_ = shift @_) { $_ = encode_utf8($_) if utf8::is_utf8($_); s/\n*$/\n/; s/<.+?>//g; # remove HTML print {$debuglog} $_; print "DEBUG: $_" if -t; } } # extra debug log sub errorlog { my $prg = $0; my $msg = "@_"; my $ra = $ENV{REMOTE_ADDR}||'-'; $ra .= '/'.$ENV{HTTP_X_FORWARDED_FOR} if $ENV{HTTP_X_FORWARDED_FOR}; $ra =~ s/\s//g; $prg =~ s:.*/::; $msg =~ s/[\r\n]+$//; $msg =~ s/[\r\n]+/ /; $msg =~ s/\s*

.*//; $msg = sprintf "%s %s %s %s\n",isodate(time),$prg,$ra,$msg; writelog('error.log',$msg); } sub writelog { my $log = shift; my $msg = shift; foreach my $logdir (@logdir) { if (open $log,'>>',"$logdir/$log") { flock $log,LOCK_EX; seek $log,0,SEEK_END; print {$log} $msg; close $log; } } } # failed authentification log sub faillog { my $request = shift; my $n = 1; if ($faillog and $max_fail_handler and open $faillog,"+>>$faillog") { flock($faillog,LOCK_EX); seek $faillog,0,SEEK_SET; $n++ while <$faillog>; printf {$faillog} "%s %s\n",isodate(time),$request; close $faillog; &$max_fail_handler($ENV{REMOTE_ADDR}) if $n > $max_fail; } } # remove all white space sub despace { local $_ = shift; s/\s//g; return $_; } # superquoting sub qqq { local $_ = shift; my ($s,$i,@s); my $q = "[\'\"]"; # quote delimiter chars " and ' # remove first newline and look for default indention s/^((\d+)?)?\n//; $i = ' ' x ($2||0); # remove trailing spaces at end s/[ \t]*?$//; @s = split "\n"; # first line have a quote delimiter char? if (/^\s+$q/) { # remove heading spaces and delimiter chars foreach (@s) { s/^\s*$q//; s/$q\s*$//; } } else { # find the line with the fewest heading spaces (and count them) # (beware of tabs!) $s = length; foreach (@s) { if (/^( *)\S/ and length($1) < $s) { $s = length($1) }; } # adjust indention foreach (@s) { s/^ {$s}/$i/; } } return join("\n",@s)."\n"; } # print superquoted sub pq { my $H = STDOUT; if (@_ > 1 and defined fileno $_[0]) { $H = shift } binmode($H,':utf8'); print {$H} qqq(@_); } # check sender quota sub check_sender_quota { my $sender = shift; my $squota = $sender_quota||0; my $du = 0; my ($file,$size,%file,$data,$upload); local $_; if (open $qf,'<',"$sender/\@QUOTA") { while (<$qf>) { s/#.*//; $squota = $1 if /sender.*?(\d+)/i; } close $qf; } foreach $file (glob "*/$sender/*") { $data = "$file/data"; $upload = "$file/upload"; if (not -l $data and $size = -s $data) { # count hard links only once (= same inode) my $i = (stat($data))[1]||0; unless ($file{$i}) { $du += $size; $file{$i} = $i; } } elsif (-f $upload) { # count hard links only once (= same inode) my $i = (stat($upload))[1]||0; unless ($file{$i}) { $size = readlink "$file/size" and $du += $size; $file{$i} = $i; } } } return($squota,int($du/1024/1024)); } # check recipient quota sub check_recipient_quota { my $recipient = shift; my $rquota = $recipient_quota||0; my $du = 0; my ($file,$size); local $_; if (open my $qf,'<',"$recipient/\@QUOTA") { while (<$qf>) { s/#.*//; $rquota = $1 if /recipient.*?(\d+)/i; } close $qf; } foreach $file (glob "$recipient/*/*") { if (-f "$file/upload" and $size = readlink "$file/size") { $du += $size; } elsif (not -l "$file/data" and $size = -s "$file/data") { $du += $size; } } return($rquota,int($du/1024/1024)); } sub getline { my $file = shift; local $_; chomp($_ = <$file>||''); return $_; } # (shell) wildcard matching sub wcmatch { local $_ = shift; my $p = quotemeta shift; $p =~ s/\\\*/.*/g; $p =~ s/\\\?/./g; $p =~ s/\\\[/[/g; $p =~ s/\\\]/]/g; return /$p/; } sub logout { my $logout; if ($skey) { $logout = "/fup?logout=skey:$skey" } elsif ($gkey) { $logout = "/fup?logout=gkey:$gkey" } elsif ($akey) { $logout = "/fup?logout=akey:$akey" } else { $logout = "/fup?logout" } return qqq(qq( '

' '

' ' ' '
' '

' )); } # print data dump of global or local variables in HTML # input musst be a string, eg: '%ENV' sub DD { my $v = shift; local $_; $n =~ s/.//; $_ = eval(qq(use Data::Dumper;Data::Dumper->Dump([\\$v]))); s/\$VAR1/$v/; s/&/&/g; s/\n$_\n\n"; } # make symlink sub mksymlink { my ($file,$link) = @_; unlink $file; return symlink untaint($link),$file; } # copy file (and modify) or symlink # returns chomped file contents or link name # preserves permissions and time stamps sub copy { my ($from,$to,$mod) = @_; my $link; local $/; local $_; $to .= '/'.basename($from) if -d $to; if (defined($link = readlink $from)) { mksymlink($to,$link); return $link; } else { open $from,'<',$from or return; open $to,'>',$to or return; $_ = <$from>; close $from; eval $mod if $mod; print {$to} $_; close $to or http_die("internal error: $to - $!"); if (my @s = stat($from)) { chmod $s[2],$to; utime @s[8,9],$to unless $mod; } chomp; return $_; } } sub slurp { my $file = shift; local $_; local $/; if (open $file,$file) { $_ = <$file>; close $file; } return $_; } # read one line from STDIN (net socket) and assign it to $_ # return number of read bytes # also set global variable $RB (read bytes) sub nvt_read { my $len = 0; if (defined ($_ = )) { 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/ } } # HTTP GET and POST parameters # (not used by fup) # fills global variable %PARAM : # normal parameter is $PARAM{$parameter} # file parameter is $PARAM{$parameter}{filename} $PARAM{$parameter}{data} sub parse_parameters { my $cl = $ENV{X_CONTENT_LENGTH} || $ENV{CONTENT_LENGTH} || 0; my $data = ''; my $filename; local $_; if ($cl > 128*$MB) { http_die("request too large"); } binmode(STDIN,':raw'); foreach (split('&',$ENV{QUERY_STRING})) { if (/(.+?)=(.*)/) { $PARAM{$1} = $2 } else { $PARAM{$_} = $_ } } $_ = $ENV{CONTENT_TYPE}||''; if ($ENV{REQUEST_METHOD} eq 'POST' and /boundary=\"?([\w\-\+\/_]+)/) { my $boundary = $1; while ($RB<$cl and &nvt_read) { last if /^--\Q$boundary/ } # continuation lines are not checked! while ($RB<$cl and &nvt_read) { $filename = ''; if (/^Content-Disposition:.*\s*filename="(.+?)"/i) { $filename = $1; } if (/^Content-Disposition:\s*form-data;\s*name="(.+?)"/i) { my $p = $1; # skip rest of mime part header while ($RB<$cl and &nvt_read) { last if /^\s*$/ } $data = ''; while () { if ($p =~ /password/i) { debuglog('*' x length) } else { debuglog($_) } $RB += length; last if /^--\Q$boundary/; $data .= $_; } unless (defined $_) { die "premature end of HTTP POST\n" } $data =~ s/\r?\n$//; if ($filename) { $PARAM{$p}{filename} = $filename; $PARAM{$p}{data} = $data; } else { $PARAM{$p} = $data; } last if /^--\Q$boundary--/; } } } } # name based virtual host? sub vhost { my $hh = shift; # HTTP_HOST my $vhost; my $locale = $ENV{LOCALE}; # memorized vhost? (default is in fex.ph) %vhost = split(':',$ENV{VHOST}) if $ENV{VHOST}; if (%vhost and $hh and $hh =~ s/^([\w\.-]+).*/$1/) { if ($vhost = $vhost{$hh} and -f "$vhost/lib/fex.ph") { $ENV{VHOST} = "$hh:$vhost"; # memorize vhost for next run $ENV{FEXLIB} = $FEXLIB = "$vhost/lib"; $logdir = $spooldir = "$vhost/spool"; $docdir = "$vhost/htdocs"; @logdir = ($logdir); if ($locale and -e "$vhost/locale/$locale/lib/fex.ph") { $ENV{FEXLIB} = $FEXLIB = "$vhost/locale/$locale/lib"; } require "$FEXLIB/fex.ph" or die "$0: cannot load $FEXLIB/fex.ph - $!"; $ENV{SERVER_NAME} = $hostname; @doc_dirs = ($docdir); foreach my $ld (glob "$FEXHOME/locale/*/htdocs") { push @doc_dirs,$ld; } return $vhost; } } } sub gpg_encrypt { my ($plain,$to,$keyring,$from) = @_; my ($pid,$pi,$po,$pe,$enc,$err); local $_; $pe = gensym; $pid = open3($po,$pi,$pe, "gpg --batch --trust-model always --keyring $keyring". " -a -e -r $bcc -r $to" ) or return; print {$po} "\n",$plain,"\n"; close $po; $enc .= $_ while <$pi>; $err .= $_ while <$pe>; errorlog("($from --> $to) $err") if $err; close $pi; close $pe; waitpid($pid,0); return $enc; } sub mtime { my @s = stat(shift) or return; return $s[9]; } # wildcard * to perl regexp sub quotewild { local $_ = quotemeta shift; s/\\\*/.*/g; # allow wildcard * return $_; } # extract locale functions into hash of subroutine references # e.g. \&german ==> $notify{german} sub locale_functions { my $locale = shift; local $/; local $_; if ($locale and open my $fexpp,"$FEXHOME/locale/$locale/lib/fex.pp") { $_ = <$fexpp>; s/.*\n(\#\#\# locale functions)/$1/s; # sub xx {} ==> xx{$locale} = sub {} s/\nsub (\w+)/\n\$$1\{$locale\} = sub/gs; s/\n}\n/\n};\n/gs; eval $_; close $fexpp; } } sub notify_locale { my $dkey = shift; my $status = shift || 'new'; my ($to,$keep,$locale,$file,$filename,$comment,$autodelete,$replyto,$mtime); local $_; if ($dkey =~ m:/.+/.+/:) { $file = $dkey; $dkey = readlink("$file/dkey"); } else { $file = readlink("$dkeydir/$dkey") or http_die("internal error: no DKEY $DKEY"); } $file =~ s:^../::; $filename = filename($file); $to = $file; $to =~ s:/.*::; $mtime = mtime("$file/data") or http_die("internal error: no $file/data"); $comment = slurp("$file/comment") || ''; $replyto = readlink "$file/replyto" || ''; $autodelete = readlink "$file/autodelete" || readlink "$to/\@AUTODELETE" || $::autodelete; $keep = readlink "$file/keep" || readlink "$to/\@KEEP" || $keep_default; $locale = readlink "$to/\@LOCALE" || readlink "$file/locale" || 'english'; $_ = untaint("$FEXHOME/locale/$locale/lib/lf.pl"); require if -f; unless ($notify{$locale}) { $locale = 'english'; $notify{$locale} ||= \¬ify; } return &{$notify{$locale}}( status => $status, dkey => $dkey, filename => $filename, keep => $keep-int((time-$mtime)/$DS), comment => $comment, autodelete => $autodelete, replyto => $replyto, ); } ########################### locale functions ########################### # Will be extracted by install process and saved in $FEXHOME/lib/lf.pl # # You cannot modify them here without re-installing! # ######################################################################## # locale function! sub notify { # my ($status,$dkey,$filename,$keep,$warn,$comment,$autodelete) = @_; my %P = @_; my ($to,$from,$file,$mimefilename,$receiver,$warn,$comment,$autodelete); my ($size,$bytes,$days,$header,$data,$replyto,$uurl); my ($mfrom,$mto,$dfrom,$dto); my $proto = 'http'; my $durl = $::durl; my $index; my $fileid = 0; my $fua = $ENV{HTTP_USER_AGENT}||''; my $warning = ''; my $disclaimer = ''; my $download = ''; my $keyring; my $boundary = randstring(16); my ($body,$enc_body); return if $nomail; $warn = $P{warn}||2; $comment = $P{comment}||''; $comment = encode_utf8($P{comment}||'') if utf8::is_utf8($comment); $comment =~ s/^!\*!//; # multi download allow flag $autodelete = $P{autodelete}||$::autodelete; $file = untaint(readlink("$dkeydir/$P{dkey}")); $file =~ s/^\.\.\///; # make download protocal same as upload protocol if ($uurl = readlink("$file/uurl") and $uurl =~ /^(\w+):/) { $proto = $1; $durl =~ s/^\w+::/$proto::/; } $index = "$proto://$hostname/index.html"; ($to,$from,$file) = split('/',$file); $filename = strip_path($P{filename}); $mfrom = $from; $mto = $to; $mfrom .= '@'.$mdomain if $mdomain and $mfrom !~ /@/; $mto .= '@'.$mdomain if $mdomain and $mto !~ /@/; $keyring = $to.'/@GPG'; # $to = '' if $to eq $from; # ??? $replyto = $P{replyto}||$mfrom; $header = "From: <$mfrom> ($mfrom via F*EX service $hostname)\n"; $header .= "Reply-To: <$replyto>\n" if $replyto ne $mfrom; $header .= "To: <$mto>\n"; $data = "$dkeydir/$P{dkey}/data"; $size = $bytes = -s $data; return unless $size; $warning = "We recommend fexget or fexit for download,\n". "because these clients can resume the download after an interruption.\n". "See $proto://$hostname/tools.html"; # if ($nowarning) { # $warning = ''; # } else { # $warning = # "Please avoid download with Internet Explorer, ". # "because it has too many bugs.\n\n"; # } if ($filename =~ /\.(tar|zip|7z|arj|rar)$/) { $warning .= "\n\n". "$filename is a container file.\n". "You can unpack it for example with 7zip ". "(http://www.7-zip.org/download.html)"; } if ($limited_download =~ /^y/i) { $warning .= "\n\n". 'This download link only works for you, you cannot distribute it.'; } if ($size < 2048) { $size = "$size Bytes"; } elsif ($size/1024 < 2048) { $size = int($size/1024)." kB"; } else { $size = int($size/1024/1024)." MB"; } if ($autodelete eq 'YES') { $autodelete = "WARNING: After download (or view with a web browser!), " . "the file will be deleted!"; } elsif ($autodelete eq 'DELAY') { $autodelete = "WARNING: When you download the file it will be deleted " . "soon afterwards!"; } else { $autodelete = ''; } if (-s $keyring) { $mimefilename = ''; } else { $mimefilename = $filename; if ($mimefilename =~ s/([_\?\=\x00-\x1F\x7F-\xFF])/sprintf("=%02X",ord($1))/eog) { $mimefilename =~ s/ /_/g; $mimefilename = '=?UTF-8?Q?'.$mimefilename.'?='; } } unless ($fileid = readlink("$dkeydir/$P{dkey}/id")) { my @s = stat($data); $fileid = @s ? $s[1].$s[9] : 0; } if ($P{status} eq 'new') { $days = $P{keep}; $header .= "Subject: F*EX-upload: $mimefilename\n"; } else { $days = $warn; $header .= "Subject: reminder F*EX-upload: $mimefilename\n"; } $header .= "X-FEX-Client-Address: $fra\n" if $fra; $header .= "X-FEX-Client-Agent: $fua\n" if $fua; foreach my $u (@durl?@durl:($durl)) { my $durl = sprintf("%s/%s/%s",$u,$P{dkey},normalize_filename($filename)); $header .= "X-FEX-URL: $durl\n" unless -s $keyring; $download .= "$durl\n"; } $header .= "X-FEX-Filesize: $bytes\n". "X-FEX-File-ID: $fileid\n". "X-FEX-Fexmaster: $ENV{SERVER_ADMIN}\n". "X-Mailer: F*EX\n". "MIME-Version: 1.0\n"; if ($comment =~ s/^\[(\@(.*?))\]\s*//) { $receiver = "group $1"; if ($_ = readlink "$from/\@GROUP/$2" and m:^../../(.+?)/:) { $receiver .= " (maintainer: $1)"; } } else { $receiver = 'you'; } if ($days == 1) { $days .= " day" } else { $days .= " days" } # explicite sender set in fex.ph? if ($sender_from) { map { s/^From: <$mfrom/From: <$sender_from/ } $header; open $sendmail,'|-',$sendmail,$mto,$bcc or http_die("cannot start sendmail - $!"); } else { # for special remote domains do not use same domain in From, # because remote MTA will probably reject this e-mail $dfrom = $1 if $mfrom =~ /@(.+)/; $dto = $1 if $mto =~ /@(.+)/; if ($dfrom and $dto and @remote_domains and grep { $dfrom =~ /(^|\.)$_$/ and $dto =~ /(^|\.)$_$/ } @remote_domains) { $header =~ s/(From: <)\Q$mfrom\E(.*?)\n/$1$admin$2\nReply-To: $mfrom\n/; open $sendmail,'|-',$sendmail,$mto,$bcc or http_die("cannot start sendmail - $!"); } else { open $sendmail,'|-',$sendmail,'-f',$mfrom,$mto,$bcc or http_die("cannot start sendmail - $!"); } } $comment = "\n$comment\n" if $comment; if ($comment =~ s/\n!(shortmail|\.)!\s*//i or (readlink("$to/\@NOTIFICATION")||'') =~ /short/i ) { $body = qqq(qq( '$comment' '$download' '$size' )); } else { $disclaimer = slurp("$from/\@DISCLAIMER") || qqq(qq( '$warning' '' 'F*EX is not an archive, it is a transfer system for personal files.' 'For more information see $index' '' 'Questions? ==> F*EX admin: $admin' )); $disclaimer .= "\n$::disclaimer\n" if $::disclaimer; $body = qqq(qq( '$comment' '$from has uploaded the file' ' "$filename"' '($size) for $receiver. Use' '' '$download' 'to download this file within $days.' '' '$autodelete' '' '$disclaimer' )); } $body =~ s/\n\n+/\n\n/g; if (-s $keyring) { $enc_body = gpg_encrypt($body,$to,$keyring,$from); } if ($enc_body) { # RFC3156 $header .= qqq(qq( 'Content-Type: multipart/encrypted; protocol="application/pgp-encrypted";' '\tboundary="$boundary"' 'Content-Disposition: inline' )); $body = qqq(qq( '--$boundary' 'Content-Type: application/pgp-encrypted' 'Content-Disposition: attachment' '' 'Version: 1' '' '--$boundary' 'Content-Type: application/octet-stream' 'Content-Disposition: inline; filename="fex.pgp"' '' '$enc_body' '--$boundary--' )); } else { $header .= "Content-Type: text/plain; charset=UTF-8\n". "Content-Transfer-Encoding: 8bit\n"; } print {$sendmail} $header,"\n",$body; close $sendmail and return $to; http_die("cannot send notification e-mail (sendmail error $!)"); } # locale function! sub reactivation { my ($expire,$user) = @_; my $fexsend = "$FEXHOME/bin/fexsend"; my $reactivation = "$FEXLIB/reactivation.txt"; return if $nomail; if (-x $fexsend) { if ($locale) { my $lr = "$FEXHOME/locale/$locale/lib/reactivation.txt"; $reactivation = $lr if -f $lr and -s $lr; } $fexsend .= " -M -D -k 30 -C" ." 'Your F*EX account has been inactive for $expire days," ." you must download this file to reactivate it." ." Otherwise your account will be deleted.'" ." $reactivation $user"; # on error show STDOUT and STDERR my $fo = `$fexsend 2>&1`; warn $fexsend.'\n'.$fo if $?; } else { warn "$0: cannot execute $fexsend for reactivation()\n"; } } 1; fex-20160919/lib/dop0000711000174700017470000003637512770006663012206 0ustar fexfex#!/usr/bin/perl -wT # F*EX document output # # is a subprogram of fexsrv! do not run it directly! # # Author: Ulli Horlacher # use File::Basename; use Fcntl qw(:flock :seek :mode); use POSIX qw(strftime locale_h); use Cwd qw(getcwd abs_path); use utf8; # use CGI::Carp qw(fatalsToBrowser); # import from fex.pp our ($bs,$tmpdir,@doc_dirs); my $log = 'dop.log'; # POSIX time format needed for HTTP header setlocale(LC_TIME,'POSIX'); sub dop { my $doc = shift; my $source = shift; my $seek = 0; my $stop = 0; my ($link,$host,$path,$range); our $error = 'F*EX document output ERROR'; security_check($doc); # reget? if ($range = $ENV{HTTP_RANGE}) { $seek = $1 if $range =~ /^bytes=(\d+)-/i; $stop = $1 if $range =~ /^bytes=\d*-(\d+)/i; } # redirect on relative symlinks without "../" if ($link = readlink($doc) and $link !~ m:^/: and $link !~ m:\.\./: and $link !~ /^:.+:$/) { $path = $ENV{REQUEST_URI}; $path =~ s:[^/]*$::; $doc = "$path/$link"; $doc =~ s:/+:/:g; $doc =~ s:^/::; nvt_print( "HTTP/1.1 302 Found", "Location: /$doc", "Content-Length: 0", "" ); &reexec; } # watchdog documents if (@wdd and $wdd and grep { $doc =~ /$_/ } @wdd) { &$wdd($doc) } my $dir = untaint(getcwd()); chdir(dirname($doc)); http_output($doc,$seek,$stop); chdir($dir); } sub http_output { my ($file,$seek,$stop) = @_; my ($filename,$files,$streamfile,$size,$total_size); my ($data,$type); my ($var,$env,$con); my @files; my $htmldoc = ''; my $htauth; my @s; my $s = 0; my $b = 0; my $http_client = $ENV{HTTP_USER_AGENT} || ''; local $_; # extra security check: document must not be in lib or spool directory if (path_match($file,$FEXLIB) or path_match($file,$spooldir)) { http_error(403); } security_check($file); $htauth = dirname($file).'/.htauth'; require_auth($htauth,$file) if -f $htauth; if (-f $file) { # normal file open $file,'<',$file or http_error(400); security_check($file); } elsif ($file =~ /(.+)\.gz$/ and -f $1) { @files = ($1); open $file,'-|',qw'gzip -c',@files or http_error(503); } elsif ($file =~ /(.+)\.tgz$/ and -f "$1.tar") { @files = ("$1.tar"); open $file,'-|',qw'gzip -c',@files or http_error(503); } elsif ($file =~ /(.+)\.(tar|tgz|zip)$/ and @s = lstat($streamfile = "$1.stream") and ($s[4] == $< or $s[4] == 0)) { # streaming file chdir dirname($file); security_check($file); if (-l $streamfile and readlink($streamfile) =~ /^:(.+):$/) { # special symlink pointer file for streaming @files = split(/:/,$1); } elsif (open $streamfile,$streamfile) { # special streaming file while (<$streamfile>) { chomp; if (/^(\/.*):/) { chdir $1; security_check($1); } else { push @files,$_; } } } else { http_error(503); } close $streamfile; foreach (@files) { if (/^\// or /\.\.\//) { # absolute path or relative path with parent directory is not allowed errorlog("$streamfile: $_ is not allowed for streaming"); http_error(403); } unless (-e $_) { errorlog("$streamfile: $_ does not exist"); http_error(403); } if (@s = stat($_) and not($s[2] & S_IRGRP) or not -r $_) { # file must be readable by user and group errorlog("$streamfile: $_ is not readable by user and group"); http_error(403); } } http_error(416) if $ENV{HTTP_RANGE}; close STDERR; if ($file =~ /\.tar$/) { @a = qw'tar --exclude *~ --exclude .* -cf -' } elsif ($file =~ /\.tgz$/) { @a = qw'tar --exclude *~ --exclude .* -czf -' } elsif ($file =~ /\.zip$/) { @a = qw'zip -x *~ */.*/* @ -rq -' } else { http_error(400) } open $file,'-|',@a,@files or http_error(503); } else { http_error(404); } $type = 'application/octet-stream'; if ($file =~ /\.html$/) { $type = 'text/html' } # elsif ($file =~ /\.txt$/) { $type = 'text/plain' } elsif ($file =~ /\.css$/) { $type = 'text/css' } elsif ($file =~ /\.js$/) { $type = 'text/javascript' } elsif ($file =~ /\.ps$/) { $type = 'application/postscript' } elsif ($file =~ /\.pdf$/) { $type = 'application/pdf' } elsif ($file =~ /\.jpg$/) { $type = 'image/jpeg' } elsif ($file =~ /\.png$/) { $type = 'image/png' } elsif ($file =~ /\.gif$/) { $type = 'image/gif' } elsif ($file !~ /\.(tar|tgz|zip|jar|rar|arj|7z|bz2?|gz)$/) { my $qfile = untaint(abs_path($file)); $qfile =~ s/([^\/\.\+\w!=,_-])/\\$1/g; $_ = `file $qfile`; if (/HTML/) { $type = 'text/html'; } elsif (/text/i and not -x $file) { $type = 'text/plain'; if (/\sASCII\s/) { $type .= "; charset=us-ascii" } elsif (/(ISO-[\w-]+)/) { $type .= "; charset=".lc($1) } else { $type .= "; charset=utf-8" } } } # show sourcecode if URL ends with '!' # to avoid this for a HTML file, simple do a: chmod o-r file if ($type eq 'text/html') { if ($htmlsource) { if (@s = stat($file) and $s[2] & S_IROTH) { $type = 'text/plain'; } else { http_error(403); } } } elsif ($ENV{'QUERY_STRING'} eq '!') { $type = 'text/plain'; } if ($type eq 'text/html') { $seek = $stop = 0; local $^W = 0; local $/; $htmldoc = <$file>; while ($htmldoc =~ s/\n##.*?\n/\n/) {}; # evaluate #if ... #else ... #elseif ... #endif blocks my $mark = randstring(16); while ($htmldoc =~ s/\n(#if\s+(.+?)\n.+?\n)#endif/\n$mark/s) { $_ = $1; # if block if (eval $2) { s/#if.*\n//; s/\n#else.*//s; $htmldoc =~ s/$mark/$_/; } else { # elseif blocks while (s/.*?\n#elseif\s+(.+?)\n//s) { if (eval $1) { s/\n#else.*//s; $htmldoc =~ s/$mark/$_/; } } # else block left? if ($htmldoc =~ /$mark/) { s/.*\n#else\s*\n//s or $_ = ''; $htmldoc =~ s/$mark/$_/; } } }; # evaluate #include while ($htmldoc =~ s/\n#include "(.*?)"/\n$mark/s) { my $file = $1; my $include = ''; if (open $file,$file) { $include = <$file>; close $file; } $dynamic = $htmldoc =~ s/$mark/$include/; } # evaluate <> or <<>> { local $timeout = ''; local $SIG{ALRM} = sub { $timeout = '

TIMEOUT!

' }; alarm(10); while ($htmldoc =~ /<<(.+?>?)>>/s) { local $pc = $1; if ($pc =~ s/^<(.+)>$/$1/) { # eval code without output substitution eval('package DOP;' . $pc); last if $timeout; $dynamic = $htmldoc =~ s/<<<(.+?)>>>//s; } else { # eval code with output substitution local $__ = ''; local $^W = 0; tie *STDOUT => "Buffer",\$__; my $r .= eval('package DOP;' . $pc); $__ .= $r if $pc !~ /;\s*$/; untie *STDOUT; last if $timeout; $dynamic = $htmldoc =~ s/<<(.+?)>>/$__/s; } } alarm(0); $dynamic = $htmldoc =~ s/<<(.+?>?)>>/$timeout/sg if $timeout; } # substitute $variable$ with value from environment (if present) while ($htmldoc =~ /\$([\w_]+)\$/g) { $var = $1; if (defined($env = $ENV{$var})) { $htmldoc =~ s/\$$var\$/$env/g; } }; $total_size = $size = $s = length($htmldoc); } else { if (@files) { $size = 0; } else { $total_size = -s $file || 0; $size = $total_size - $seek - ($stop ? $total_size-$stop-1 : 0); } } if ($size < 0) { http_header('416 Requested Range Not Satisfiable'); exit; } alarm($timeout*10); if ($seek or $stop) { my $range; if ($stop) { $range = sprintf("bytes %s-%s/%s",$seek,$stop,$total_size); } else { $range = sprintf("bytes %s-%s/%s",$seek,$total_size-1,$total_size); } nvt_print( 'HTTP/1.1 206 Partial Content', 'Server: fexsrv', "Content-Length: $size", "Content-Range: $range", "Content-Type: $type", ); } else { # streaming? if (@files) { nvt_print( 'HTTP/1.1 200 OK', 'Server: fexsrv', "Expires: 0", "Content-Type: $type", ); } else { # Java (clients) needs Last-Modified header! # if there are locale versions, use actual time for Last-Modified # to enforce reload of page $file =~ m{/htdocs/(.+)}; my @lfiles = glob("$FEXHOME/locale/*/htdocs/$1"); my $date = ($dynamic or @lfiles > 1) ? strftime("%a, %d %b %Y %T GMT",gmtime(time)) : http_date($file); nvt_print( 'HTTP/1.1 200 OK', 'Server: fexsrv', "Last-Modified: $date", "Expires: 0", "Content-Length: $size", "Content-Type: $type", ); # nvt_print("Set-Cookie: locale=$locale") if $use_cookies and $locale; } } nvt_print($_) foreach(@extra_header); nvt_print(''); if ($ENV{REQUEST_METHOD} eq 'GET') { if ($type eq 'text/html') { alarm($timeout*10); print $htmldoc; $s = $size; } else { # binary data # can be stream! seek $file,$seek,0 if $seek; while ($b = read($file,$data,$bs)) { if ($stop and $s+$b > $size) { $b = $size-$s; $data = substr($data,0,$b) } $s += $b; alarm($timeout*10); print $data or last; } } fdlog($log,$file,$s,$size) if $s; } alarm(0); close $file; exit if @files; # streaming end return $s; } # show directory index sub showindex { my $dir = shift; my ($htmldoc,$size); my @links = (); my @dirs = (); my @files = (); my $uri = $ENV{REQUEST_URI}; my $allowed; my ($htindex,$htauth); local $_; $uri =~ s:/+$::; $dir =~ s:/+$::; security_check($dir); $htindex = "$dir/.htindex"; $htauth = "$dir/.htauth"; open $htindex,$htindex or http_error(403); require_auth($htauth,$dir) if -f $htauth; # .htindex may contain listing regexp chomp ($allowed = <$htindex>||'.'); close $htindex; opendir $dir,$dir or http_error(503); while (defined($_ = readdir $dir)) { next if /^[.#]/ or /~$/; if (@s = lstat "$dir/$_" and ($s[2] & (S_IRGRP|S_IROTH))) { if (-l _) { push @links,$_ } elsif (-d _) { push @dirs,$_ } elsif (-f _) { push @files,$_ } } } closedir $dir; # parent directory listable? if ($uri =~ m:(/.+)/.+: and -f "$dir/../.htindex") { unshift @dirs,$1; } # first the (sub)directories $htmldoc = "\n

$uri/

\n"; foreach my $d (sort @dirs) { if ($d =~ m:^/: and -f "$d/.htindex") { $htmldoc .= "

$d/

\n"; } elsif (-f "$dir/$d/.htindex") { $htmldoc .= "

$uri/$d/

\n"; } } # # then the symlinks # $htmldoc .= "\n
\n";
#  my $link;
#  foreach my $l (sort @links) {
#    if ($l =~ /$allowed/ and $link = readlink "$dir/$l" and $link =~ /^[^.\/]/) {
#      $htmldoc .= "$l -> $dir/$link\n";
#    }
#  }

  # then the files
  $htmldoc .= "\n
\n";
  foreach my $f (sort @files) {
    if ($f =~ /$allowed/) {
      $htmldoc .= sprintf "%20s %20s %s\n",
                          isodate(mtime("$dir/$f")),
                          d3(-s "$dir/$f"||0),
                          $uri,urlencode($f),$f;
    }
  }
  $htmldoc .= "
\n\n"; $size = length($htmldoc); nvt_print( 'HTTP/1.1 200 OK', 'Server: fexsrv', "Content-Length: $size", "Content-Type: text/html", '', ); print $htmldoc; fdlog($log,"$dir/",$size,$size); } sub d3 { local $_ = shift; while (s/(\d)(\d\d\d\b)/$1,$2/) {}; return $_; } sub http_date { my $file = shift; my @stat; if (@stat = stat($file)) { return strftime("%a, %d %b %Y %T GMT",gmtime($stat[9])); } else { return 0; } } sub path_match { my $p1 = abs_path(shift); my $p2 = abs_path(shift); if (defined $p1 and defined $p2) { return 1 if $p1 =~ /^\Q$p2/; return 2 if dirname($p1) =~ /^\Q$p2/; } return 0; } # return real file name (from symlink) sub realfilename { my $file = shift; return '' unless -e $file; if (-l $file) { return realfilename(readlink($file)); } else { return $file; } } sub security_check { my $file = shift; # can be directory, too! my @s; # client ip allowed? access_check($file); # documents with leading . are not allowed if (abs_path($file) =~ /\/\./) { errorlog("$file with leading ."); http_error(403); } if (-f $file) { # document filename must not contain @ if (realfilename($file) =~ /@/ or abs_path($file) =~ /@/) { errorlog("$file contains @"); http_error(403); } # document filename must not end with ~ if (realfilename($file) =~ /~$/) { errorlog("$file ends with ~"); http_error(403); } # file must be group or world readable if (@s = stat($file) and not($s[2] & (S_IRGRP|S_IROTH))) { errorlog("$file not group or world readable"); http_error(403); } # symlink to regular file and symlink owned by root or fex? ==> ok! if (-l $file and path_match(dirname($file),$docdir)) { @s = lstat($file); return if $s[4] == 0 or $s[4] == $<; } } # file in allowed directory? ==> ok! foreach my $dir (@doc_dirs) { return if path_match($file,$dir); } errorlog("$file not in \@doc_dirs"); http_error(403); } # security check: client ip allowed? sub access_check { my $file = abs_path(shift); my $dir = $file; my $af; local $_; $dir .= '/x' if -d $dir; while ($dir = dirname($dir) and $dir ne '/') { $af = "$dir/.htaccessfrom"; if (open $af,$af) { while (<$af>) { s/\s//g; if (ipin($ra,$_)) { close $af; return; } } errorlog("no access to $file by $af"); http_error(403); } } } # HTTP Basic authentication sub require_auth { my $htauth = shift; my $doc = shift; my ($realm,$auth); my @http_auth; my $uri = $ENV{REQUEST_URI} || '/'; $uri =~ s/\/index\.html$//; $uri =~ s/\/$//; if (-d $doc or $doc =~ /\/index\.html$/) { $realm = $uri; } else { $realm = dirname($uri); } $auth = slurp($htauth); unless ($auth and $realm) { http_header("200 OK"); print html_header("$ENV{SERVER_NAME} no authentication"); pq(qq( '

$htauth missing

' '' )); exit; } chomp $auth; if ($ENV{HTTP_AUTHORIZATION} and $ENV{HTTP_AUTHORIZATION} =~ /Basic\s+(.+)/) { @http_auth = split(':',decode_b64($1)) } if (@http_auth != 2 or $http_auth[1] ne $auth) { http_header( '401 Authorization Required', "WWW-Authenticate: Basic realm=\"$realm\"", 'Content-Length: 0', ); # control back to fexsrv for further HTTP handling &reexec; } } # function for <> inside HTML documents sub out { $__ .= join('',@_); return ''; } # tie STDOUT to buffer variable (redefining print and printf) package Buffer; sub TIEHANDLE { my ($class,$buffer) = @_; bless $buffer,$class; } sub PRINT { my $buffer = shift; $$buffer .= $_ foreach @_; } sub PRINTF { my $buffer = shift; my $fmt = shift @_; $$buffer .= sprintf($fmt,@_); } 1; fex-20160919/lib/reactivation.txt0000600000174700017470000000006511705314646014712 0ustar fexfexYour F*EX account has been successfully reactivated. fex-20160919/bin/0000755000174700017470000000000012770010176011464 5ustar fexfexfex-20160919/bin/backup0000755000174700017470000000022112770010167012652 0ustar fexfex#!/bin/sh mkdir -p $HOME/backup/spool 2>/dev/null cd $HOME/spool rsync -aRH --delete --exclude "*/*@*.*" --delete-excluded * $HOME/backup/spool/ fex-20160919/bin/fexsend0000755000174700017470000027153312770010173013056 0ustar fexfex#!/usr/bin/perl -w # CLI client for the F*EX service (send, list, delete) # # see also: fexget # # Author: Ulli Horlacher # # Perl Artistic Licence use 5.006; use strict qw'vars subs'; use Encode; use Config; use Socket; use IO::Handle; use IO::Socket::INET; use Getopt::Std; use File::Basename; use Cwd 'abs_path'; use Fcntl qw':flock :mode'; use Digest::MD5 'md5_hex'; # encrypted ID / SID use Time::HiRes 'time'; # use Smart::Comments; use constant k => 2**10; use constant M => 2**20; eval 'use Net::INET6Glue::INET_is_INET6'; &update if "@ARGV" eq 'UPDATE'; $| = 1; our ($SH,$fexhome,$idf,$tmpdir,$windoof,$macos,$useragent,$editor,$nomail); our ($anonymous,$public); our ($tpid,$frecipient); our ($FEXID,$FEXXX,$HOME); our (%alias); our $chunksize = 0; our $version = 20160919; our $_0 = $0; our $DEBUG = $ENV{DEBUG}; my %SSL = (SSL_version => 'TLSv1'); my $sigpipe; if ($Config{osname} =~ /^mswin/i) { # http://slu.livejournal.com/17395.html $windoof = $Config{osname}; $HOME = $ENV{USERPROFILE}; $fexhome = $ENV{FEXHOME} || $HOME.'\fex'; $tmpdir = $ENV{FEXTMP} || $ENV{TEMP} || "$fexhome\\tmp"; $idf = "$fexhome\\id"; $editor = $ENV{EDITOR} || 'notepad.exe'; $useragent = sprintf("fexsend-$version (%s %s)", $Config{osname},$Config{archname}); $SSL{SSL_verify_mode} = 0; } elsif ($Config{osname} =~ /^darwin/i or $ENV{MACOS}) { # http://stackoverflow.com/questions/989349/running-a-command-in-a-new-mac-os-x-terminal-window $macos = $Config{osname}; $HOME = (getpwuid($<))[7]||$ENV{HOME}; $fexhome = $HOME.'/.fex'; $tmpdir = $ENV{FEXTMP} || $ENV{TMPDIR} || "$fexhome/tmp"; $tmpdir =~ s:/$::; $idf = "$fexhome/id"; chmod 0600,$idf; $editor = $ENV{EDITOR} || 'open -W -n -e'; $_ = `sw_vers -productVersion 2>/dev/null`||''; chomp; $useragent = "fexsend-$version (MacOS $_)"; } else { $0 =~ s:.*/::; $HOME = (getpwuid($<))[7]||$ENV{HOME}; $fexhome = $HOME.'/.fex'; $tmpdir = $ENV{FEXTMP} || "$fexhome/tmp"; $idf = "$fexhome/id"; chmod 0600,$idf; $editor = $ENV{EDITOR} || 'vi'; $_ = `(lsb_release -d||uname -a)2>/dev/null`||''; chomp; s/^Description:\s+//; $useragent = "fexsend-$version ($_)"; } if (-f ($_ = '/etc/fex/config.pl')) { eval { require } or warn $@; } my $from = ''; my $to = ''; my $id = ''; my $skey = ''; my $gkey = ''; my $atype = ''; # archive type my $fexcgi; # F*EX CGI URL my @files; # files to send my %AB = (); # server based address book my ($server,$port,$sid,$https); my $proxy = ''; my $proxy_prefix = ''; my $features = ''; my $timeout = 30; # server timeout my $fexlist = "$tmpdir/fexlist"; my ($usage,$hints); my $xx = $0 =~ /\bxx$/; if ($xx) { $usage = "usage: send file(s): xx [:slot] file...\n". " or: send STDIN: xx [:slot] -\n". " or: send pipe: ... | xx [:slot] \n". " or: get file(s) or STDIN: xx [:slot] \n". " or: get file(s) no-questions: xx [:slot] --\n". "examples: dmesg | xx\n". " xx project\n". " xx --\n". " xx :conf /etc /boot\n"; } else { $usage = < 'user1\@domain1.org', 'alias2' => 'user2\@domain2.org', 'both' => 'user1\@domain1.org,user2\@domain2.org', 'extra' => 'extra\@special.net:-i other -K -k 30', ); fexsend also respects aliases in $HOME/.mutt/aliases The alias priority is (descending): \$HOME/.fex/config.pl \$HOME/.mutt/aliases fexserver address book In \$HOME/.fex/config.pl you can also set the SSL* environment variables and the \$opt_* variables, e.g.: \$ENV{SSLVERSION} = 'TLSv1'; \${'opt_+'} = 1; \$opt_m = 200; EOD } my @rcamel = ( ' _ _ c*_) / \/ \// *=( __ / \\\\/\\\\/ ', " \\\\/\\\\/ \n", " //\\\\//\\\\\n" ); my @rrcamel = ( ' (_*p _ _ \\\\/ \/ \\ \ __ )=* //\\\\//\\\\ ', " \\\\/\\\\/ \n", " //\\\\//\\\\\n" ); autoflush STDOUT; autoflush STDERR; if ($windoof and not @ARGV and not $ENV{PROMPT}) { # restart with cmd.exe to have mouse cut+paste exec qw'cmd /k',$0,'-W'; exit; } unless (-d $fexhome) { mkdir $fexhome,0700 or die "$0: cannot create FEXHOME $fexhome - $!\n"; } unless (-d $tmpdir) { mkdir $tmpdir,0700 or die "$0: cannot create tmpdir $tmpdir - $!\n"; } my @_ARGV = @ARGV; # save arguments our ($opt_q,$opt_h,$opt_H,$opt_v,$opt_m,$opt_c,$opt_k,$opt_d,$opt_l,$opt_I, $opt_K,$opt_D,$opt_u,$opt_f,$opt_a,$opt_C,$opt_R,$opt_M,$opt_L,$opt_Q, $opt_A,$opt_i,$opt_z,$opt_Z,$opt_b,$opt_P,$opt_x,$opt_X,$opt_V,$opt_U, $opt_s,$opt_o,$opt_g,$opt_F,$opt_n,$opt_r,$opt_S,$opt_N,$opt_T); if ($xx) { $opt_q = 1 if @ARGV and $ARGV[-1] eq '--' and pop @ARGV or not -t STDOUT; $opt_h = $opt_v = $opt_m = $opt_I = 0; $opt_X = ''; $_ = "$fexhome/config.pl"; require if -f; getopts('hvIm:') or die $usage; } else { if ($macos and not @ARGV) { &ask_file; } $opt_h = $opt_v = $opt_m = $opt_c = $opt_k = $opt_d = $opt_l = $opt_I = 0; $opt_H = $opt_K = $opt_D = $opt_R = $opt_M = $opt_L = $opt_Q = $opt_A = 0; $opt_x = $opt_o = $opt_g = $opt_V = $opt_U = $opt_F = $opt_n = $opt_q = 0; $opt_S = $opt_N = 0; ${'opt_@'} = ${'opt_!'} = ${'opt_+'} = ${'opt_.'} = ${'opt_/'} = 0; ${'opt_='} = ${'opt_#'} = ''; $opt_u = $opt_f = $opt_a = $opt_C = $opt_i = $opt_b = $opt_P = $opt_X = ''; $opt_s = $opt_r = $opt_T = ''; $_ = "$fexhome/config.pl"; require if -f; getopts('hHvcdognVDKlILUARWMFzZqQS@!+./r:m:k:u:f:a:s:C:i:b:P:x:X:N:T:=:#:') or die $usage; if ($opt_H) { print $hints; exit; } if ($opt_V) { print "Version: $version\n"; unless (@ARGV) { print "Upgrade fexsend? "; $_ = ||''; if (/^y/i) { my $new = `wget -nv -O- http://fex.belwue.de/download/fexsend`; my $newversion = $1 if $new =~ /version = (\d+)/; if ($new !~ /upgrade fexsend/ or not $newversion) { die "$0: bad update\n"; } if ($newversion <= $version) { die "$0: no newer version\n"; } $_0 = abs_path($_0); system qw'rsync -a',$_0,$_0.'_old'; exit $? if $?; open $_0,'>',$_0 or die "$0: cannot write $_0. - $!\n"; print {$_0} $new; close $_0; exec $_0,qw'-V .'; } } exit; exit if "@ARGV" eq '.'; } if ($opt_K and $opt_D) { die "$0: you cannot use both options -D and -K\n"; } if ($opt_a and $opt_c) { die "$0: you cannot use both options -a and -c\n"; } if ($opt_a and $opt_s) { die "$0: you cannot use both options -a and -s\n"; } if ($opt_g and $opt_c) { $opt_c = 0; } $opt_f ||= $opt_b; if ($opt_f and $opt_f !~ /^\d+$/) { die "$0: option -f needs a number, see $0 -l\n"; } if ($opt_I and $opt_R) { die "$0: you cannot use both options -I and -R\n"; } # $opt_C is COMMENT command in F*EX protocol $opt_C = ($opt_d) ? 'DELETE': ($opt_l or $opt_L) ? 'LIST': ($opt_Q) ? 'CHECKQUOTA': ($opt_S) ? 'LISTSETTINGS': ($opt_Z) ? 'RECEIVEDLOG': ($opt_z) ? 'SENDLOG': (${'opt_!'}) ? 'FOPLOG': $opt_C; $opt_D = ($opt_D) ? 'DELAY': ($opt_K) ? 'NO': $opt_D; } &get_ssl_env; if ($opt_h) { female_mode("show help?") if $opt_F; print $usage; exit; } if ($opt_R) { ®ister; exit; } die $usage if $opt_m and $opt_m !~ /^\d+/; if ($opt_P) { if ($opt_P =~ /^([\w.-]+:\d+)(:(\d+))?/) { $proxy = $1; $chunksize = $3 || 0; } else { die "$0: proxy must be: SERVER:PORT\n"; } } if ($FEXID = $ENV{FEXID}) { $FEXID = decode_b64($FEXID) if $FEXID !~ /\s/; ($fexcgi,$from,$id) = split(/\s+/,$FEXID); } else { if ($windoof and not -f $idf) { &init_id } if (open $idf,$idf) { &get_id($idf); close $idf; } } if ($xx) { # convert old idxx file if ($idf and open $idf,$idf.'xx') { &get_id($idf); close $idf; if (open $idf,'>>',$idf) { print {$idf} "\n[xx]\n", "$fexcgi\n", "$from\n", "$id\n"; close $idf; unlink $idf.'xx'; } } # special xx ID? if ($FEXXX = $ENV{FEXXX}) { $FEXXX = decode_b64($FEXXX) if $FEXXX !~ /\s/; ($fexcgi,$from,$id) = split(/\s+/,$FEXXX); } elsif (open $idf,$idf) { while (<$idf>) { if (/^\[xx\]/) { $proxy = $proxy_prefix = ''; &get_id($idf); last; } } close $idf; } } else { # alternativ ID? if ($opt_i) { $proxy = $proxy_prefix = ''; open $idf,$idf or die "$0: cannot open $idf - $!\n"; while (<$idf>) { if (/^\[$opt_i\]/) { &get_id($idf); last; } } close $idf; die "$0: no [$opt_i] in $idf\n" unless $_; } } if ($opt_I) { if ($xx) { &show_id } else { &init_id } exit; } if ($opt_T) { my ($up,$down); $usage = "usage: $0 -T MB_up[:MB_down] [fexserver]\n"; if ($opt_T =~ /^(\d+)$/) { $up = $down = $1; } elsif ($opt_T =~ /^(\d+):(\d+)$/) { $up = $1; $down = $2; } else { die $usage; } if (@ARGV) { nettest($ARGV[0],$up,$down); } elsif ($fexcgi) { nettest($fexcgi,$up,$down); } else { nettest('fex.belwue.de',$up,$down); } exit; } if (@ARGV > 1 and $ARGV[-1] =~ /(^|\/)anonymous/) { $fexcgi = $1 if $ARGV[-1] =~ s:(.+)/::; die "usage: $0 [options] file FEXSERVER/anonymous\n" unless $fexcgi; $anonymous = $from = 'anonymous'; $sid = $id = 'ANONYMOUS'; } elsif (@ARGV > 1 and $id eq 'PUBLIC') { $public = $sid = $id; } elsif (@ARGV > 1 and $ARGV[-1] =~ m{^(https?://[\w.-]+(:\d+)?/fup\?[sg]key=\w+)}) { $fexcgi = $1; $skey = $1 if $fexcgi =~ /skey=(\w+)/; $gkey = $1 if $fexcgi =~ /gkey=(\w+)/; } else { $fexcgi = $opt_u if $opt_u; if (not -e $idf and not ($fexcgi and $from and $id)) { die "$0: no ID file $idf found, use \"fexsend -I\" to create it\n"; } unless ($fexcgi) { die "$0: no FEX URL found, use \"$0 -u URL\" or \"$0 -I\"\n"; } unless ($from and $id) { die "$0: no sender found, use \"$0 -f FROM:ID\" or \"$0 -I\"\n"; } if ($fexcgi !~ /^http/) { if ($fexcgi =~ /:443/) { $fexcgi = "https://$fexcgi" } else { $fexcgi = "http://$fexcgi" } } } $server = $fexcgi; $port = 80; $port = 443 if $server =~ s{https://}{}; $port = $1 if $server =~ s/:(\d+)//; if ($port == 443) { # $opt_s and die "$0: cannot use -s with https due to stunnel bug\n"; # $opt_g and die "$0: cannot use -g with https due to stunnel bug\n"; $https = $port; } $server =~ s{http://}{}; $server =~ s{/.*}{}; # $chunksize = 4*k unless $chunksize; $chunksize *= M; if ($proxy) { if ($port == 80) { $proxy_prefix = "http://$server" } elsif ($port != 443) { $proxy_prefix = "http://$server:$port" } } # xx: special file exchange between own accounts if ($xx) { my $transferfile = "$tmpdir/STDFEX"; # slot? if ($0 eq 'xxx') { $transferfile = "$tmpdir/xx:xxx"; } elsif (@ARGV and $ARGV[0] =~ /^:([\w.=+-]+)$/) { $transferfile = "$tmpdir/xx:$1"; shift @ARGV; } open my $lock,'>>',$transferfile or die "$0: cannot write $transferfile - $!\n"; flock($lock,LOCK_EX|LOCK_NB) or die "$0: $transferfile is locked by another process\n"; truncate $transferfile,0; if (not @ARGV and -t) { &get_xx($transferfile); } else { &send_xx($transferfile); } exit; } # regular fexsend &inquire if $windoof and not @ARGV and not ($opt_l or $opt_L or $opt_Q or $opt_A or $opt_U or $opt_I or $opt_f or $opt_x or $opt_N); if (${'opt_.'}) { $opt_C = "!SHORTMAIL! $opt_C"; } if ($opt_n or $opt_C =~ /NOMAIL|!#!/) { $nomail = 'NOMAIL'; } unless ($skey or $gkey or $anonymous) { if (not $opt_q and ( $opt_f||$opt_x||$opt_Q||$opt_l||$opt_L||$opt_U||$opt_z||$opt_Z||$opt_A ||$opt_d||${'opt_!'}||${'opt_@'}) ) { warn "Server/User: $fexcgi/$from\n" } } if ($opt_V and not @ARGV) { exit } if ($opt_f) { &forward } elsif ($opt_x) { &modify } elsif ($opt_N) { &renotify } elsif ($opt_Q) { &query_quotas } elsif ($opt_S) { &query_settings } elsif ($opt_l or $opt_L) { &list } elsif ($opt_U) { &show_URL } elsif ($opt_z or $opt_Z or ${'opt_!'}) { &get_log } elsif ($opt_A) { edit_address_book($from) } elsif (${'opt_@'}) { &show_address_book } elsif ($opt_d and $anonymous) { &purge } elsif ($opt_d and $ARGV[-1] =~ /^\d+$/) { &delete_file_number } else { &send_fex } exit; # initialize ID file or show ID sub init_id { my $tag; my $proxy = ''; if ($opt_I) { $tag = shift @ARGV; die $usage if @ARGV; } $fexcgi = $from = $id = ''; unless (-d $fexhome) { mkdir $fexhome,0700 or die "$0: cannot create FEXHOME $fexhome - $!\n"; } # show ID if (not $tag and open $idf,$idf) { if ($opt_i) { while (<$idf>) { last if /^\[$opt_i\]/; } } $fexcgi = <$idf>; $from = <$idf>; $id = <$idf>; close $idf; if ($id) { chomp($fexcgi,$from,$id); $FEXID = encode_b64("$fexcgi $from $id"); if (-t STDIN) { print "# hint: to edit the ID file $idf use \"$0 -I .\" #\n"; print "export FEXID=$FEXID\n"; print "history -d \$((HISTCMD-1));history -d \$((HISTCMD-1))\n"; } else { print "FEXID=$FEXID\n"; } exit; } else { die "$0: no ID data found\n"; } } if ($tag and $tag eq '.') { exec $ENV{EDITOR}||'vi',$idf } if ($tag) { print "F*EX server URL for [$tag]: " } else { print "F*EX server URL: " } $fexcgi = ; $fexcgi =~ s/[\s\n]//g; die "you MUST provide a FEX-URL!\n" unless $fexcgi; if ($fexcgi =~ /\?/) { $from = $1 if $fexcgi =~ /\bfrom=(.+?)(&|$)/i; $id = $1 if $fexcgi =~ /\bid=(.+?)(&|$)/i; # $skey = $1 if $fexcgi =~ /\bskey=(.+?)(&|$)/i; # $gkey = $1 if $fexcgi =~ /\bgkey=(.+?)(&|$)/i; die "$0: cannot use GKEY URL in ID file\n" if $fexcgi =~ /gkey=/i; die "$0: cannot use SKEY URL in ID file\n" if $fexcgi =~ /skey=/i; $fexcgi =~ s/\?.*//; } unless ($fexcgi =~ /^[_:=\w\-\.\/\@\%]+$/) { die "\"$fexcgi\" is not a legal FEX-URL!\n"; } $fexcgi =~ s:/fup/*$::; print "proxy address (hostname:port or empty if none): "; $proxy = ; $proxy =~ s/[\s\n]//g; if ($proxy =~ /^[\w.-]+:\d+$/) { $proxy = "!$proxy"; } elsif ($proxy =~ /\S/) { die "wrong proxy address format\n"; } else { $proxy = ""; } if ($proxy) { print "proxy POST limit in MB (use 2048 if unknown): "; $_ = ; if (/(\d+)/) { $proxy .= "[$1]"; } } if ($skey) { $from = 'SUBUSER'; $id = $skey; } elsif ($gkey) { $from = 'GROUPMEMBER'; $id = $gkey; } else { unless ($from) { print "Your e-mail address as registered at $fexcgi: "; $from = ; $from =~ s/[\s\n]//g; die "you MUST provide your e-mail address!\n" unless $from; } unless ($from =~ /^[_:=\w\-\.\/\@\%\+]+$/) { die "\"$from\" is not a legal e-mail address!\n"; } unless ($id) { print "Your auth-ID for $from at $fexcgi: "; $id = ; $id =~ s/[\s\n]//g; die "you MUST provide your ID!\n" unless $id; } } if (open $idf,'>>',$idf) { print {$idf} "\n[$tag]\n" if $tag and -s $idf; print {$idf} "$fexcgi$proxy\n", "$from\n", "$id\n"; close $idf; print "data written to $idf\n"; } else { die "$0: cannot write to $idf - $!\n"; } } sub show_id { my ($fexcgi,$from,$id); if (open $idf,$idf) { $fexcgi = <$idf>; # $fexcgi = <$idf> if $fexcgi =~ /^\[.+\]/; $from = <$idf>; $id = <$idf>; while (<$idf>) { if (/^\[xx\]/) { $fexcgi = <$idf>; $from = <$idf>; $id = <$idf>; } } close $idf; die "$0: too few data in $idf" unless defined $id; chomp($fexcgi); chomp($from); chomp($id); $FEXXX = encode_b64("$fexcgi $from $id"); if (-t STDIN) { print "export FEXXX=$FEXXX\n"; print "history -d \$((HISTCMD-1));history -d \$((HISTCMD-1))\n"; } else { print "FEXXX=$FEXXX\n"; } } else { die "$0: cannot read $idf - $!\n"; } } sub register { my $fs = shift @ARGV or die $usage; my $mail = shift @ARGV or die $usage; my $port; my ($server,$user,$id); die "$0: $idf does already exist\n" if -e $idf; if ($fs =~ /^https/) { die "$0: cannot handle https at this time\n"; } $fs =~ s{^http://}{}; $fs =~ s{/.*}{}; if ($fs =~ s/:(\d+)//) { $port = $1 } else { $port = 80 } tcpconnect($fs,$port); sendheader("$fs:$port","GET $proxy_prefix/fur?user=$mail&verify=no HTTP/1.1"); http_response(); # header while (<$SH>) { s/\r//; printf "<-- $_"if $opt_v; last if /^\s*$/; } while (<$SH>) { s/\r//; printf "<-- $_"if $opt_v; if (m{http://(.*)/fup\?from=(.+)&ID=(.+)}) { $server = $1; $user = $2; $id = $3; if (open F,">$idf") { print F "$server\n", "$user\n", "$id\n"; close F; chmod 0600,$idf; print "user data written to $idf\n"; print "you can now fex!\n"; exit; } else { die "$0: cannot write to $idf - $!\n"; } } } die "$0: no account data received from F*EX server\n"; } # menu for MacOS users sub menu { my $key; my $new; local $_; system 'clear'; print "\n"; print "fexsend-$version\n"; for (;;) { if (open $idf,$idf) { $fexcgi = getline($idf) and $from = getline($idf) and $id = getline($idf); close $idf; last if $id; } &set_ID; } print "\n"; print "$from on $fexcgi\n"; print "\n"; for (;;) { print "\n"; print "[s] send a file or directory\n"; print "[u] update fexsend\n"; print "[l] change login data (user, server, auth-ID)\n"; print "[h] help\n"; print "[q] quit\n"; print "\n"; print "your choice: "; $key = ReadKey(0); if ($key eq 'q') { print "$key\n"; print "\n"; print "Type [Cmd]W to close this window.\n"; exit; } if ($key eq 'h') { print "$key\n"; print "\n". "With fexsend you can send files of any size to any e-mail address.\n". "\n". "At the recipient or file prompt [RETURN] brings you to this option menu.\n". "\n". "To send more than one file:\n". "When you enter * at the file prompt, you will be first asked for an archive name\n". "and then you can drag+drop multiple files.\n". "\n". "Do not forget to terminate each input line with [RETURN].\n". "\n". "See http://fex.rus.uni-stuttgart.de/ for more information.\n"; next; } if ($key eq 'u') { print "$key\n"; if ($0 =~ m:(^/client/|/sw/):) { print "\n"; print "use swupdate to update fexsend!\n"; next; } $new = $0.'.new'; system "curl http://fex.belwue.de/download/fexsend>".quote($new); chmod 0755,$new; system qw'perl -c',$new; if ($? == 0) { rename $new,$0; exec $0; } else { print "\n"; print "cannot install new fexsend\n"; } next; } if ($key eq 'l') { print "$key\n"; system 'clear'; &set_ID; next; } if ($key eq 's' or $key eq "\n") { print "s\n"; &ask_file; next; } } exit; } # for MacOS sub ask_file { my ($file,$comment,$recipient,$archive,$size,$cmd,$key); my @files; my $qfiles; local $_; system 'clear'; &set_ID unless -s $idf; print "\n"; print "Enter [RETURN] after each input line.\n"; print "\n"; for (;;) { print "Recipient(s): "; $recipient = ; chomp $recipient; $recipient =~ s/^\s+//; $recipient =~ s/\s+$//; $recipient =~ s/[\s;,]+/,/g; &menu unless $recipient; last if $recipient =~ /\w/ or $recipient eq '.'; } for (;;) { print "\n"; print "Drag a file into this window or hit [RETURN] "; print $archive ? "to continue.\n" : "for menu options.\n"; print "File to send: "; $file = ||''; chomp $file; $file =~ s/^\s+//; $file =~ s/ $// if $file !~ /\\ $/; &menu unless $file or $archive; if ($file eq '*') { print "Archive name: "; $archive = ||''; chomp $archive; next unless $archive; $archive =~ s/^\s+//g; $archive =~ s/\s+$//g; $archive =~ s/[^\w=.+-]/_/g; next; } if ($file) { unless (-e $file) { $file =~ s/\\\\/\000/g; $file =~ s/\\//g; $file =~ s/\000/\\/g; } unless (-r $file) { print "\"$file\" is not readable\n"; next; } my $qf = quote($file); if (`du -ms $qf` =~ /^(\d+)/) { $size += $1; printf "%d MB\n",$1; } if ($archive) { push @files,$file; next; } } if ($archive) { next unless @files; $qfiles = join(' ',map(quote($_),@files)); if ($size < 2048) { $archive .= '.zip'; } else { $archive .= '.tar'; } } print "\n"; print "Comment: "; $comment = ||''; chomp $comment; print "\n"; if ($comment =~ s/^:\s*-/-/) { $cmd = quote($0)." $comment "; if ($archive) { $cmd .= '-a '.quote($archive).' '.$qfiles; } else { $cmd .= quote($file); } $cmd .= ' '.quote($recipient); print $cmd,"\n"; system $cmd; } else { print quote($0)." -C '$comment' "; if ($archive) { printf "-a %s %s %s\n",quote($archive),$qfiles,$recipient; system $0,'-C',$comment,'-a',$archive,@files,$recipient; } else { printf "%s %s\n",quote($file),$recipient; system $0,'-C',$comment,$file,$recipient; } } print "\n"; print "[s] send another file to $recipient\n"; print "[n] send another file to another recipient\n"; print "[q] quit\n"; print "\n"; print "your choice: "; for (;;) { $key = ReadKey(0); &ask_file if $key eq 'n'; if ($key eq 's' or $key eq "\n") { print "s\n"; last; } if ($key eq 'q') { print "$key\n"; exit; } } $file = $comment = $archive = ''; @files = (); } } sub set_ID { my ($server,$port,$user,$logo); local $_; print "\n"; for (;;) { print "F*EX server URL: "; $server = ; $server =~ s/[\s\n]//g; if ($server =~ s:/fup/(\w+)$::) { $_ = decode_b64($1); if (/(from|user)=(.+)&id=(.+)/) { $user = $2; $id = $3; } } $server =~ s:/fup.*::; $server =~ s:/+$::; next if $server !~ /\w/; if ($server =~ s/^https:..// or $server =~ /:443/) { $server =~ s/:.*//; $port = 443; eval "use IO::Socket::SSL"; if ($@) { print "\nno perl SSL modules installed - cannot use https\n\n"; next; } $SH = IO::Socket::SSL->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp', %SSL ); } else { $server =~ s:^http.//::; if ($server =~ s/:(\d+)//) { $port = $1; } else { $port = 80; } $SH = IO::Socket::INET->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp', ); } unless ($SH) { print "\ncannot connect to $server:$port - $!\n\n"; next; } sendheader( "$server:$port", "GET /logo.jpg HTTP/1.0", "Connection: close", ); $_ = <$SH>||''; unless (/HTTP.1.1 200/) { print "\nbad server reply: $_\n"; next; } while (<$SH>) { last if /^\s*$/ } local $/; $logo = <$SH>||''; close $SH; if (length $logo < 9999) { print "\n$server is not a F*EX server!\n\n"; next; } open $logo,">$tmpdir/fex.jpg"; print {$logo} $logo; close $logo; last; } for (;;) { last if $user; print "Your login (e-mail address): "; $user = ; $user =~ s/[\s\n]//g; if ($user !~ /.@[\w.-]+$/) { print "\"$user\" is not a valid e-mail address!\n"; next; } } for (;;) { last if $id; print "Your auth-ID for this account: "; $id = ; $id =~ s/[\s\n]//g; } open $idf,'>',$idf or die "$0: cannot write to $idf - $!\n"; print {$idf} "$server\n", "$user\n", "$id\n"; close $idf; print "\n"; print "Login data written to $idf\n\n"; print "fexing test file to $user:\n\n"; system "$0 -o -M -C test $tmpdir/fex.jpg $user"; print "\n"; if ($? != 0) { print "fexsend failed, login data is invalid, try again\n"; &set_ID; } else { print "fexsend test succeeded!\n"; sleep 3; } } sub nettest { my $url = shift; my $up = shift; my $down = shift; my $bs = 2**16; my ($length,$t0,$t1,$t2,$tt,$tb,$tc,$B,$kBs,$bt); my $nettest = $sid = 'nettest'; $port ||= 80; if ($url =~ s:^https.//::) { $https = $port = 443; } else { $url =~ s:^http.//::; $port = $1 if $url =~ s/:(\d+)//; } $url =~ s/[\/:].*//; $server = $url; if ($up) { serverconnect($server,$port); checkrecipient($nettest,$nettest); warn "$0: send to $server:$port\n"; formdatapost( from => $nettest, to => $nettest, id => $nettest, file => $nettest, size => $up*M, comment => 'NOSTORE', ); } if ($down) { serverconnect($server,$port); warn "$0: receive from $server:$port\n"; sendheader("$server:$port","GET $proxy_prefix/ddd/$down HTTP/1.0"); $_ = <$SH>; die "$0: no response from fex server $server\n" unless $_; s/\r//; if (/^HTTP\/[\d.]+ 2/) { warn "<-- $_" if $opt_v; while (<$SH>) { s/\r//; print "<-- $_" if $opt_v; last if /^$/; $length = $1 if /^Content-Length:\s*(\d+)/i; } } else { s/HTTP\/[\d.]+ \d+ //; die "$0: bad server reply: $_"; } unless ($length) { die "$0: no Content-Length header in server reply\n"; } if (${'opt_+'}) { print $rrcamel[0]; $tc = 0; } $t0 = $t1 = $t2 = int(time); $B = 0; while ($B < $length) { $b = read $SH,$_,$bs or die "$0: cannot read after $B bytes - $!\n"; # defined($_ = <$SH>) or die "$0: cannot read after $B bytes - $!\n"; # $b = length; $B += $b; $bt += $b; $t2 = time; if (${'opt_+'} and int($t2*10)>$tc) { print $rrcamel[$tc%2+1]; $tc = int($t2*10); } if (int($t2) > $t1) { $kBs = int($bt/k/($t2-$t1)); $t1 = $t2; $bt = 0; printf STDERR "nettest: %d MB (%d%%) %d kB/s \r", int($B/M),int(100*$B/$length),$kBs; } } close $SH; $tt = $t2-$t0; $kBs = int($B/k/($tt||1)); if (${'opt_+'}) { print $rrcamel[1]; print $rrcamel[2]; } printf STDERR "nettest: %d MB in %d s = %d kB/s \n", int($B/M),$tt,$kBs; } } # read one key from terminal in raw mode sub ReadKey { my $key; local $SIG{INT} = sub { stty('reset'); exit }; stty('raw'); # loop necessary for ESXi support while (not defined $key) { $key = getc(STDIN); } stty('reset'); return $key; } sub stty { if (shift eq 'raw') { system qw'stty -echo -icanon eol',"\001"; } else { system qw'stty echo icanon eol',"\000"; } } sub send_xx { my $transferfile = shift; my $file = ''; my (@r,@tar,$dir); $SIG{PIPE} = $SIG{INT} = sub { unlink $transferfile; exit 3; }; if ($0 eq 'xxx') { @tar = qw'tar -cv' } else { @tar = qw'tar -cvz' } if (-t) { if ("@ARGV" eq '-') { # store STDIN to transfer file shelldo("cat >> $transferfile"); } elsif (@ARGV) { print "making tar transfer file $transferfile :\n"; # single file? then add this directly if (scalar @ARGV == 1) { # strip path if not ending with / if ($ARGV[0] =~ m:(.+)/(.+): and $2 !~ m:/$:) { ($dir,$file) = ($1,$2); chdir $dir or die "$0: $dir - $!\n"; } else { $file = $ARGV[0]; } if (-l $file) { shelldo(@tar,qw'--dereference -f',$transferfile,$file); } else { shelldo(@tar,'-f',$transferfile,$file); } } else { shelldo(@tar,'-f',$transferfile,@ARGV); } if ($?) { unlink $transferfile; if ($? == 2) { die "$0: interrupted making tar transfer file\n"; } else { die "$0: error while making tar transfer file\n"; } } } } else { # write input from pipe to transfer file shelldo("cat >> $transferfile"); } die "$0: no transfer file\n" unless -s $transferfile; serverconnect($server,$port); query_sid($server,$port); @r = formdatapost( from => $from, to => $from, id => $sid, file => $transferfile, comment => 'NOMAIL', autodelete => $transferfile =~ /STDFEX/ ? 'NO' : 'DELAY', ); # open P,'|w3m -T text/html -dump' or die "$0: w3m - $!\n"; # print P @r; http_response(@r); if ($transferfile =~ /:/ and $0 ne 'xxx') { if ("@r" =~ /\s(X-)?Location: (http.*)\s/) { print "wget -O- $2 | tar xvzf -\n"; } } unlink $transferfile; } sub query_quotas { my (@r,$r); local $_; female_mode("query quotas?") if $opt_F; @r = formdatapost( from => $from, to => $from, id => $sid, command => $opt_C, ); die "$0: no response from fex server $server\n" unless @r; $_ = shift @r; unless (/^HTTP.* 2/) { s:HTTP/[\d\. ]+::; die "$0: server response: $_\n"; } if (($_) = grep(/^X-Sender-Quota/,@r) and /(\d+)\s+(\d+)/) { print "sender quota (used): $1 ($2) MB\n"; } else { print "sender quota: unlimited\n"; } if (($_) = grep(/^X-Recipient-Quota/,@r) and /(\d+)\s+(\d+)/) { print "recipient quota (used): $1 ($2) MB\n"; } else { print "recipient quota: unlimited\n"; } } sub query_settings { my (@r,$r); local $_; female_mode("query settings?") if $opt_F; if ($FEXID) { print "ID data from \$FEXID\n"; } elsif (-f $idf) { print "ID data from $idf\n"; } else { die "$0: found no ID\n"; } print "server: $fexcgi\n"; print "user: $from\n"; print "auth-ID: $id\n"; print "login URL: "; &show_URL; @r = formdatapost( from => $from, to => $from, id => $sid, command => $opt_C, ); die "$0: no response from fex server $server\n" unless @r; $_ = shift @r; unless (/^HTTP.* 2/) { s:HTTP/[\d\. ]+::; die "$0: server response: $_\n"; } if (($_) = grep(/^X-Autodelete/,@r) and /:\s+(\w+)/) { print "autodelete: $1\n"; } if (($_) = grep(/^X-Default-Keep/,@r) and /(\d+)/) { print "default keep: $1 days\n"; } if (($_) = grep(/^X-Default-Locale/,@r) and /:\s+(\w+)/) { print "default locale: $1\n"; } if (($_) = grep(/^X-MIME/,@r) and /:\s+(\w+)/) { print "display file with browser: $1\n"; } if (($_) = grep(/^X-Sender-Quota/,@r) and /(\d+)\s+(\d+)/) { print "sender quota (used): $1 ($2) MB\n"; } else { print "sender quota: unlimited\n"; } if (($_) = grep(/^X-Recipient-Quota/,@r) and /(\d+)\s+(\d+)/) { print "recipient quota (used): $1 ($2) MB\n"; } else { print "recipient quota: unlimited\n"; } } # list spool sub list { my (@r,$r); my ($data,$dkey); my $n = 0; my $s = 1; my $a = shift @ARGV || '.'; local $_; female_mode("list spooled files?") if $opt_F; if ($opt_l) { if ($a =~ /^\d+$/) { open $fexlist,$fexlist or die "$0: $fexlist - $!\n"; while (<$fexlist>) { if (/^\s*(\d+)\) (\w+) (.+)/ and $1 eq $a) { serverconnect($server,$port) unless $SH; sendheader( "$server:$port", "GET $proxy_prefix/fop/$2/$2?LIST HTTP/1.1", ); $_ = <$SH>||''; s/\r//; print "<-- $_" if $opt_v; if (/^HTTP.* 200/) { print "<-- $_" if $opt_v; while (<$SH>) { s/\r//; if (/^\n/) { print; print while <$SH>; } } } elsif (s:HTTP/[\d\. ]+::) { die "$0: server response: $_"; } else { die "$0: no response from fex server $server\n"; } exit; } } die "$0: file \#$a not found in fexlist\n"; } } @r = formdatapost( from => $from, to => $opt_l ? '*' : $from, command => $opt_C, ); die "$0: no response from fex server $server\n" unless @r; $_ = shift @r; unless (/^HTTP.* 200/) { s:HTTP/[\d\. ]+::; die "$0: server response: $_\n"; } # list sent files if ($opt_l) { open $fexlist,">$fexlist" or die "$0: cannot write $fexlist - $!\n"; foreach (@r) { next unless /
/ or $data;
      $data = 1;
      last if m:
:; if (//) { $dkey = $1 } else { $dkey = '' } # $_ = encode_utf8($_); s/<.*?>//g; s/&/&/g; s/"/\"/g; s/<// or $data; $data = 1; next if m:
:;
      last if m:
:; if (/(from .* :)/) { print "\n$1\n"; } if (m{(\d+) (MB.*)
(.+)( ".*")?}) { printf "%8d %s%s%s\n",$1,$2,$3,($5||''); } } } } sub show_URL { printf "%s/fup/%s\n",$fexcgi,encode_b64("from=$from&id=$id"); } sub get_log { my (@r); local $_; @r = formdatapost( from => $from, to => $from, id => $sid, command => $opt_C, ); die "$0: no response from fex server $server\n" unless @r; $_ = shift @r; unless (/^HTTP.* 200/) { s:HTTP/[\d\. ]+::; die "$0: server response: $_\n"; } while (shift @r) {} foreach (@r) { print "$_\n" } } sub show_address_book { my (%AB,@r); my $alias; local $_; %AB = query_address_book($server,$port,$from); foreach $alias (sort keys %AB) { next if $alias eq 'ADDRESS_BOOK'; $_ = sprintf "%s = %s (%s) # %s\n", $alias, $AB{$alias}, $AB{$alias}->{options}, $AB{$alias}->{comment}; s/ \(\)//; s/ \# $//; print; } } sub purge { die "$0: not yet implemented\n"; } sub delete_file_number { my ($to,$file); while (@ARGV) { $opt_d = shift @ARGV; die "usage: $0 -d #\n" if $opt_d !~ /^\d+$/; open $fexlist,$fexlist or die "$0: $fexlist - $!\n"; while (<$fexlist>) { if (/^to (.+\@.+) :/) { $to = $1; } elsif (/^\s*(\d+)\) (\w+) (.+)/ and $1 eq $opt_d) { serverconnect($server,$port) unless $SH; sendheader( "$server:$port", "GET $proxy_prefix/fop/$2/$2?DELETE HTTP/1.1", ); $_ = <$SH>||''; s/\r//; print "<-- $_" if $opt_v; if (/^HTTP.* 200/) { while (<$SH>) { s/\r//; last if /^\n/; # ignore HTML output print "<-- $_" if $opt_v; if (/^X-File:.*\/(.+)/) { printf "%s deleted\n",decode_utf8(urldecode($1)); } } undef $SH; } elsif (s:HTTP/[\d\. ]+::) { die "$0: server response: $_"; } else { die "$0: no response from fex server $server\n"; } last; } } close $fexlist; sleep 1; # do not overrun server } exit; } sub delete_file { my ($from,$to,$file) = @_; local $_; unless ($SH) { serverconnect($server,$port); query_sid($server,$port) unless $anonymous; } $file = urlencode($file); sendheader( "$server:$port", "GET $proxy_prefix/fop/$to/$from/$file?id=$sid&DELETE HTTP/1.1", ); while (<$SH>) { s/\r//; printf "<-- $_"if $opt_v; last if /^\s*$/; } } sub urlencode { local $_ = shift; s/([^_=:,;<>()+.\w\-])/'%'.uc(unpack("H2",$1))/ge; return $_; } sub send_fex { my @to; my $file = ''; my @files = (); my ($data,$aname,$alias); my (@r,$r); my $t0 = time; my $transferfile; my @transferfiles; local $_; if ($from =~ /^SUBUSER|GROUPMEMBER$/) { $to = '_'; } else { # look for single @ in arguments for (my $i=1; $i<$#ARGV; $i++) { if ($ARGV[$i] eq '@') { $ARGV[$i] = join(',',@ARGV[$i+1 .. $#ARGV]); $#ARGV = $i; last; } } $to = pop @ARGV or die $usage; if ($to eq '.') { $to = $from; $nomail = $opt_C ||= 'NOMAIL'; } if ($to eq ':') { $to = $from; $nomail = $opt_C ||= 'NOMAIL'; } if ($opt_g and $to =~ /,/) { die "$0: encryption is supported to only one recipient\n"; } if ($to =~ m{^https?://.*/fup\?skey=(\w+)}) { $from = 'SUBUSER'; $to = '_'; $id = $1; } if ($to =~ m{^https?://.*/fup\?gkey=(\w+)}) { $from = 'GROUPMEMBER'; $to = '_'; $id = $1; } } @to = split(',',lc($to)); die $usage unless @ARGV or $opt_a or $opt_s; die $usage if $opt_s and @ARGV; # early serverconnect necessary for X-Features info serverconnect($server,$port); if ($anonymous) { my $aok; sendheader("$server:$port","OPTIONS /FEX HTTP/1.1"); $_ = <$SH>||''; s/\r//; die "$0: no response from fex server $server\n" unless $_; print "<-- $_" if $opt_v; if (/^HTTP.* 201/) { while (<$SH>) { s/\r//; print "<-- $_" if $opt_v; last unless /\w/; $aok = $_ if /X-Features:.*ANONYMOUS/; } die "$0: no anonymous support on server $server\n" unless $aok; } else { die "$0: bad response from server $server : $_\n"; } } elsif ($public) { } else { query_sid($server,$port); if ($from eq 'SUBUSER') { $skey = $sid; # die "skey=$skey\nid=$id\nsid=$sid\n"; } if ($from eq 'GROUPMEMBER') { $gkey = $sid; } if ($to eq '.') { @to = ($from); $opt_C ||= 'NOMAIL'; } elsif ($to =~ m:^(//.*):) { my $xkey = $1; if ($features =~ /XKEY/) { @to = ($from); $opt_C = $xkey; } else { die "$0: server does not support XKEY\n"; } } elsif (grep /^[^@]*$/,@to and not $skey and not $gkey) { %AB = query_address_book($server,$port,$from); if ($proxy) { serverconnect($server,$port); query_sid($server,$port); } foreach $to (@to) { # alias in local config? if ($alias{$to}) { if ($alias{$to} =~ /(.+?):(.+)/) { my $ato = $1; my $opt = $2; my @argv = @_ARGV; pop @argv; # special extra upload system $0,split(/\s/,$opt),@argv,$ato; $to = ''; } else { $to = $alias{$to}; } } # alias in server address book? elsif ($AB{$to}) { # do not substitute alias with expanded addresses because then # keep and autodelete options from address book will get lost # $to = $AB{$to}; } # look for mutt aliases elsif ($to !~ /@/ and $to ne $from) { $to = get_mutt_alias($to); } } } $to = join(',',grep /./,@to) or exit; # warn "Server/User: $fexcgi/$from\n" unless $opt_q; if ( not $skey and not $gkey and $from ne $to and $features =~ /CHECKRECIPIENT/ and $opt_C !~ /^(DELETE|LIST|RECEIVEDLOG|SENDLOG|FOPLOG)$/ ) { checkrecipient($from,$to); if ($proxy) { serverconnect($server,$port); query_sid($server,$port); } } } if (@ARGV > 1 and not ($opt_a or $opt_s or $opt_d)) { print "Archive name (name.tar, name.tgz or name.zip) or [RETURN] to send file for file:\n"; $opt_a = ; $opt_a =~ s/^\s+//; $opt_a =~ s/\s+$//; $opt_a =~ s/\//_/g; } if ($macos and not $opt_a and -d "@ARGV") { my $dir = "@ARGV"; my $qdir = quote($dir); if (`du -s $qdir` =~ /^(\d+)/ and $1 < 2**21) { $opt_a = "$dir.zip"; } else { $opt_a = "$dir.tar"; } } if ($opt_s) { $opt_s =~ s/^=//; $opt_s =~ s:.*/::; $opt_s =~ s/[^\w_.+-]/_/g; @files = ($opt_s); } elsif ($opt_a) { $opt_a =~ s/^=//; $opt_a =~ s:.*/::; $opt_a =~ s/[^\w_.+-]/_/g; if ($opt_a =~ /(.+)\.(zip|tar|tgz|7z)$/) { $aname = $1; $atype = $2; } else { die "$0: archive name must be one of ". "$opt_a.tar $opt_a.tgz $opt_a.zip\n"; } # no file argument left? unless (@ARGV) { # use file name as archive name push @ARGV,$aname; $opt_a =~ s:/+$::g; $opt_a =~ s:.*/::g; } foreach my $file (@ARGV) { die "$0: cannot read \"$file\"\n" unless -l $file or -r $file; } $opt_a .= ".$atype" if $opt_a !~ /\.$atype$/; $transferfile = "$tmpdir/$opt_a"; unlink $transferfile; print "Making fex archive ($opt_a):\n"; if ($atype eq 'zip') { if ($windoof) { # if ($opt_c) { system(qw'7z a -tzip',$transferfile,@ARGV) } # else { system(qw'7z a -tzip -mm=copy',$transferfile,@ARGV) } system(qw'7z a -tzip',$transferfile,@ARGV); @files = ($transferfile); } elsif ($macos and scalar(@ARGV) == 1) { ## ditto-zip is now handled by formdatapost() system 'true'; @files = ($opt_a); } else { # zip archives must be < 2 GB, so split as necessary @files = zipsplit($transferfile,@ARGV); if (scalar(@files) == 1) { $transferfile = $files[0]; $transferfile =~ s/_1.zip$/.zip/; rename $files[0],$transferfile; @files = ($transferfile); } } @transferfiles = @files; } elsif ($atype eq '7z') { # http://www.7-zip.org/ my @X = (); # exclude list if (${'opt_#'}) { foreach my $x (split('#',${'opt_#'})) { push @X,"-x!$x"; } } if ($opt_c) { system(qw'7z a',@X,$transferfile,@ARGV) } else { system(qw'7z a -t7z -mx0',@X,$transferfile,@ARGV) } @transferfiles = @files = ($transferfile); } elsif ($atype eq 'tar') { if ($windoof) { system(qw'7z a -ttar',$transferfile,@ARGV); @transferfiles = @files = ($transferfile); } else { ## tar is now handled by formdatapost() # system(qw'tar cvf',$transferfile,@ARGV); system 'true'; @files = ($opt_a); } } elsif ($atype eq 'tgz') { if ($windoof) { die "$0: archive type tgz not available, use tar, zip or 7z\n"; } else { ## tgz is now handled by formdatapost() # system(qw'tar cvzf',$transferfile,@ARGV); @files = ($opt_a); } } else { die "$0: unknown archive format \"$atype\"\n"; } if (@transferfiles) { # error in making transfer archive? if ($?) { unlink @transferfiles; die "$0: $! - aborting upload\n"; } # maybe timeout, so make new connect if (time-$t0 >= $timeout) { serverconnect($server,$port); query_sid($server,$port) unless $anonymous; } } } else { unless (@ARGV) { if ($windoof) { &inquire; } else { die $usage; } } foreach (@ARGV) { my $file = $_; unless ($opt_d) { unless (-f $file) { if (-e $file) { die "$0: \"$file\" is not a regular file, try option -a\n" } else { die "$0: \"$file\" does not exist\n"; } } die "$0: cannot read \"$file\"\n" unless -r $file; } push @files,$file; } } if (${'opt_/'}) { foreach my $file (@files) { my @s = stat($file); unless (@s and ($s[2] & S_IROTH) and -r $file) { die "$0: \"$file\" is not world readable\n"; } } } foreach my $file (@files) { sleep 1; # do not overrun server! unless (-s $file or $opt_d or $opt_a or $opt_s) { die "$0: cannot send empty file \"$file\"\n"; } female_mode("send file $file?") if $opt_F; @r = formdatapost( from => $from, to => $to, replyto => $opt_r, id => $sid, file => $file, keep => $opt_k, comment => $opt_C, autodelete => $opt_D, ); if (not @r or not grep /\w/,@r) { die "$0: no response from server\n"; } next if "@r" eq '0'; # already transfered if (($r) = grep /^ERROR:/,@r) { if ($anonymous and $r =~ /purge it/) { die "$0: file is already on server for $to - use another anonymous recipent\n"; } elsif ($r =~ /timeout/i) { close $SH; retry("timed out"); } else { $r =~ s/.*?:\s*//; $r =~ s/<.+?>//g; die "$0: server error: $r\n"; } } unless ($opt_d) { if (scalar(@r) == 1) { die "$0: server error: @r\n"; } else { if ($r[0] !~ /HTTP.1.. 2/) { if ($r[0] =~ /HTTP.[\s\d.]+(.+)/) { die "$0: server error: $1\n"; } else { die "$0: server error:\n".join("\n",@r)."\n"; } } } } if (($r) = grep /

\Q$file/,@r) { $r =~ s/<.+?>//g; print "$r\n"; } if ($opt_a !~ /^afex_\d+\.tar$/ and $file !~ /afex_\d+\.tar$/) { # print grep({s/^(X-Recipient:.*\((.+)\))/Parameters: $2\n/i} @r); my $nonot = 0; my $recipient = ''; my $location = ''; foreach (@r) { if (/^(X-)?(Recipient.*)/i) { $recipient = $2; if (/notification=no/i) { $nonot = 1 } else { $nonot = 0 } } if (/^(X-)?(Location.*)/i) { $location = $2; } } if ($from eq $to or $from =~ /^\Q$to\E@/i or $nomail or $anonymous or $nonot) { print "$recipient\n" if $recipient; print "$location\n" if $location; } } } # delete transfer tmp file unlink $transferfile if $transferfile; } sub forward { my (@r); my ($to,$n,$dkey,$file,$req); my ($status,$fp); local $_; # look for single @ in arguments for (my $i=1; $i<$#ARGV; $i++) { if ($ARGV[$i] eq '@') { $ARGV[$i] = join(',',@ARGV[$i+1 .. $#ARGV]); $#ARGV = $i; last; } } # if ($windoof and not @ARGV) { &inquire } $to = pop @ARGV or die $usage; $to = $from if $to eq '.'; if ($to !~ /@/ and $to ne $from) { $to = get_mutt_alias($to); } open $fexlist,$fexlist or die "$0: $fexlist - $!\n"; while (<$fexlist>) { if (/^\s*(\d+)\) (\w+) .\s*\d+ d. ([+-] )?(.+)/ and $1 eq $opt_f) { $n = $1; $dkey = $2; $file = $4; if ($file =~ s/ "(.*)"$//) { $opt_C ||= $1 if $1 ne 'NOMAIL'; } last; } } close $fexlist; unless ($n) { die "$0: file #$opt_f not found in fexlist\n"; } female_mode("forward file #$opt_f?") if $opt_F; serverconnect($server,$port); query_sid($server,$port); $req = "GET $proxy_prefix/fup?" ."from=$from&ID=$sid&to=$to&dkey=$dkey&command=FORWARD"; $req .= "&comment=$opt_C" if $opt_C; $req .= "&keep=$opt_k" if $opt_k; $req .= "&autodelete=$opt_D" if $opt_D; $req .= "&$opt_X" if $opt_X; $req .= " HTTP/1.1"; sendheader("$server:$port",$req); http_response(); $fp = $file; $fp =~ s/[^\w_.-]/.+/g; # because of UTF8 filename $status = 1; while (<$SH>) { $status = 0 if /"$fp"/; print if $opt_v or /"$fp"/; } if ($status) { die "$0: server failed, rerun command with option -v\n"; } exit; } sub renotify { my (@r); my ($to,$n,$dkey,$file,$req,$recipient); local $_; die $usage if @ARGV; open $fexlist,$fexlist or die "$0: $fexlist - $!\n"; while (<$fexlist>) { if (/^\s*(\d+)\) (\w+) .\s*\d+ d. (.+)/ and $1 eq $opt_N) { $n = $1; $dkey = $2; last; } } close $fexlist; unless ($n) { die "$0: file #$opt_N not found in fexlist\n"; } female_mode("resend notification for file #$opt_N?") if $opt_F; serverconnect($server,$port); query_sid($server,$port); $req = "GET $proxy_prefix/fup?" ."from=$from&ID=$sid&dkey=$dkey&command=RENOTIFY" ." HTTP/1.1"; sendheader("$server:$port",$req); http_response(); while (<$SH>) { s/\r//; print "<-- $_" if $opt_v; last if /^\s*$/; if (/^X-Notify: (.+)\/(.+)\/(.+)/) { $recipient = $1; $file = $3; } } if ($file) { print "notification e-mail for $file has been resent to $recipient\n"; } else { if ($opt_v) { die "$0: server failed\n"; } else { die "$0: server failed, rerun command with option -v\n"; } } exit; } sub modify { my (@r); my ($n,$dkey,$file,$req); local $_; die $usage if @ARGV; die $usage unless $opt_C or $opt_k or $opt_D; open $fexlist,$fexlist or die "$0: $fexlist - $!\n"; while (<$fexlist>) { if (/^\s*(\d+)\) (\w+) .\s*\d+ d. (.+)/ and $1 eq $opt_x) { $n = $1; $dkey = $2; $file = $3; $file =~ s/ "(.*)"$//; last; } } close $fexlist; unless ($n) { die "$0: file #$opt_x not found in fexlist\n"; } female_mode("modify file #$opt_x?") if $opt_F; serverconnect($server,$port); query_sid($server,$port); $req = "GET $proxy_prefix/fup?" ."from=$from&ID=$sid&dkey=$dkey&command=MODIFY"; $req .= "&comment=$opt_C" if $opt_C; $req .= "&keep=$opt_k" if $opt_k; $req .= "&autodelete=$opt_D" if $opt_D; $req .= " HTTP/1.1"; sendheader("$server:$port",$req); http_response(); while (<$SH>) { if ($opt_v) { print "<-- $_"; } else { print if /\Q$file/; } } exit; } sub get_xx { my $transferfile = shift; my $ft = ''; local $_; # get transfer file from FEX server unless ($SH) { serverconnect($server,$port); query_sid($server,$port); } xxget($from,$sid,$transferfile); # empty file? unless (-s $transferfile) { unlink $transferfile; exit; } # no further processing if delivering to pipe exec 'cat',$transferfile unless -t STDOUT; if ($ft = `file $transferfile 2>/dev/null`) { if ($ft =~ /compressed/) { rename $transferfile,"$transferfile.gz"; shelldo(ws("gunzip $transferfile.gz")); } $ft = `file $transferfile`; } # file command failed, so we look ourself into the file... elsif (open $transferfile,$transferfile) { read $transferfile,$_,4; close $transferfile; # gzip magic? if (/\x1F\x8B\x08\x00/) { rename $transferfile,"$transferfile.gz"; shelldo(ws("gunzip $transferfile.gz")); # assuming tar $ft = 'tar archive'; } } if ($ft =~ /tar archive/) { rename $transferfile,"$transferfile.tar"; $transferfile .= '.tar'; if ($opt_q) { $_ = 'y'; } else { print "Files in transfer-container:\n\n"; shelldo(ws("tar tvf $transferfile")); print "\nExtract these files? [Yn] "; $_ = ; } if (/^n/i) { print "keeping $transferfile\n"; } else { my $untar = "tar xvf"; # if ($> == 0 and `tar --help 2>&1` =~ /gnu/) { # $untar = "tar --no-same-owner -xvf"; # } system("$untar $transferfile && rm $transferfile"); die "$0: error while untaring, see $transferfile\n" if -f $transferfile; } } else { exec 'cat',$transferfile; } exit; } sub formdatapost { my %P = @_; my ($boundary,$filename,$length,$buf,$file,$fpsize,$resume,$seek,$nettest); my ($flink); my (@hh,@hb,@r,@pv,$to); my ($bytes,$b,$t,$bt); my ($t0,$t1,$t2,$tt,$tc); my $bs = 2**16; # blocksize for reading and sending file my $fileid = int(time); my $chunk = 0; my $filesize = 0; my $connection = ''; my $pct = ''; my $dittodir = '.'; my ($tar,$ditto,$aname,$atype,$list,$error,$location,$transferfile); local $_; if (defined($file = $P{file})) { $to = $AB{$P{to}} || $P{to}; # for gpg # special file: stream from STDIN if ($opt_s) { $filename = encode_utf8($file); $filesize = -1; } # compression? if ($opt_c) { my ($if,$of); $if = $file; $if =~ s/([^_\w\.\-])/\\$1/g; $transferfile = $tmpdir . '/' . basename($file) . '.gz'; $of = $transferfile; $of =~ s/([^_\w\.\-])/\\$1/g; shelldo("gzip <$if>$of"); $filesize = -s $transferfile; die "$0: cannot gzip \"$file\"\n" unless $filesize; $file = $transferfile; } # special file: tar-on-the-fly if (not $windoof and $opt_a and $file =~ /(.+)\.(tar|tgz)$/) { $aname = $1; $atype = $2; $list = "$tmpdir/$aname.list"; $error = "$tmpdir/$aname.error"; $tar = 'tar -cv'; $tar .= 'z' if $atype eq 'tgz'; if (`tar --help 2>/dev/null` =~ /--index-file/) { $tar .= " --index-file=$list -f-"; } else { $tar .= " -f-"; } if (${'opt_#'}) { foreach my $x (split('#',${'opt_#'})) { $tar .= " --exclude=$x"; } } foreach (@ARGV) { $tar .= ' '.quote($_); } # print "calculating archive size... "; open $tar,"$tar 2>$error|" or die "$0: cannot run tar - $!\n"; $t0 = int(time) if -t STDOUT; while ($b = read $tar,$_,$bs) { $filesize += $b; if ($t0) { $t1 = int(time); if ($t1>$t0) { printf "Archive size: %d MB\r",int($filesize/M); $t0 = $t1; } } } printf "Archive size: %d MB\n",int($filesize/M) if -t STDOUT; unless (close $tar) { $_ = ''; if (open $error,$error) { local $/; $_ = <$error>; close $error; } unlink $list,$error; die "$0: tar error:\n$_"; } $file = "$aname.$atype"; $filename = encode_utf8($file); undef $SH; # force reconnect (timeout!) } # special file: ditto-zip-on-the-fly # ditto: Can't archive multiple sources elsif ($macos and $opt_a and $file =~ /(.+)\.(zip)$/ and scalar(@ARGV) == 1) { $aname = $1; $atype = $2; $list = "$tmpdir/$aname.list"; $error = "$tmpdir/$aname.error"; $ditto = 'ditto -c -k --sequesterRsrc --keepParent'; if (-d "@ARGV" and "@ARGV" =~ m:^(.+)/(.+):) { $dittodir = $1; $file = $2; $file =~ s/([^\w\-\@\#%,.=+_:])/\\$1/g; $ditto .= ' '.$file; } else { foreach (@ARGV) { $file = $_; $file =~ s/([^\w\-\@\#%,.=+_:])/\\$1/g; $ditto .= ' '.$file; } } # print "calculating archive size... "; debug("cd $dittodir;$ditto -"); open $ditto,"cd $dittodir;$ditto - 2>$error|" or die "$0: cannot run ditto - $!\n"; $t0 = int(time) if -t STDOUT; while ($b = read $ditto,$_,$bs) { $filesize += $b; if ($t0) { $t1 = int(time); if ($t1>$t0) { printf "Archive size: %d MB\r",int($filesize/M); $t0 = $t1; } } } printf "Archive size: %d MB\n",int($filesize/M) if -t STDOUT; unless (close $ditto) { $_ = ''; if (-s $error and open $error,$error) { local $/; $_ = <$error>; close $error; } unlink $list,$error; die "$0: ditto-zip error:\n$_"; } unlink $list,$error; $file = "$aname.$atype"; $filename = encode_utf8($file); undef $SH; # force reconnect (timeout!) } elsif ($P{to} eq 'nettest') { $filename = $nettest = 'nettest'; $filesize = $P{size}; $fileid = 0; } # single file else { $filename = encode_utf8(${'opt_='} || $file); if ($windoof) { $filename =~ s/^[a-z]://; $filename =~ s/.*\\//; } $filename =~ s:.*/::; $filename =~ s:[\r\n]+: :g; if ($opt_d) { $filesize = 0; } elsif (not $opt_g and not $opt_s) { $filesize = -s $file or die "$0: \"$file\" is empty or not readable\n"; } } $filename .= '.gpg' if $opt_g; unless ($opt_d or $nettest) { if ($opt_g) { $filesize = -1; $fileid = int(time); } else { if ($opt_a) { $fileid = md5_hex(fmd(@ARGV)); } else { $fileid = fileid($file); } } } } else { $file = $filename = ''; $filesize = 0; } FORMDATAPOST: @hh = (); # HTTP header @hb = (); # HTTP body @r = (); $seek = 0; $resume = ''; $chunk++; unless ($SH) { serverconnect($server,$port); query_sid($server,$port) unless $anonymous or $nettest; } $P{id} = $sid; # ugly hack! $filename =~ s/\\/_/g; # \ is a illegal character for fexsrv # ask server if this file has been already sent if ($file and not $xx and not $nettest) { if (not $opt_d and $opt_o) { # delete before overwrite delete_file($from,$to,$filename); serverconnect($server,$port); query_sid($server,$port) unless $anonymous; $P{id} = $sid; # ugly hack! } elsif (not($opt_s or $opt_g or $opt_d or $opt_l or $opt_L or ${'opt_/'})) { ($seek,$location) = query_file($server,$port, $frecipient||$P{to},$P{from},$P{id},$filename,$fileid); if ($filesize == $seek) { print "Location: $location\n" if $location and $nomail; warn "$0: $file has been already transferred\n"; return 0; } elsif ($seek and $seek < $filesize) { $resume = " (resuming at byte $seek)"; } elsif ($filesize <= $seek) { $seek = 0; } } if ($proxy) { sleep 1; # do not overrun proxy serverconnect($server,$port); } } # file part size if ($chunksize and $proxy and $port != 443 and $filesize - $seek > $chunksize - $bs) { if ($features !~ /MULTIPOST/) { die sprintf("$0: server does not support chunked multi-POST needed for" ." files > %d MB via proxy\n",$chunksize/M); } $opt_o = 0; # no overwriting mode for next chunks $fpsize = $chunksize - $bs; } else { $fpsize = $filesize - $seek; } $boundary = randstring(48); $P{seek} = $seek; $P{filesize} = $filesize; # send HTTP POST variables if ($skey) { $P{skey} = $skey; @pv = qw'from to skey keep autodelete comment seek filesize'; } elsif ($gkey) { $P{gkey} = $gkey; @pv = qw'from to gkey keep autodelete comment seek filesize'; } else { @pv = qw'from to id replyto keep autodelete comment command seek filesize'; } foreach my $v (@pv) { if ($P{$v}) { my $name = uc($v); push @hb,"--$boundary"; push @hb,"Content-Disposition: form-data; name=\"$name\""; push @hb,""; # push @hb,encode_utf8($P{$v}); push @hb,$P{$v}; } } # at last, POST the file if ($file) { push @hb,"--$boundary"; push @hb,"Content-Disposition: form-data; name=\"FILE\"; filename=\"$filename\""; unless ($opt_d) { if ($opt_M) { push @hb,"Content-Type: application/x-mime" } else { push @hb,"Content-Type: application/octet-stream" } if (${'opt_/'}) { $flink = abs_path($file); push @hb,"Content-Location: $flink"; } else { # push @hb,"Content-Length: " . ((-s $file||0) - $seek); # optional header! push @hb,"Content-Length: $fpsize"; # optional header! NOT filesize! push @hb,"X-File-ID: $fileid"; } push @hb,""; } push @hb,""; # prevent proxy chunked mode reply $connection = "close"; } push @hb,"--$boundary--"; if ($fpsize < 0) { $length = $fpsize; } else { $length = length(join('',@hb)) + scalar(@hb)*2 + $fpsize; } if ($file and not $opt_d) { if ($flink) { $hb[-2] = $flink } else { $hb[-2] = '(file content)' } } # any other extra URL arguments my $opt_X = ''; $opt_X = "?$::opt_X" if $::opt_X and $file; # HTTP header push @hh,"POST $proxy_prefix/fup$opt_X HTTP/1.1"; push @hh,"Host: $server:$port"; push @hh,"User-Agent: $useragent"; push @hh,"Content-Length: $length"; push @hh,"Content-Type: multipart/form-data; boundary=$boundary"; push @hh,"Connection: $connection" if $connection; push @hh,''; if ($opt_v) { print "--> $_\n" foreach (@hh,@hb); } $SIG{PIPE} = \&sigpipehandler; # foreach $sig (keys %SIG) { # eval '$SIG{$sig} = sub { print "\n!!! SIGNAL '.$sig.' !!!\n"; exit; }'; # } if ($file) { pop @hb; pop @hb unless $flink; nvtsend(@hh,@hb) or do { warn "$0: server has closed the connection, reconnecting...\n"; sleep 3; goto FORMDATAPOST; # necessary: new $sid ==> new @hh }; unless ($opt_d or $flink) { $t0 = $t2 = int(time); $tt = $t0-1; $t1 = 0; $tc = 0; if ($opt_s) { if ($opt_g) { open $file,"gpg -e -r $to|" or die "$0: cannot run gpg - $!\n"; } else { open $file,'>&=STDIN' or die "$0: cannot open STDIN - $!\n"; } } elsif ($tar) { if ($opt_g) { open $file,"$tar|gpg -e -r $to|" or die "$0: cannot run tar&gpg - $!\n"; } else { open $file,"$tar|" or die "$0: cannot run tar - $!\n"; } if (-t STDOUT) { $tpid = fork(); if (defined $tpid and $tpid == 0) { sleep 1; if (open $list,$list) { # print "\n$tar|\n"; system "ls -l $list"; while ($list) { while (<$list>) { print ' 'x(length($file)+40),"\r",$_; } sleep 1; } } exit; } $SIG{CHLD} = 'IGNORE'; } if ($seek) { print "Fast forward to byte $seek (resuming)\n"; readahead($file,$seek); } } elsif ($ditto) { $ditto =~ s/ditto/ditto -V/; open $file,"cd $dittodir;$ditto -|" or die "$0: cannot run ditto - $!\n"; if ($seek) { print "Fast forward to byte $seek (resuming)\n"; readahead($file,$seek); } } elsif ($nettest) { # } else { if ($opt_g) { my $fileq = quote($file); open $file,"gpg -e -r $to <$fileq|" or die "$0: cannot run gpg - $!\n"; } else { open $file,$file or die "$0: cannot read \"$file\" - $!\n"; seek $file,$seek,0; } binmode $file; } $bytes = 0; autoflush $SH 0; print $rcamel[0] if ${'opt_+'}; $buf = '#' x $bs if $nettest; $SIG{ALRM} = sub { retry("timed out") }; while ($bytes < $fpsize) { if ($nettest) { $b = $bs; } else { $b = read $file,$buf,$bs; last if $b == 0; } alarm($timeout*2); if ($https) { print {$SH} $buf or &sigpipehandler; } else { syswrite $SH,$buf or &sigpipehandler; } alarm(0); $bytes += $b; if (not $nettest and $filesize > 0 and $bytes+$seek > $filesize) { if ($tpid) { kill 9,$tpid; unlink $list; } die "$0: \"$file\" filesize has grown while uploading\n"; } $bt += $b; $t2 = time; if (${'opt_+'} and int($t2*10)>$tc) { print $rcamel[$tc%2+1]; $tc = int($t2*10); } if (not $opt_q and -t STDOUT and int($t2)>$t1) { &sigpipehandler unless $SH->connected; # smaller block size is better on slow links $bs = 4096 if $t1 and $bs>4096 and $bytes/($t2-$t0)<65536; if ($filesize > 0) { $pct = sprintf "(%d%%)",int(($bytes+$seek)/$filesize*100); } if ($bytes>2*M and $bs>4096) { printf STDERR "%s: %d MB of %d MB %s %d kB/s \r", $opt_s||$opt_a||$file, int(($bytes+$seek)/M), int($filesize/M), $pct, int($bt/k/($t2-$tt)); } else { printf STDERR "%s: %d kB of %d MB %s %d kB/s \r", $opt_s||$opt_a||$file, int(($bytes+$seek)/k), int($filesize/M), $pct, int($bt/k/($t2-$tt)); } $t1 = $t2; # time window for transfer rate calculation if ($t2-$tt>10) { $bt = 0; $tt = $t2; } } last if $filesize > 0 and $bytes >= $fpsize; sleep 1 while ($opt_m and $bytes/k/(time-$t0||1) > $opt_m); } close $file unless $nettest; $tt = ($t2-$t0)||1; print $rcamel[2] if ${'opt_+'}; # terminate tar verbose output job if ($tpid) { sleep 2; kill 9,$tpid; unlink $list; } if ($fileid =~ /[a-z]/ and not ($opt_s or $opt_g)) { if ($opt_a) { if ($fileid ne md5_hex(fmd(@ARGV))) { print "\n" unless $opt_q; die "$0: files have been modified while uploading\n"; } } else { if ($fileid ne fileid($file)) { print "\n" unless $opt_q; die "$0: file has been modified while uploading\n"; } } } unless ($opt_q) { if (not $chunksize and $bytes+$seek < $filesize) { die "$0: \"$file\" filesize has shrunk while uploading\n"; } if ($seek or $chunksize and $chunksize < $filesize) { if ($fpsize>2*M) { printf STDERR "%s: %d MB in %d s = %d kB/s", $opt_s||$opt_a||$file, int($bytes/M), $tt, int($bytes/k/$tt); if ($bytes+$seek == $filesize) { printf STDERR ", total %d MB\n",int($filesize/M); } else { printf STDERR ", chunk #%d : %d MB\n", $chunk,int(($bytes+$seek)/M); } } else { printf STDERR "%s: %d kB in %d s = %d kB/s", $opt_s||$opt_a||$file, int($bytes/k), $tt, int($bytes/k/$tt); if ($bytes+$seek == $filesize) { printf STDERR ", total %d kB\n",int($filesize/k); } else { printf STDERR ", chunk #%d : %d kB\n", $chunk,int(($bytes+$seek)/k); } } } else { if ($bytes>2*M) { printf STDERR "%s: %d MB in %d s = %d kB/s \n", $opt_s||$opt_a||$file, int($bytes/M), $tt, int($bytes/k/$tt); } else { printf STDERR "%s: %d kB in %d s = %d kB/s \n", $opt_s||$opt_a||$file, int($bytes/k), $tt, int($bytes/k/$tt); } } if (-t STDOUT and not ($opt_s or $opt_g or $nettest)) { print STDERR "waiting for server ok..." } } } autoflush $SH 1; print {$SH} "\r\n--$boundary--\r\n"; # return if $nettest; # special handling of streaming file because of stunnel tcp shutdown bug if ($opt_s or $opt_g) { close $SH; sleep 1; serverconnect($server,$port); query_sid($server,$port) unless $anonymous; ($seek,$location) = query_file($server,$port,$P{to},$P{from},$sid, $filename,$fileid); if ($seek != $bytes) { die "$0: streamed $bytes bytes but server received $seek bytes\n"; } return "X-Location: $location\n"; } if ($flink) { $bytes = -s $flink; if ($bytes>2*M) { printf STDERR "%s: %d MB\n",$flink,int($bytes/M); } else { printf STDERR "%s: %d kB\n",$flink,int($bytes/k); } } } else { autoflush $SH 1; nvtsend(@hh,@hb); } # SuSe: Can't locate object method "BINMODE" via package "IO::Socket::SSL::SSL_HANDLE" # binmode $SH,':utf8'; if (not $opt_q and $file and -t STDOUT) { print STDERR "\r \r"; } while (<$SH>) { s/[\r\n]+//; print "<-- $_\n" if $opt_v; last if @r and $r[0] =~ / 204 / and /^$/ or /<\/html>/i; push @r,decode_utf8($_); } if ($file) { close $SH; undef $SH; if ($proxy and $fpsize+$seek < $filesize) { goto FORMDATAPOST; } } return @r; } sub randstring { my $n = shift; my @rc = ('A'..'Z','a'..'z',0..9 ); my $rn = @rc; my $rs; for (1..$n) { $rs .= $rc[int(rand($rn))] }; return $rs; } sub zipsplit { my $zipbase = shift; my @files = @_; my @zipfiles = (); my $file; my ($zsize,$size,$n); $zipbase =~ s/\.zip$//; map { s/([^_\w\+\-\.])/\\$1/g } @files; open my $ff,"find @files|" or die "$0: cannot search for @_ - $!\n"; @files = (); zipfile: for (;;) { $n++; if ($n eq 10) { unlink @zipfiles; die "$0: too many zip-archives\n"; } $zsize = 0; while ($file = <$ff>) { chomp $file; # next if -l $file or not -f $file; next unless -f $file; $size = -s $file; if ($size > 2147480000) { unlink @zipfiles; die "$0: \"$file\" too big for zip\n"; } if ($zsize + $size > 2147000000) { push @zipfiles,zip($zipbase.'_'.$n.'.zip',@files); @files = ($file); next zipfile; } else { push @files,$file; $zsize += $size; } } close $ff; last; } push @zipfiles,zip($zipbase.'_'.$n.'.zip',@files); return @zipfiles; } sub zip { no strict 'refs'; my $zip = shift; my $cmd; local $_; unlink $zip; # if ($opt_c) { $cmd = "zip -@ $zip" } # else { $cmd = "zip -0 -@ $zip" } $cmd = "zip -@ $zip"; if (${'opt_#'}) { ${'opt_#'} =~ s/#/ /g; $cmd .= " -x ".${'opt_#'}; } print $cmd,"\n" if $opt_v; open $cmd,"|$cmd" or die "$0: cannot create $zip - $!\n"; foreach (@_) { print {$cmd} $_."\n"; print " $_\n" if $opt_v; } close $cmd or die "$0: zip failed - $!\n"; return $zip; } sub getline { my $file = shift; local $_; while (<$file>) { chomp; s/^#.*//; s/\s+#.*//; s/^\s+//; s/\s+$//; return $_ if length($_); } return ''; } sub query_file { my ($server,$port,$to,$from,$id,$filename,$fileid) = @_; my $seek = 0; my $qfileid = ''; my ($head,$location); my ($response,$fexsrv,$cc); local $_; $to =~ s/[,:].*//; $to = $AB{$to} if $AB{$to}; $filename =~ s/([^_=:,;<>()+.\w\-])/'%'.uc(unpack("H2",$1))/ge; # urlencode if ($skey) { $head = "HEAD $proxy_prefix/fop/$to/$from/$filename??SKEY=$id HTTP/1.1"; } elsif ($gkey) { $head = "HEAD $proxy_prefix/fop/$to/$from/$filename??GKEY=$id HTTP/1.1"; } else { $head = "HEAD $proxy_prefix/fop/$to/$from/$filename??ID=$id HTTP/1.1"; } sendheader("$server:$port",$head); $_ = <$SH>; unless (defined $_ and /\w/) { die "$0: no response from server\n"; } s/\r//; print "<-- $_" if $opt_v; unless (/^HTTP.* 200/) { s:HTTP/[\d\. ]+::; $response = $_; while (<$SH>) { s/\r//; print "<-- $_" if $opt_v; $fexsrv = $_ if /^(Server: fexsrv|X-Features:)/; last if /^\s*$/; } die "$0: no fexserver at $server:$port\n" unless $fexsrv; die "$0: server response: $response"; } while (<$SH>) { s/\r//; print "<-- $_" if $opt_v; last if /^$/; if (/^Content-Length:\s+(\d+)/) { $seek = $1 } if (/^X-File-ID:\s+(.+)/) { $qfileid = $1 } if (/^X-Features:\s+(.+)/) { $features = $1 } if (/^X-Location:\s+(.+)/) { $location = $1 } if (/^Connection: close/) { $cc = $_ } } # return true seek only if file is identified $seek = 0 if $qfileid and $qfileid ne $fileid; if ($cc) { serverconnect($server,$port); $sid = $id; } return ($seek,$location); } sub edit_address_book { my ($user) = @_; my $alias; my $ab = "$fexhome/ADDRESS_BOOK"; my (%AB,@r); local $_; die "$0: address book not available for subusers\n" if $skey; die "$0: address book not available for group members\n" if $gkey; female_mode("edit your address book?") if $opt_F; %AB = query_address_book($server,$port,$user); if ($AB{ADDRESS_BOOK} !~ /\w/) { $AB{ADDRESS_BOOK} = "# Format: alias e-mail-address # Comment\n". "# Example:\n". "framstag framstag\@rus.uni-stuttgart.de\n"; } open $ab,">$ab" or die "$0: cannot write to $ab - $!\n"; print {$ab} $AB{ADDRESS_BOOK}; close $ab; system "$editor $ab"; exit unless -s $ab; $opt_o = $opt_A; serverconnect($server,$port); query_sid($server,$port); @r = formdatapost( from => $user, to => $user, id => $sid, file => $ab, ); unlink $ab,$ab.'~'; } sub query_address_book { my ($server,$port,$user) = @_; my ($req,$alias,$address,$options,$comment,$cl,$ab,$b); my %AB; local $_; unless ($SH) { serverconnect($server,$port); query_sid($server,$port); } $req = "GET $proxy_prefix/fop/$user/$user/ADDRESS_BOOK?ID=$sid HTTP/1.1"; sendheader("$server:$port",$req); $_ = <$SH>; unless (defined $_ and /\w/) { die "$0: no response from server\n"; } s/\r//; print "<-- $_" if $opt_v; unless (/^HTTP.* 200/) { if (/^HTTP.* 404/) { while (<$SH>) { last if /^\r?\n/ } return; } else { # s:HTTP/[\d\. ]+::; # die "$0: server response: $_"; close $SH; undef $SH; return (); } } while (<$SH>) { s/\r//; print "<-- $_" if $opt_v; last if /^$/; $cl = $1 if /^Content-Length: (\d+)/; } if ($cl) { while (<$SH>) { $b += length; $ab .= $_; s/[\r\n]//g; s/^\s+//; s/\s+$//; print "<-- $_\n" if $opt_v; s/\s*#\s*(.*)//; if ($_) { $comment = $1||''; ($alias,$address,$options) = split; if ($address) { if ($options) { $options =~ s/[()]//g } else { $options = '' } $AB{$alias} = $address; $AB{$alias}->{options} = $options||''; $AB{$alias}->{comment} = $comment||''; if ($options and $options =~ /keep=(\d+)/i) { $AB{$alias}->{keep} = $1; } if ($options and $options =~ /autodelete=(\w+)/i) { $AB{$alias}->{autodelete} = $1; } } } last if $b >= $cl; } } $AB{ADDRESS_BOOK} = $ab; return %AB; } # sets global $sid $features $timeout # ugly hack! :-} sub query_sid { my ($server,$port) = @_; my ($req,$fexsrv); local $_; $sid = $id; if ($port eq 443 or $proxy) { return if $opt_d; return if $features; # early return if we know enough $req = "OPTIONS /FEX HTTP/1.1"; # does not work with (some) proxies $req = "GET /SID HTTP/1.1"; # needed as FEATURES query } else { $req = "GET /SID HTTP/1.1"; } sendheader("$server:$port",$req); $_ = <$SH>; unless (defined $_ and /\w/) { print "\n" if $opt_v; die "$0: no response from server\n"; } s/\r//; print "<-- $_" if $opt_v; if ($req =~ /OPTIONS/ and /^HTTP.* 502 /) { # (reverse) proxy error close $SH; serverconnect($server,$port); $req = "GET /SID HTTP/1.0"; sendheader("$server:$port",$req); $_ = <$SH>; unless (defined $_ and /\w/) { print "\n" if $opt_v; die "$0: no response from server\n"; } s/\r//; print "<-- $_" if $opt_v; while (<$SH>) { s/\r//; print "<-- $_" if $opt_v; $features = $1 if /^X-Features: (.+)/; $timeout = $1 if /^X-Timeout: (\d+)/; last if /^\n/; } close $SH; serverconnect($server,$port); } elsif (/^HTTP.* [25]0[01] /) { if (not $proxy and $port ne 443 and /^HTTP.* 201 (.+)/) { $sid = 'MD5H:'.md5_hex($id.$1); } my $cc; while (<$SH>) { s/\r//; print "<-- $_" if $opt_v; $features = $1 if /^X-Features: (.+)/; $timeout = $1 if /^X-Timeout: (\d+)/; $cc = $_ if /^Connection: close/; last if /^\n/; } if ($cc) { serverconnect($server,$port); $sid = $id; } } elsif (/^HTTP.* 301 /) { while (<$SH>) { last if /Location/ } die "$0: cannot use $server:$port because server has a redirection to\n".$_; } else { # no SID support - perhaps transparent web proxy? while (<$SH>) { s/\r//; print "<-- $_" if $opt_v; $fexsrv = $_ if /^(Server: fexsrv|X-Features:)/; last if /^\s*$/; } die "$0: no fexserver at $server:$port\n" unless $fexsrv; serverconnect($server,$port); $sid = $id; } # warn "proxy: $proxy\n"; if ($proxy) { serverconnect($server,$port); $sid = $id; } } sub xxget { my ($from,$id,$save) = @_; my $bs = 4096; my $xx = $save; my ($url,$B,$b,$t0,$t1,$cl); my ($ts,$tso); local $_; $xx =~ s:.*/::; $url = "$proxy_prefix/fop/$from/$from/$xx?ID=$id"; sendheader("$server:$port","GET $url HTTP/1.0"); http_response(); while (<$SH>) { s/\r//; print "<-- $_" if $opt_v; $cl = $1 if /^Content-Length:\s(\d+)/; # $ft = $1 if /^X-File-Type:\s(.+)/; last if /^$/; } die "$0: no Content-Length in server-reply\n" unless $cl; open $save,">$save" or die "$0: cannot write to $save - $!\n"; binmode $save; $t0 = $t1 = int(time); $tso = ''; while ($b = read($SH,$_,$bs)) { $B += $b; print {$save} $_; if (int(time) > $t1) { $t1 = int(time); $ts = ts($B,$cl); if ($ts ne $tso) { print STDERR $ts,"\r"; $tso = $ts; } } sleep 1 while ($opt_m and $B/k/(time-$t0||1) > $opt_m); } print STDERR ts($B,$cl),"\n"; close $save; } # transfer status sub ts { my ($b,$tb) = @_; return sprintf("transferred: %d MB (%d%%)",int($b/M),int($b/$tb*100)); } sub sigpipehandler { retry("died"); } sub retry { my $reason = shift; local $SIG{ALRM} = sub { }; if (fileno $SH) { alarm(1); my @r = <$SH>; alarm(0); kill 9,$tpid if $tpid; if (@r and $opt_v) { die "\n$0: ($$) server error: @r\n"; } if (@r and $r[0] =~ /^HTTP.* \d+ (.*)/) { die "\n$0: server error: $1\n"; } } $timeout *= 2; warn "\n$0: connection to $server $reason\n"; warn "retrying after $timeout seconds...\n"; sleep $timeout; if ($windoof) { exec $^X,$0,@_ARGV } else { exec $_0,@_ARGV } die $!; } sub checkrecipient { my ($from,$to) = @_; my @r; local $_; @r = formdatapost( from => $from, to => $to, id => $sid, command => 'CHECKRECIPIENT', ); $_ = shift @r or die "$0: no reply from server\n"; if (/ 2\d\d /) { return if $to eq 'nettest'; foreach (@r) { last if /^$/; if (s/X-(Recipient: .+)/$1\n/) { s/autodelete=\w+/autodelete=$opt_D/ if $opt_D; s/keep=\d+/keep=$opt_k/ if $opt_k; print; $frecipient ||= (split)[1]; } } } else { http_response($_,@r); } } # get ID data from ID file sub get_id { my $idf = shift; $fexcgi = getline($idf) || die "$0: no FEX-URL in $idf\n"; $from = getline($idf) || die "$0: no FROM in $idf\n"; $id = getline($idf) || die "$0: no ID in $idf\n"; if ($fexcgi =~ s/!([\w.-]+:\d+)(:(\d+))?//) { $proxy = $1; $chunksize = $3 || 0; } unless ($fexcgi =~ /^[_:=\w\-\.\/\@\%]+$/) { die "$0: illegal FEX-URL \"$fexcgi\" in $idf\n"; } unless ($from =~ /^[_:=\w\-\.\/\@\%\+]+$/) { die "$0: illegal FROM \"$from\" in $idf\n"; } $fexcgi =~ s:/+$::; } # for windows sub inquire { my ($file,$to); for (;;) { print "file to send: "; chomp($file = ); $file =~ s/^\"//; $file =~ s/\"$//; last if -e $file; warn "$file does not exist\n"; } print "recipient (e-mail address): "; chomp($to = ); die $usage unless $to; unless ($opt_n) { print "comment: "; chomp($opt_C = ); } @ARGV = ($file,$to); } sub shelldo { if (system(@_) < 0) { die "failed: @_\n" } } # emulate seek on a pipe sub readahead { my $fh = shift; # filehandle my $ba = shift; # bytes ahead my $bs = 2**16; my $s = 0; my $n; local $_; while ($s < $ba) { $n = $ba-$s; $n = $bs if $n > $bs; $s += read $fh,$_,$n; } } sub fileid { my $file = shift; my $dirmode = shift; my @s = $dirmode ? lstat($file) : stat($file); if (@s) { return md5_hex($file.$s[0].$s[1].$s[7].$s[9]); } else { warn "$0: $file - $!\n"; return int(time); } } sub get_mutt_alias { my $to = shift; my $ma = $HOME.'/.mutt/aliases'; my ($alias,$options); local $_; $to =~ s/(:.+)// and $options = $1; open $ma,$ma or return $to; while (<$ma>) { if (/^alias \Q$to\E\s/i) { chomp; s/\s*#.*//; s/\(.*?\)//; s/\s+$//; s/.*\s+//; s/[<>]//g; if (/,/) { warn "$0: ignoring mutt multi-alias $to = $_\n"; last; } if (/@/) { $alias = $_; warn "$0: found mutt alias $to = $alias\n"; $alias .= $options if $options; last; } } } close $ma; $to = "$to:$options" if $options; return ($alias||$to); } # collect (hashed) file meta data sub fmd { my @files = @_; my ($file,$dir); my $fmd = ''; foreach $file (@files) { if (not -l $file and -d $file) { $dir = $file; if (opendir $dir,$dir) { while (defined ($file = readdir($dir))) { next if $file eq '..'; if ($file eq '.') { $fmd .= fileid($dir); } elsif (-l "$dir/$file") { # hack for dangling symlinks: do not raise an error $fmd .= fileid("$dir/$file",'dirmode'); } else { $fmd .= fmd("$dir/$file"); } } closedir $dir; } } else { $fmd .= fileid($file); } } return $fmd; } # from MIME::Base64::Perl sub decode_b64 { local $_ = shift; my $uu = ''; my ($i,$l); tr|A-Za-z0-9+=/||cd; s/=+$//; tr|A-Za-z0-9+/| -_|; return "" unless length; $l = (length)-60; for ($i = 0; $i <= $l; $i += 60) { $uu .= "M" . substr($_,$i,60); } $_ = substr($_,$i); if (length) { $uu .= chr(32+(length)*3/4) . $_; } return unpack("u",$uu); } sub female_mode { local $_; if (open my $tty,'/dev/tty') { print "@_\n"; print " [y] yes\n", " [n] no\n", " [p] perhaps - don't know\n", "your choice: "; $_ = <$tty> || ''; close $tty; if (/^y/i) { return } if (/^n/i) { exit } if (/^p/i) { int(rand(2)) ? return : exit } female_mode(@_); } } sub http_response { local $_ = shift || <$SH>; my @r = @_; my $error; $_ = <$SH> unless $_; unless (defined $_ and /\w/) { die "$0: no response from server\n"; } s/\r?\n//; print "<-- $_\n" if $opt_v; # CGI fatalsToBrowser if (/^HTTP.* 500/) { @r = <$SH> unless @r; @r = () unless @r; die "$0: server error: $_\n@r\n"; } unless (/^HTTP.* 200/) { $error = $_; $error =~ s/HTTP.[\s\d.]+//; @r = <$SH> unless @r; @r = () unless @r; foreach (@r) { chomp; $error .= "\n".$_ if /^Location/; print "<-- $_\n" if $opt_v; } die "$0: server error: $error\n"; } return $_; } sub ws { local $_ = shift; return split; } sub update { my $cfb = '### common functions ###'; my $cfc; local $/; open $0,$0 or die "cannot read $0 - $!\n"; $cfc = <$0>; close $0; $cfc =~ s/.*\n$cfb\n//s; foreach my $p (qw'fexget sexsend') { open $p,$p or die "cannot read $p - $!\n"; $_ = <$p>; close $p; s/\n$cfb.*/\n$cfb\n$cfc/s; system "vv -s $p"; open $p,'>',$p or die "cannot write $p - $!\n"; print {$p} $_; close $p; } exec "l fexsend fexget sexsend"; exit; } ### common functions ### sub mtime { my @d = localtime((stat shift)[9]); return sprintf('%d%02d%02d',$d[5]+1900,$d[4]+1,$d[3]); } sub urldecode { local $_ = shift; s/\%([a-f\d]{2})/chr(hex($1))/ige; return $_; } sub get_ssl_env { # set SSL/TLS options $SSL{SSL_verify_mode} = $ENV{SSLVERIFY} if defined($ENV{SSLVERIFY}); foreach my $opt (qw( SSL_version SSL_cipher_list SSL_verify_mode SSL_ca_path SSL_ca_file) ) { my $env = uc($opt); $env =~ s/_//g; $SSL{$opt} = $ENV{$env} if defined($ENV{$env}); } if ($SSL{SSL_verify_mode}) { &search_ca; unless ($SSL{SSL_ca_path} or $SSL{SSL_ca_file}) { die "$0: \$SSLVERIFYMODE, but not valid \$SSLCAPATH or \$SSLCAFILE\n"; } } elsif (defined($SSL{SSL_verify_mode})) { # user has set SSLVERIFY=0 ! } else { &search_ca; $SSL{SSL_verify_mode} = 1 if $SSL{SSL_ca_path} or $SSL{SSL_ca_file}; } } sub search_ca { local $_; return if $SSL{SSL_ca_file} or $SSL{SSL_ca_path}; foreach (qw(/etc/ssl/certs/ca-certificates.crt)) { if (-f) { $SSL{SSL_ca_file} = $_; return; } } foreach (qw(/etc/ssl/certs /etc/pki/tls/certs)) { if (-f) { $SSL{SSL_ca_path} = $_; return; } } } sub serverconnect { my ($server,$port) = @_; my $connect = "CONNECT $server:$port HTTP/1.1"; local $_; if ($proxy) { tcpconnect(split(':',$proxy)); if ($https) { printf "--> %s\n",$connect if $opt_v; nvtsend($connect,""); $_ = <$SH>; s/\r//; printf "<-- $_"if $opt_v; unless (/^HTTP.1.. 200/) { die "$0: proxy error : $_"; } &enable_ssl; $SH = IO::Socket::SSL->start_SSL($SH,%SSL); } } else { tcpconnect($server,$port); } # if ($https and $opt_v) { # printf "%s\n",$SH->get_cipher(); # } } # set up tcp/ip connection sub tcpconnect { my ($server,$port) = @_; if ($SH) { close $SH; undef $SH; } if ($https) { # eval "use IO::Socket::SSL qw(debug3)"; &enable_ssl; $SH = IO::Socket::SSL->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp', %SSL ); } else { $SH = IO::Socket::INET->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp', ); } if ($SH) { autoflush $SH 1; binmode $SH; } else { die "$0: cannot connect $server:$port - $@\n"; } print "TCPCONNECT to $server:$port\n" if $opt_v; } sub enable_ssl { eval "use IO::Socket::SSL"; die "$0: cannot load IO::Socket::SSL\n" if $@; eval '$SSL{SSL_verify_mode} = 0 if Net::SSLeay::SSLeay() <= 9470143'; if ($opt_v) { foreach my $v (keys %SSL) { printf "%s => %s\n",$v,$SSL{$v}; } } } sub sendheader { my $sp = shift; my @head = @_; my $head; push @head,"Host: $sp"; push @head,"User-Agent: $useragent"; foreach $head (@head) { chomp $head; print "--> $head\n" if $opt_v; print {$SH} $head,"\r\n"; } print "-->\n" if $opt_v; print {$SH} "\r\n"; } sub nvtsend { local $SIG{PIPE} = sub { $sigpipe = "@_" }; $sigpipe = ''; die "$0: internal error: no active network handle\n" unless $SH; die "$0: remote host has closed the link\n" unless $SH->connected; foreach my $line (@_) { print {$SH} $line,"\r\n"; if ($sigpipe) { undef $SH; return 0; } } return 1; } sub quote { local $_ = shift; s/([^\w\@\/%^,.=+_:+-])/\\$1/g; return $_; } sub debug { print "## DEBUG: @_\n" if $DEBUG; } # from MIME::Base64::Perl sub encode_b64 { my $res = ""; my $eol = "\n"; my $padding; pos($_[0]) = 0; $res = join '',map(pack('u',$_)=~ /^.(\S*)/, ($_[0]=~/(.{1,45})/gs)); $res =~ tr|` -_|AA-Za-z0-9+/|; $padding = (3-length($_[0])%3)%3; $res =~ s/.{$padding}$/'=' x $padding/e if $padding; return $res; } fex-20160919/bin/fexget0000755000174700017470000006174012770010173012701 0ustar fexfex#!/usr/bin/perl -w # CLI client for the FEX service for retrieving files # # see also: fexsend # # Author: Ulli Horlacher # # Perl Artistic Licence use 5.006; use strict qw'vars subs'; use Config; use POSIX; use Encode; use Cwd 'abs_path'; use Getopt::Std; use File::Basename; use Socket; use IO::Handle; use IO::Socket::INET; use Time::HiRes 'time'; use constant k => 2**10; use constant M => 2**20; eval 'use Net::INET6Glue::INET_is_INET6'; $| = 1; our $SH; our ($fexhome,$idf,$tmpdir,$windoof,$useragent); our ($xv,%autoview); our $bs = 2**16; # blocksize for tcp-reading and writing file our $version = 20160919; our $CTYPE = 'ISO-8859-1'; our $fexsend = $ENV{FEXSEND} || 'fexsend'; our $DEBUG = $ENV{DEBUG}; our $_0 = $0; my %SSL = (SSL_version => 'TLSv1'); my $sigpipe; # inquire default character set # cannot use "use I18N::Langinfo" because of no windows support! eval { local $^W = 0; require I18N::Langinfo; I18N::Langinfo->import(qw'langinfo CODESET'); $CTYPE = langinfo(CODESET()); }; if ($Config{osname} =~ /^mswin/i) { $windoof = $Config{osname}; $ENV{HOME} = $ENV{USERPROFILE}; $fexhome = $ENV{FEXHOME} || $ENV{HOME}.'/fex'; $tmpdir = $ENV{FEXTMP} || $ENV{TMP} || "$fexhome/tmp"; $idf = "$fexhome/id"; $useragent = sprintf("fexget-$version (%s %s)", $Config{osname},$Config{archname}); $SSL{SSL_verify_mode} = 0; chdir $ENV{USERPROFILE}.'\Desktop'; # open XX,'>XXXXXX';close XX; } elsif ($Config{osname} =~ /^darwin/i or $ENV{MACOS}) { $0 =~ s:(.*)/:: and $ENV{PATH} .= ":$1"; $fexhome = $ENV{FEXHOME} || $ENV{HOME}.'/.fex'; $tmpdir = $ENV{FEXTMP} || $ENV{TMPDIR} || "$fexhome/tmp"; $idf = "$fexhome/id"; $_ = `sw_vers -productVersion 2>/dev/null`||''; chomp; $useragent = "fexget-$version (MacOS $_)"; } else { $0 =~ s:(.*)/:: and $ENV{PATH} .= ":$1"; $fexhome = $ENV{FEXHOME} || $ENV{HOME}.'/.fex'; $tmpdir = $ENV{FEXTMP} || "$fexhome/tmp"; $idf = "$fexhome/id"; $_ = `(lsb_release -d||uname -a)2>/dev/null`||''; chomp; s/^Description:\s+//; $useragent = "fexget-$version ($_)"; } if (-f ($_ = '/etc/fex/config.pl')) { eval { require } or warn $@; } my $usage = < 'my_prefered_image_viewer', '\.(avi|mp4|mov)' => 'vlc -f', '\.pdf' => 'evince', ); For HTTPS you can set the environment variables: SSLVERIFY=1 # activate server identity verification SSLVERSION=TLSv1 # this is the default SSLCAPATH=/etc/ssl/certs # path to trusted (root) certificates SSLCAFILE=/etc/ssl/cert.pem # file with trusted (root) certificates SSLCIPHERLIST=HIGH:!3DES # see http://www.openssl.org/docs/apps/ciphers.html You can set these environment variables also in $HOME/.fex/config.pl, as well as the $opt_* variables, e.g.: $ENV{SSLVERSION} = 'TLSv1'; ${'opt_+'} = 1; $opt_m = 200; EOD if ($windoof and not @ARGV and not $ENV{PROMPT}) { # restart with cmd.exe to have mouse cut+paste my $cmd = "cmd /k \"$0\""; # print "$cmd\n"; exec $cmd; exit; } my $atype = '\.(tgz|tar|zip|7z)$'; my $proxy = ''; my $proxy_prefix = ''; my $chunksize; our ($opt_h,$opt_v,$opt_l,$opt_d,$opt_m,$opt_z,$opt_K,$opt_o,$opt_a); our ($opt_s,$opt_k,$opt_i,$opt_V,$opt_X,$opt_f,$opt_P,$opt_L,$opt_H); $opt_m = $opt_h = $opt_v = $opt_l = $opt_d = $opt_K = $opt_o = $opt_a = 0; $opt_V = $opt_X = $opt_f = $opt_L = $opt_H = 0; ${'opt_+'} = 0; $opt_s = $opt_k = $opt_i = $opt_P = ''; $_ = "$fexhome/config.pl"; require if -f; getopts('hvVHlLdkzoaXVf+m:s:i:K:P:') or die $usage; $opt_k = '?KEEP' if $opt_k; if ($opt_m =~ /(\d+)/) { $opt_m = $1 } else { $opt_m = 0 } if ($opt_V) { print "Version: $version\n"; unless (@ARGV) { print "Upgrade fexget? "; $_ = ||''; if (/^y/i) { my $new = `wget -nv -O- http://fex.belwue.de/download/fexget`; my $newversion = $1 if $new =~ /version = (\d+)/; if ($new !~ /upgrade fexget/ or not $newversion) { die "$0: bad update\n"; } if ($newversion <= $version) { die "$0: no newer version\n"; } $_0 = abs_path($_0); system qw'rsync -a',$_0,$_0.'_old'; exit $? if $?; open $_0,'>',$_0 or die "$0: cannot write $_0. - $!\n"; print {$_0} $new; close $_0; exec $_0,qw'-V .'; } } exit; exit if "@ARGV" eq '.'; } die $usage if $opt_h; if ($opt_H) { print $hints; exit; } &get_ssl_env; my $ffl = "$tmpdir/fexget"; # F*EX files list (cache) my @rcamel = ( ' (_*p _ _ \\\\/ \/ \\ \ __ )=* //\\\\//\\\\ ', " \\\\/\\\\/ \n", " //\\\\//\\\\\n" ); # get fexlog if ($opt_z) { my $cmd = "$fexsend -Z"; $cmd .= " -i $opt_i" if $opt_i; warn "$cmd\n" if $opt_v; exec $cmd; die "$0: cannot run $cmd : $!\n"; } if ($opt_l) { &list; exit; } if ($opt_L) { my $cmd = "$fexsend -L"; $cmd .= " -i $opt_i" if $opt_i; warn "$cmd\n" if $opt_v; exec $cmd; die "$0: cannot run $cmd : $!\n"; } if ($opt_P) { if ($opt_P =~ /^([\w.-]+:\d+)(:(\d+))?/) { $proxy = $1; $chunksize = $3 || 0; } else { die "$0: proxy must be: SERVER:PORT\n"; } } if ($opt_a) { $opt_X = $opt_a; die $usage if @ARGV; &list; print "\n"; if (open $ffl,$ffl) { while (<$ffl>) { push @ARGV,$1 if /^\s+(\d+)/; } close $ffl; } } else { unless (@ARGV) { if ($windoof) { my $url; for (;;) { print "download-URL: "; chomp($url = ); if ($url =~ /^http/) { @ARGV = ($url); last; } } } else { die $usage; } } } my ($file,%files,$download,$server,$port,$fop,$https); if ($opt_f) { unless ($ENV{FEXID} or -f $ENV{HOME}.'/.fex/id') { die "$0: no local FEXID\n"; } $opt_f = pop(@ARGV); if ($opt_f =~ /^\d+$|^https?:/) { die "$0: $opt_f is not an e-mail address\n"; } } URL: foreach my $url (@ARGV) { # do not overrun server sleep 1 if $fop; if ($url !~ /^http/) { unless (%files) { open $ffl,$ffl or die "$0: no $ffl, use first: $0 -l\n"; my $from = ''; while (<$ffl>) { if (/^from (.+) :$/) { $from = $1; } elsif (/^\s*(\d+)\)\s+\d+ MB.* (http\S+)/) { push @{$files{all}},$2; push @{$files{$from}},$2; } } close $ffl; } if ($url =~ /^(\d+)$/) { $url = ${files{all}}[$1-1] or die "$0: unknown file number\n"; } } if ($url =~ m{^http(s?)://([\w\.\-]+)(:(\d+))?(/.*fop/\S+)}) { $https = $1; $server = $2; $port = $4 || ($1?443:80); $fop = $5; } else { die "$0: unknown F*EX URL $url\n"; } if ($proxy) { if ($port == 80) { $proxy_prefix = "http://$server" } elsif ($port == 443) { $proxy_prefix = "" } else { $proxy_prefix = "http://$server:$port" } } serverconnect($server,$port); if ($opt_f) { forward($url); next; } if ($opt_d) { my @r = del($url); $_ = shift @r; if (/^HTTP.* 200/) { ($file) = grep { $_ = $1 if /^X-File:\s+(.+)/ } @r; $file = $url unless $file; $file =~ s:.*/::; printf "%s deleted\n",locale(decode_utf8(urldecode($file))); } else { s:HTTP/[\d\. ]+::; die "$0: server response: $_"; } next; } if ($opt_K) { my @r = keep($url); $_ = shift @r; if (/^HTTP.* 200/) { $file = $url; $file =~ s:.*/::; print "$file kept\n"; } else { s:HTTP/[\d\. ]+::; die "$0: server response: $_"; } next; } $download = download($server,$port,$fop); exit if $opt_s eq '-'; unlink $download unless -s $download; exit 2 unless -f $download; if ($windoof) { print "READY\n"; exit; } if (not $opt_X and $download =~ /\.gpg$/) { if (-t) { print "decrypt \"$download\"? "; $_ = ||'y'; unless (/^[y\n]/i) { print "keeping \"$download\"\n"; exit; } } if (system('gpg',$download) == 0) { unlink $download; $download =~ s/\.gpg$//; } } unless ($opt_X) { foreach my $a (keys %autoview) { if ($download =~ /$a$/i and $autoview{$a}) { printf "run \"%s %s\" [Yn] ? ",$autoview{$a},basename($download); $_ = ||''; system sprintf("%s %s",$autoview{$a},quote($download)) if /^y|^$/i; next URL; } } if ($ENV{DISPLAY} and $download =~ /\.(gif|jpg|png|tiff?)$/i) { # see also mimeopen and xdg-mime # http://unix.stackexchange.com/questions/144047/how-does-xdg-open-do-its-work if (my $xv = $xv || pathsearch('xv') || pathsearch('xdg-open')) { printf "run \"%s %s\" [Yn] ? ",basename($xv),basename($download); $_ = ||''; system $xv,$download if /^y|^$/i; next URL; } } if ($download =~ /$atype/) { if ($download =~ /\.(tgz|tar.gz)$/) { extract('tar tvzf','tar xvzf') } elsif ($download =~ /\.tar$/) { extract('tar tvf','tar xvf') } elsif ($download =~ /\.zip$/i) { extract('unzip -l','unzip') } elsif ($download =~ /\.7z$/i) { extract('7z l','7z x') } else { die "$0: unknown archive \"$download\"\n" } if ($? == 0) { unlink $download; } else { die "$0: keeping \"$download\"\n"; } } } } exit; sub extract { my $l = shift; my $x = shift; my $d = $download; my $xd = ''; local $_; if (-t and not $windoof) { print "Files in archive:\n"; system(split(' ',$l),$download); $d =~ s:.*/:./:; $d =~ s/\.[^.]+$//; $d =~ s:/*$:/:; for (;;) { $xd = inquire("extract to directory (Ctrl-C to keep archive): ",$d); last if $xd =~ s:^(\./*)*!?$::; if ($xd eq '-') { print "keeping $download\n"; exit; } if ($xd !~ s/!$//) { if (-d $xd) { print "directory $xd does already exist, add \"!\" to overwrite\n"; redo; } unless (mkdir $xd) { print "cannot mkdir $xd - $!\n"; redo; } } unless (chdir $xd) { print "cannot chdir $xd - $!\n"; redo; } last; } } print "extracting to $xd :\n" if $xd; system(split(' ',$x),$download); print "extracted to $xd\n" if $xd; } sub del { my $url = shift; my ($server,$port); my $del; my @r; if ($url =~ m{^http(s?)://([\w\.\-]+)(:(\d+))?(/fop/.+)}) { $server = $2; $port = $4 || ($1?443:80); $del = $5.'?DELETE'; } else { die "$0: unknown F*EX URL $url\n"; } sendheader("$server:$port","GET $del HTTP/1.1","User-Agent: $useragent"); while (<$SH>) { s/\r//; last if /^\n/; # ignore HTML output warn "<-- $_" if $opt_v; push @r,$_; } die "$0: no response from fex server $server\n" unless @r; return @r; } sub forward { my $url = shift; my ($server,$port); my ($uri,$dkey,$list,$cmd,$n,$copy); my @r; if ($url =~ m{^http(s?)://([\w\.\-]+)(:(\d+))?(/fop/.+)}) { $server = $2; $port = $4 || ($1?443:80); $uri = $5; } else { die "$0: unknown F*EX URL $url\n"; } sendheader( "$server:$port", "GET $uri?COPY HTTP/1.1", "User-Agent: $useragent", ); $_ = <$SH>; die "$0: no reply from fex server $server\n" unless $_; warn "<-- $_" if $opt_v; if (/^HTTP.*already exists/) { if ($uri =~ m:/fop/(\w+)/:) { $dkey = $1; } } elsif (/^HTTP.*200/) { # ok! } else { s/^HTTP.... \d+ //; die "$0: $_"; } while (<$SH>) { s/\r//; last if /^\n/; # ignore HTML output $dkey = $1 if /^Location:.*\/(\w+)\/.+/; warn "<-- $_" if $opt_v; } print "fexsend -l\n" if $opt_v; system 'fexsend -l >/dev/null 2>&1'; $list = $ENV{HOME}.'/.fex/tmp/fexlist'; open $list,$list or die "$0: cannot open $list - $!\n"; while (<$list>) { if (/^\s+(\d+)\) (\w+)/ and $2 eq $dkey) { $n = $1; $cmd = "fexsend -b $n $opt_f"; print "$cmd\n" if $opt_v; system $cmd; last; } } close $list; if ($n) { $cmd = "fexsend -d $n >/dev/null 2>&1"; print "$cmd\n" if $opt_v; system $cmd; } else { warn "$0: forwarding failed\n"; } } sub keep { my $url = shift; my ($server,$port); my $keep; my (@hh,@r); if ($url =~ m{^http(s?)://([\w\.\-]+)(:(\d+))?(/fop/.+)}) { $server = $2; $port = $4 || ($1?443:80); $keep = "$5?KEEP=$opt_K"; } else { die "$0: unknown F*EX URL $url\n"; } push @hh,"GET $keep HTTP/1.1", "Host: $server:$port", "User-Agent: $useragent", ""; foreach (@hh) { warn $_,"\n" if $opt_v; print $SH $_,"\r\n"; } while (<$SH>) { s/\r//; last if /^\n/; push @r,$_; } die "$0: no response from fex server $server\n" unless @r; grep { warn "\t$_" } @r if $opt_v; return @r; } sub download { my ($server,$port,$fop,$nocheck) = @_; my ($file,$download,$ssl,$pipe,$filesize,$checkstorage,$dkey); my (@hh,@r); my ($t0,$t1,$t2,$tt,$tm,$ts,$kBs,$b,$bt,$tb,$B,$buf); my $length = 0; my $seek = 0; my $tc = 0; local $_; local *X; if ($opt_s) { $file = $opt_s; if ($opt_s eq '-') { $pipe = $download = $opt_s; } elsif (-p $opt_s or -c $opt_s) { $download = $opt_s; $nocheck = 'pipe or character device'; } else { $download = $file.'.tmp'; $seek = -s $download || 0; } } else { # ask server for real file name sendheader( "$server:$port", "HEAD $proxy_prefix$fop HTTP/1.1", "User-Agent: $useragent" ); my $reply = $_ = <$SH>; unless (defined $_ and /\w/) { die "$0: no response from server\n"; } warn "<-- $_" if $opt_v; unless (/^HTTP\/[\d.]+ 200/) { s:HTTP/[\d. ]+::; die "$0: server response: $_"; } while (<$SH>) { s/\r//; warn "<-- $_" if $opt_v; last if /^\r?\n/; if (/^Content-Disposition: attachment; filename="(.+)"/i) { $file = locale(decode_utf8($1)); $file =~ s:.*/::; } } unless ($file) { $file = $fop; $file =~ s:.*/::; } $download = $file.'.tmp'; $seek = -s $download || 0; } $fop =~ m:/fop/(\w+)/: and $dkey=$1 or $dkey=''; push @hh,"GET $proxy_prefix$fop$opt_k HTTP/1.1", "User-Agent: $useragent", "Cookie: dkey=$dkey", "Connection: close"; push @hh,"Range: bytes=$seek-" if $seek; # HTTPS needs a new connection for actually downloading the file serverconnect($server,$port) if $opt_P and $port == 443; sendheader("$server:$port",@hh); $_ = <$SH>; die "$0: no response from fex server $server\n" unless $_; s/\r//; if (/^HTTP\/[\d.]+ 2/) { warn "<-- $_" if $opt_v; while (<$SH>) { s/\r//; warn "<-- $_" if $opt_v; last if /^\r?\n/; if (/^Content-length:\s*(\d+)/i) { $length = $1; } elsif (/^X-Size: (\d+)/i) { $filesize = $1; } } } else { s/HTTP\/[\d.]+ \d+ //; die "$0: bad server reply: $_"; } if ($pipe) { *X = *STDOUT; } else { if ($opt_s and $opt_s eq $download) { open X,'>',$download or die "$0: cannot write to \"$download\" - $!\n"; $checkstorage = $filesize unless $nocheck; } else { if (-e $file and not $opt_o) { die "$0: destination file \"$file\" does already exist\n"; } if ($seek) { open X,'>>',$download or die "$0: cannot write to \"$download\" - $!\n"; } else { open X,'>',$download or die "$0: cannot write to \"$download\" - $!\n"; $checkstorage = $filesize unless $nocheck; } } if ($checkstorage and not $nocheck) { my $t0 = my $t1 = my $t2 = time; my $n = 0; my $buf = '.' x M; my $storagetest = $file.'.test'; my $error = "$0: cannot write \"$storagetest\""; open $storagetest,'>',$storagetest or die "$error - $!\n"; print STDERR "checking storage...\r"; while (-s $storagetest < $checkstorage) { syswrite $storagetest,$buf or do { unlink $storagetest; die "\n$error - $!\n"; }; $n++; $t2 = int(time); if ($t2 > $t1) { print STDERR "checking storage... ".$n." MB\r"; $t1 = $t2; } } close $storagetest or do { unlink $storagetest; die "\n$error - $!\n"; }; print STDERR "checking storage... ".$n." MB ok!\n"; unlink $storagetest; if (time-$t0 > 25) { # retry after timeout serverconnect($server,$port); return(download($server,$port,$fop,'nocheck')) } } } $t0 = $t1 = $t2 = int(time); $tb = $B = 0; printf STDERR "resuming at byte %s\n",$seek if $seek; print $rcamel[0] if ${'opt_+'}; while ($B < $length and $b = read $SH,$buf,$bs) { syswrite X,$buf; $B += $b; $tb += $b; $bt += $b; $t2 = time; if (${'opt_+'} and int($t2*10)>$tc) { print $rcamel[$tc%2+1]; $tc = int($t2*10); } if (int($t2) > $t1) { $kBs = int($bt/k/($t2-$t1)); $kBs = int($tb/k/($t2-$t0)) if $kBs < 10; $t1 = $t2; $bt = 0; # smaller block size is better on slow links $bs = 4096 if $bs>4096 and $tb/($t2-$t0)<65536; if ($tb<10*M) { printf STDERR "%s: %d kB (%d%%) %d kB/s \r", $download, int(($tb+$seek)/k), int(($tb+$seek)/($length+$seek)*100), $kBs; } else { printf STDERR "%s: %d MB (%d%%) %d kB/s \r", $download, int(($tb+$seek)/M), int(($tb+$seek)/($length+$seek)*100), $kBs; } } if ($opt_m) { if ($t2 == $t0 and $B > $opt_m*k) { print "\nsleeping...\r" if $opt_v; sleep 1; } else { while ($t2 > $t0 and $tb/k/($t2-$t0) > $opt_m) { print "\nsleeping...\r" if $opt_v; sleep 1; $t2 = time; } } } } close $SH; close X; print $rcamel[2] if ${'opt_+'}; $tt = $t2-$t0; $tm = int($tt/60); $ts = $tt-$tm*60; $kBs = int($tb/k/($tt||1)); if ($seek) { printf STDERR "$file: %d MB, last %d MB in %d s (%d kB/s) \n", int(($tb+$seek)/M),int($tb/M),$tt,$kBs; } else { printf STDERR "$file: %d MB in %d s (%d kB/s) \n", int($tb/M),$tt,$kBs; } if ($tb != $length) { if ($windoof) { exec "\"$0\" @ARGV"; exit; } else { die "$0: $server annouced $length bytes, but only $tb bytes has been read\n"; } } unless ($pipe or -p $download or -c $download) { my @s = stat $file if -e $file; rename $download,$file or die "$0: cannot rename \"$download\" to \"$file\" - $!\n"; chmod $s[2],$file if @s; } return sprintf("%s/%s",getcwd(),$file); } sub list { my $cmd = "$fexsend -L"; $cmd .= " -i $opt_i" if $opt_i; if ($opt_v) { $cmd .= " -v"; warn "$cmd\n"; } open $cmd,"$cmd|" or die "$0: cannot run $cmd : $!\n"; open $ffl,'>',$ffl or die "$0: cannot open $ffl : $!\n"; my $n; while (<$cmd>) { if (/\d MB .*http/) { $n++; printf {$ffl} "%4d) %s",$n,$_; s:http[^\"]*/::; printf "%4d) %s",$n,$_; } else { print; print {$ffl} $_; } } } sub locale { my $string = shift; if ($CTYPE) { if ($CTYPE =~ /UTF-?8/i) { return $string; } elsif (grep { $CTYPE =~ /^$_$/i } Encode->encodings()) { return encode($CTYPE,$string); } else { return encode('ISO-8859-1',$string); } } return $string; } sub pathsearch { my $prg = shift; foreach my $dir (split(':',$ENV{PATH})) { return "$dir/$prg" if -x "$dir/$prg"; } } { my $tty; sub inquire { my $prompt = shift; my $default = shift; local $| = 1; local $_; if (defined $default) { unless ($tty) { chomp($tty = `tty 2>/dev/null`); eval { local $^W; require "sys/ioctl.ph"; }; } if (defined(&TIOCSTI) and $tty and open($tty,'>',$tty)) { print $prompt; # push default answer into keyboard buffer foreach my $a (split("",$default)) { ioctl($tty,&TIOCSTI,$a) } chomp($_ = ||''); } else { $prompt =~ s/([\?:=]\s*)/ [$default]$1/ or $prompt .= " [$default] "; print $prompt; chomp($_ = ||''); $_ = $default unless length; } } else { print $prompt; chomp($_ = ||''); } return $_; } } ### common functions ### sub mtime { my @d = localtime((stat shift)[9]); return sprintf('%d%02d%02d',$d[5]+1900,$d[4]+1,$d[3]); } sub urldecode { local $_ = shift; s/\%([a-f\d]{2})/chr(hex($1))/ige; return $_; } sub get_ssl_env { # set SSL/TLS options $SSL{SSL_verify_mode} = $ENV{SSLVERIFY} if defined($ENV{SSLVERIFY}); foreach my $opt (qw( SSL_version SSL_cipher_list SSL_verify_mode SSL_ca_path SSL_ca_file) ) { my $env = uc($opt); $env =~ s/_//g; $SSL{$opt} = $ENV{$env} if defined($ENV{$env}); } if ($SSL{SSL_verify_mode}) { &search_ca; unless ($SSL{SSL_ca_path} or $SSL{SSL_ca_file}) { die "$0: \$SSLVERIFYMODE, but not valid \$SSLCAPATH or \$SSLCAFILE\n"; } } elsif (defined($SSL{SSL_verify_mode})) { # user has set SSLVERIFY=0 ! } else { &search_ca; $SSL{SSL_verify_mode} = 1 if $SSL{SSL_ca_path} or $SSL{SSL_ca_file}; } } sub search_ca { local $_; return if $SSL{SSL_ca_file} or $SSL{SSL_ca_path}; foreach (qw(/etc/ssl/certs/ca-certificates.crt)) { if (-f) { $SSL{SSL_ca_file} = $_; return; } } foreach (qw(/etc/ssl/certs /etc/pki/tls/certs)) { if (-f) { $SSL{SSL_ca_path} = $_; return; } } } sub serverconnect { my ($server,$port) = @_; my $connect = "CONNECT $server:$port HTTP/1.1"; local $_; if ($proxy) { tcpconnect(split(':',$proxy)); if ($https) { printf "--> %s\n",$connect if $opt_v; nvtsend($connect,""); $_ = <$SH>; s/\r//; printf "<-- $_"if $opt_v; unless (/^HTTP.1.. 200/) { die "$0: proxy error : $_"; } &enable_ssl; $SH = IO::Socket::SSL->start_SSL($SH,%SSL); } } else { tcpconnect($server,$port); } # if ($https and $opt_v) { # printf "%s\n",$SH->get_cipher(); # } } # set up tcp/ip connection sub tcpconnect { my ($server,$port) = @_; if ($SH) { close $SH; undef $SH; } if ($https) { # eval "use IO::Socket::SSL qw(debug3)"; &enable_ssl; $SH = IO::Socket::SSL->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp', %SSL ); } else { $SH = IO::Socket::INET->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp', ); } if ($SH) { autoflush $SH 1; binmode $SH; } else { die "$0: cannot connect $server:$port - $@\n"; } print "TCPCONNECT to $server:$port\n" if $opt_v; } sub enable_ssl { eval "use IO::Socket::SSL"; die "$0: cannot load IO::Socket::SSL\n" if $@; eval '$SSL{SSL_verify_mode} = 0 if Net::SSLeay::SSLeay() <= 9470143'; if ($opt_v) { foreach my $v (keys %SSL) { printf "%s => %s\n",$v,$SSL{$v}; } } } sub sendheader { my $sp = shift; my @head = @_; my $head; push @head,"Host: $sp"; foreach $head (@head) { print "--> $head\n" if $opt_v; print {$SH} $head,"\r\n"; } print "-->\n" if $opt_v; print {$SH} "\r\n"; } sub nvtsend { local $SIG{PIPE} = sub { $sigpipe = "@_" }; $sigpipe = ''; die "$0: internal error: no active network handle\n" unless $SH; die "$0: remote host has closed the link\n" unless $SH->connected; foreach my $line (@_) { print {$SH} $line,"\r\n"; if ($sigpipe) { undef $SH; return 0; } } return 1; } sub quote { local $_ = shift; s/([^\w\@\/%^,.=+_:+-])/\\$1/g; return $_; } sub debug { print "## DEBUG: @_\n" if $DEBUG; } # from MIME::Base64::Perl sub encode_b64 { my $res = ""; my $eol = "\n"; my $padding; pos($_[0]) = 0; $res = join '',map(pack('u',$_)=~ /^.(\S*)/, ($_[0]=~/(.{1,45})/gs)); $res =~ tr|` -_|AA-Za-z0-9+/|; $padding = (3-length($_[0])%3)%3; $res =~ s/.{$padding}$/'=' x $padding/e if $padding; return $res; } fex-20160919/bin/sexsend0000755000174700017470000004101512657123636013076 0ustar fexfex#!/usr/bin/perl -w # client for stream exchange of the FEX service # # Author: Ulli Horlacher # # Perl Artistic Licence # sexsend / sexget / sexxx use Getopt::Std; use Socket; use IO::Handle; use IO::Socket::INET; use Digest::MD5 qw(md5_hex); # encypted ID / SID use constant k => 2**10; use constant M => 2**20; eval 'use Net::INET6Glue::INET_is_INET6'; our $version = 20160919; our $DEBUG = $ENV{DEBUG}; my %SSL = (SSL_version => 'TLSv1'); my $sigpipe; if (-f ($_ = '/etc/fex/config.pl')) { eval { require } or warn $@; } $0 =~ s:.*/::; $| = 1; # sexsend is default $usage = "usage: ... | $0 [options] [SEX-URL/]recipient [stream]\n". "options: -v verbose mode\n". " -g show transfer rate\n". " -V show version\n". " -t timeout timeout in s (waiting for recipient)\n". "special: recipient may be \"public\" or \"anonymous\" or \".\"\n". "see also: sexget, sexxx\n". "example: tail -f /var/log/syslog | $0 fex.flupp.org/admin log\n"; if ($0 eq 'sexget' or $0 eq 'fuckme') { $usage = "usage: $0 [options] [[SEX-URL/]user:ID] [stream]\n". "options: -v verbose mode\n". " -g show transfer rate\n". " -V show version\n". "arguments: user:ID use this user & ID\n". " (ID may be \"public\" or user:ID may be \"anonymous\")\n". " stream name of the stream\n". "see also: sexsend, sexxx\n". "example: $0 log | grep kernel\n"; } if ($0 eq 'sexxx') { $usage = "usage: $0 [-v] [-g] [-c] [-u [SEX-URL/]user] [-s stream] [files...]\n". "usage: $0 [-v] [-g] [-u [SEX-URL/]user] [-s stream] | ...\n". "options: -v verbose mode\n". " -g show transfer rate\n". " -q quiet mode\n". " -c compress files\n". " -u SEX-URL/user SEX-URL and user (default: use FEXID/FEXXX)\n". " -s stream stream name (default: xx)\n". "see also: sexsend, sexget\n". "examples: $0 -s config /etc /usr/local/etc\n". " $0 > backup.tar\n"; } $fexhome = $ENV{FEXHOME} || $ENV{HOME}.'/.fex'; $user = $id = ''; $type = $timeout = $stream = $mode = ''; $idf = "$fexhome/id"; $bs = $ENV{BS} || 2**16; # I/O blocksize # server URL, user and auth-ID if ($FEXID = $ENV{FEXID}) { $FEXID = decode_b64($FEXID) if $FEXID !~ /\s/; ($fexcgi,$user,$id) = split(/\s+/,$FEXID); } else { if (open $idf,$idf) { chomp($fexcgi = <$idf>) or die "$0: no FEX-URL in $idf\n"; chomp($user = <$idf>) or die "$0: no FROM in $idf\n"; chomp($id = <$idf>) or die "$0: no ID in $idf\n"; close $idf; despace($fexcgi,$user,$id); unless ($fexcgi =~ /^[_:=\w\-\.\/\@\%]+$/) { die "$0: illegal FEX-URL \"$fexcgi\" in $idf\n"; } unless ($user =~ /^[_:=\w\-\.\/\@\%\+]+$/) { die "$0: illegal FROM \"$user\" in $idf\n"; } } } $opt_h = $opt_v = $opt_V = $opt_q = 0; $opt_u = $opt_s = $opt_c = $opt_t = ''; $_ = "$fexhome/config.pl"; require if -f; if ($0 eq 'sexxx') { # xx server URL, user and auth-ID if ($FEXXX = $ENV{FEXXX}) { $FEXXX = decode_b64($FEXXX) if $FEXXX !~ /\s/; ($fexcgi,$user,$id) = split(/\s+/,$FEXXX); } elsif (open $idf,$idf) { while (<$idf>) { if (/^\[xx\]/) { chomp($fexcgi = <$idf>) or die "$0: no xx FEX-URL in $idf\n"; chomp($user = <$idf>) or die "$0: no xx FROM in $idf\n"; chomp($id = <$idf>) or die "$0: no xx ID in $idf\n"; last; } } close $idf; } getopts('hgvcu:s:') or die $usage; die $usage if $opt_h; die $usage unless -t; if ($opt_c) { $opt_c = 'z'; $type = '&type=GZIP'; } if ($opt_u) { $fexcgi = $1 if $opt_u =~ s:(.+)/::; $user = $opt_u; } unless ($fexcgi) { die "$0: no xx user found, use \"$0 -u SEX-URL/user\"\n"; } unless ($user) { die "$0: no xx user found, use \"$0 -u user\"\n"; } } elsif ($0 eq 'sexget' or $0 eq 'fuckme') { $opt_g = 0; getopts('hgvVdu:') or die $usage; die $usage if $opt_h; if ($opt_V) { print "Version: $version\n"; exit unless @ARGV; } if (not $opt_u and @ARGV and $ARGV[0] =~ m{^anonymous|/|:}) { $opt_u = shift @ARGV; } if ($opt_u) { $fexcgi = $1 if $opt_u =~ s:(.+)/::; ($user,$id) = split(':',$opt_u); if ($user =~ /^anonymous/) { $anonymous = $user; } elsif (not $id) { die $usage; } } unless ($fexcgi) { die "$0: no SEX URL found, use \"$0 -u SEX-URL/recipient\" or \"fexsend -I\"\n"; } unless ($user) { die "$0: no recipient found, use \"$0 -u SEX-URL/recipient\" or \"fexsend -I\"\n"; } } else { # sexsend $opt_g = 0; getopts('hguvqVTt:') or die $usage; die $usage if $opt_h; if ($opt_V) { print "Version: $version\n"; exit unless @ARGV; } if ($opt_t and $opt_t =~ /^\d+$/) { $timeout = "&timeout=$opt_t"; } my $save_user = $user; $user = shift or die $usage; $fexcgi = $1 if $user =~ s:(.+)/::; if ($user =~ /^anonymous/) { die "$0: need SEX-URL with anonymous SEX\n" unless $fexcgi; $mode = 'anonymous'; } elsif ($user eq 'public') { unless ($id) { die "$0: public SEX not possible without FEXID, set it with \"fexsend -I\"\n"; } $mode = $user; $user = $save_user; } elsif ($user eq '.') { open $idf,$idf or die "$0: no $idf\n"; $_ = <$idf>; $user = <$idf>||''; chomp $user; } else { unless ($fexcgi) { die "$0: no SEX URL found, use \"$0 SEX-URL/recipient\" or \"fexsend -I\"\n"; } } } &get_ssl_env; $fexcgi =~ s(^http://)()i; $fexcgi =~ s(/fup.*)(); $server = $fexcgi; if ($server =~ s(^https://)()i) { $port = 443 } elsif ($server =~ /:(\d+)/) { $port = $1 } else { $port = 80 } $server =~ s([:/].*)(); ## set up tcp/ip connection # $iaddr = gethostbyname($server) # or die "$0: cannot find ip-address for $server $!\n"; # socket(SH,PF_INET,SOCK_STREAM,getprotobyname('tcp')) or die "$0: socket $!\n"; # connect(SH,sockaddr_in($port,$iaddr)) or die "$0: connect $!\n"; # warn "connecting $server:$port user=$user\n"; if ($port == 443) { if ($opt_v and %SSL) { foreach my $v (keys %SSL) { printf "%s => %s\n",$v,$SSL{$v}; } } eval "use IO::Socket::SSL"; die "$0: cannot load IO::Socket::SSL\n" if $@; $SH = IO::Socket::SSL->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp', %SSL ); } else { $SH = IO::Socket::INET->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp', ); } die "cannot connect $server:$port - $!\n" unless $SH; warn "TCPCONNECT to $server:$port\n" if $opt_v; # autoflush $SH 1; autoflush STDERR; $SIG{PIPE} = \&sigpipehandler; if ($0 eq 'sexget' or $0 eq 'fuckme') { $stream = "&stream=" . shift if @ARGV; if ($anonymous) { $cid = 'anonymous'; } elsif ($id eq 'public') { $cid = 'public'; } else { $cid = query_sid($server,$port,$id); } request("GET /sex?BS=$bs&user=$user&ID=$cid$stream HTTP/1.0"); transfer($SH,STDOUT); # print while sysread $SH,$_,$bs; exit; } if ($0 eq 'sexxx') { $stream = "&stream=" . ($opt_s || 'xx'); if (@ARGV) { warn "streaming:\n"; open my $tar,'-|','tar',"cv${opt_c}f",'-',@ARGV or die "$0: cannot run tar - $!\n"; request("POST /sex?BS=$bs&user=$user$type$stream HTTP/1.0"); transfer($tar,$SH); # while (read $tar,$_,$bs) { syswrite $SH,$_ } } else { $cid = query_sid($server,$port,$id); request("GET /sex?BS=$bs&user=$user&ID=$cid$stream HTTP/1.0"); $opt_c = 'z' if $H{'CONTENT-TYPE'} =~ /gzip/i; if (-t STDOUT) { print "extracting from stream:\n"; open $out,"|tar xv${opt_c}f -" or die "$0: cannot run tar - $!\n"; } else { if ($opt_c) { open $out,"|gzip -d" or die "$0: cannot run gunzip - $!\n"; } else { $out = *STDOUT; } } print {$out} $_ while sysread $SH,$_,$bs; } exit; } # sexsend $stream = "&stream=" . shift if @ARGV; if ($mode eq 'anonymous') { unless ($opt_q) { print "http://$server:$port/sex?user=$user&ID=anonymous$stream\n"; printf "http://$server:$port/sex?%s\n", encode_b64("user=$user&ID=anonymous$stream"); } $mode = "&mode=anonymous"; } elsif ($mode eq 'public') { die "$0: need user/ID when sending to public, set it with fexsend -I\n" unless $user and $id; unless ($opt_q) { print "http://$server:$port/sex?user=$user&ID=public$stream\n"; printf "http://$server:$port/sex?%s\n", encode_b64("user=$user&ID=public$stream"); } $cid = query_sid($server,$port,$id); $mode = "&ID=$cid&mode=public"; } else { # $user = checkalias($user) unless $opt_d; } request("POST /sex?BS=$bs&user=$user$mode$type$timeout$stream HTTP/1.0"); print STDERR "--> (streaming ...)\n" if $opt_v; transfer(STDIN,$SH); exit; sub transfer { my $source = shift; my $destination = shift; my ($t0,$t1,$tt); my ($B,$b,$bt); $t0 = $t2 = time; $tt = $t0-1; $t1 = 0; while ($b = sysread $source,$_,$bs) { print {$destination} $_ or die "$0: link failure - $!\n"; $B += $b; $bt += $b; $t2 = time; if ($t2>$t1) { if ($opt_g) { if ($B>2*M) { printf STDERR "%d MB %d kB/s \r", int($B/M),int($bt/k/($t2-$tt)); } else { printf STDERR "%d kB %d kB/s \r", int($B/k),int($bt/k/($t2-$tt)); } } $t1 = $t2; if ($t2-$tt>10) { sleep 1; # be nice to bandwith $bt = 0; $tt = $t2; } } } die "$0: no stream data\n" unless $B; $tt = (time-$t0)||1; if ($opt_v or $opt_g) { if ($B>2097152) { printf STDERR "transfered: %d MB in %d s with %d kB/s\n", int($B/1048576),$tt,int($B/1024/$tt); } elsif($B>2048) { printf STDERR "transfered: %d kB in %d s with %d kB/s\n", int($B/1024),$tt,int($B/1024/$tt); } else { printf STDERR "transfered: %d B in %d s with %d kB/s\n", $B,$tt,int($B/1024/$tt); } } } sub request { my $req = shift; print STDERR "--> $req\n" if $opt_v; syswrite $SH,"$req\r\n"; syswrite $SH,"User-Agent: sexsend\r\n"; syswrite $SH,"\r\n"; for (;;) { unless (defined($_ = &getline)) { die "$0: server has closed the connection\n"; } if (/^HTTP\/[\d\.]+ 200/) { print STDERR "<-- $_" if $opt_v; last; } elsif (/^HTTP\/[\d\.]+ 199/) { print STDERR "<-- $_" if $opt_v; } else { if ($opt_v) { print STDERR "<-- $_"; exit 3; } else { s:^HTTP/[ \d\.]+::; s/\r//; die "$0: server response: $_"; } } } while (defined($_ = &getline)) { last if /^\s*$/; $H{uc($1)} = $2 if /(.+):\s*(.+)/; print STDERR "<-- $_" if $opt_v; } } # check for (mutt) alias sub checkalias { my $to = shift; if ($to !~ /@/ and open F,$ENV{HOME}.'/.mutt/aliases') { while () { next if /,/; if (/^alias $to\s/i) { chomp; s/\s*#.*//; s/\s+$//; s/.*\s+//; s///; $to = $_; warn "$0: found alias, using address $to\n"; die unless $to; last; } } close F; } return $to; } sub despace { foreach (@_) { s/^\s+//; s/\s+$//; } } sub query_sid { my ($server,$port,$id) = @_; my $req; local $_; $req = "GET SID HTTP/1.1"; print STDERR "--> $req\n" if $opt_v; syswrite $SH,"$req\r\n\r\n"; $_ = &getline; unless (defined $_ and /\w/) { print STDERR "\n" if $opt_v; die "$0: no response from server\n"; } s/\r//; if (/^HTTP.* 201 (.+)/) { print STDERR "<-- $_" if $opt_v; $id = 'MD5H:'.md5_hex($id.$1); while (defined($_ = &getline)) { s/\r//; last if /^\n/; print STDERR "<-- $_" if $opt_v; } } else { die "$0: $server does not support session ID\n"; } return $id; } sub sigpipehandler { local $_ = ''; $SIG{ALRM} = sub { }; alarm(1); $_ = &getline||''; if (/^HTTP.* \d+ (.*)/) { if ($opt_v) { die "\n$0: server error: @_\n"; } else { die "\n$0: server error: $1\n"; } } else { die "\n$0: got SIGPIPE (server closed connection)\n"; } } # read one text line from $SH; sub getline { my $line = ''; my $c; local $SIG{ALRM} = sub { die "$0: timeout while waiting for server reply\n" }; alarm($opt_t||300); # must use sysread to avoid perl line buffering while (sysread $SH,$c,1) { $line .= $c; last if $c eq "\n"; } alarm(0); return $line; } # from MIME::Base64::Perl sub decode_b64 { local $_ = shift; my $uu = ''; my ($i,$l); tr|A-Za-z0-9+=/||cd; s/=+$//; tr|A-Za-z0-9+/| -_|; return "" unless length; $l = (length) - 60; for ($i = 0; $i <= $l; $i += 60) { $uu .= "M" . substr($_,$i,60); } $_ = substr($_,$i); if (length) { $uu .= chr(32 + (length)*3/4) . $_; } return unpack ("u",$uu); } ### common functions ### sub mtime { my @d = localtime((stat shift)[9]); return sprintf('%d%02d%02d',$d[5]+1900,$d[4]+1,$d[3]); } sub urldecode { local $_ = shift; s/\%([a-f\d]{2})/chr(hex($1))/ige; return $_; } sub get_ssl_env { # set SSL/TLS options $SSL{SSL_verify_mode} = $ENV{SSLVERIFY} if defined($ENV{SSLVERIFY}); foreach my $opt (qw( SSL_version SSL_cipher_list SSL_verify_mode SSL_ca_path SSL_ca_file) ) { my $env = uc($opt); $env =~ s/_//g; $SSL{$opt} = $ENV{$env} if defined($ENV{$env}); } if ($SSL{SSL_verify_mode}) { &search_ca; unless ($SSL{SSL_ca_path} or $SSL{SSL_ca_file}) { die "$0: \$SSLVERIFYMODE, but not valid \$SSLCAPATH or \$SSLCAFILE\n"; } } elsif (defined($SSL{SSL_verify_mode})) { # user has set SSLVERIFY=0 ! } else { &search_ca; $SSL{SSL_verify_mode} = 1 if $SSL{SSL_ca_path} or $SSL{SSL_ca_file}; } } sub search_ca { local $_; return if $SSL{SSL_ca_file} or $SSL{SSL_ca_path}; foreach (qw(/etc/ssl/certs/ca-certificates.crt)) { if (-f) { $SSL{SSL_ca_file} = $_; return; } } foreach (qw(/etc/ssl/certs /etc/pki/tls/certs)) { if (-f) { $SSL{SSL_ca_path} = $_; return; } } } sub serverconnect { my ($server,$port) = @_; my $connect = "CONNECT $server:$port HTTP/1.1"; local $_; if ($proxy) { tcpconnect(split(':',$proxy)); if ($https) { printf "--> %s\n",$connect if $opt_v; nvtsend($connect,""); $_ = <$SH>; s/\r//; printf "<-- $_"if $opt_v; unless (/^HTTP.1.. 200/) { die "$0: proxy error : $_"; } &enable_ssl; $SH = IO::Socket::SSL->start_SSL($SH,%SSL); } } else { tcpconnect($server,$port); } # if ($https and $opt_v) { # printf "%s\n",$SH->get_cipher(); # } } # set up tcp/ip connection sub tcpconnect { my ($server,$port) = @_; if ($SH) { close $SH; undef $SH; } if ($https) { # eval "use IO::Socket::SSL qw(debug3)"; &enable_ssl; $SH = IO::Socket::SSL->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp', %SSL ); } else { $SH = IO::Socket::INET->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp', ); } if ($SH) { autoflush $SH 1; binmode $SH; } else { die "$0: cannot connect $server:$port - $@\n"; } print "TCPCONNECT to $server:$port\n" if $opt_v; } sub enable_ssl { eval "use IO::Socket::SSL"; die "$0: cannot load IO::Socket::SSL\n" if $@; eval '$SSL{SSL_verify_mode} = 0 if Net::SSLeay::SSLeay() <= 9470143'; if ($opt_v) { foreach my $v (keys %SSL) { printf "%s => %s\n",$v,$SSL{$v}; } } } sub sendheader { my $sp = shift; my @head = @_; my $head; push @head,"Host: $sp"; foreach $head (@head) { print "--> $head\n" if $opt_v; print {$SH} $head,"\r\n"; } print "-->\n" if $opt_v; print {$SH} "\r\n"; } sub nvtsend { local $SIG{PIPE} = sub { $sigpipe = "@_" }; $sigpipe = ''; die "$0: internal error: no active network handle\n" unless $SH; die "$0: remote host has closed the link\n" unless $SH->connected; foreach my $line (@_) { print {$SH} $line,"\r\n"; if ($sigpipe) { undef $SH; return 0; } } return 1; } sub quote { local $_ = shift; s/([^\w\@\/%^,.=+_:+-])/\\$1/g; return $_; } sub debug { print "## DEBUG: @_\n" if $DEBUG; } # from MIME::Base64::Perl sub encode_b64 { my $res = ""; my $eol = "\n"; my $padding; pos($_[0]) = 0; $res = join '',map(pack('u',$_)=~ /^.(\S*)/, ($_[0]=~/(.{1,45})/gs)); $res =~ tr|` -_|AA-Za-z0-9+/|; $padding = (3-length($_[0])%3)%3; $res =~ s/.{$padding}$/'=' x $padding/e if $padding; return $res; } fex-20160919/bin/fbm0000755000174700017470000002246712770010173012166 0ustar fexfex#!/usr/bin/perl -w # F*EX benchmark # # Author: Ulli Horlacher # # Copyright: Perl Artistic use 5.006; use strict qw'vars subs'; use Config; use Socket; use IO::Handle; use IO::Socket::INET; use Getopt::Std; use Time::HiRes qw'time'; # use Smart::Comments; use constant k => 2**10; use constant M => 2**20; our ($SH,$windoof,$sigpipe,$useragent); our ($FEXSERVER); our $version = 20160919; # server defaults my $server = 'fex.rus.uni-stuttgart.de'; my $port = 80; my $proxy = ''; my $from = 'nettest'; my $to = $from; my $id = $from; my $proxy_prefix = ''; my $mb; my (@r,$r); my $bs = 2**16; my $timeout = 30; # server timeout $version ||= mtime($0); $0 =~ s:.*/::; my $usage = </dev/null`||''; chomp; s/^Description:\s+//; $useragent = "fbm-$version ($_)"; } $| = 1; autoflush STDERR; my @_ARGV = @ARGV; # save arguments our $opt_n = 0; our $opt_v = 0; our $opt_h = 0; our $opt_s = ''; our $opt_P = ''; getopts('hvnP:s:') or die $usage; if ($opt_h) { print $usage; exit; } if ($opt_P) { if ($opt_P =~ /^[\w.-]+:\d+/) { $proxy = $opt_P; } else { die "$0: proxy must be: SERVER:PORT\n"; } } $mb = shift or die $usage; $mb =~ /^\d+$/ or die $usage; # $port = $1 if $server =~ s/:(\d+)//; if ($opt_s) { ($server,$port) = split /:/,$opt_s; $port = 80 unless $port; } $server =~ s{http://}{}; $server =~ s{/.*}{}; if ($proxy) { if ($port == 80) { $proxy_prefix = "http://$server" } else { $proxy_prefix = "http://$server:$port" } } print "Testing $server:\n"; @r = formdatapost( from => $from, to => $to, id => $id, comment => $opt_n ? 'NOSTORE' : 'NOMAIL', keep => 1, autodelete => 'YES', ); if (not @r or not grep /\w/,@r) { die "$0: no response from server\n"; } if (($r) = grep /ERROR:/,@r) { $r =~ s/.*?:\s*//; $r =~ s/<.*//; die "$0: server error: $r\n"; } if (($r) = grep /^Location: http/,@r) { $r =~ s:.*(/fop/\w+/.+$):$1:; download($r); } else { download("/ddd/$mb"); } exit; sub formdatapost { my %P = @_; my ($boundary,$filename,$filesize,$length); my (@hh,@hb,@r,@pv); my ($t,$bt,$t0,$t1,$t2,$tt); my $buf = '#' x $bs; local $_; @hh = (); # HTTP header @hb = (); # HTTP body @r = (); serverconnect($server,$port); $boundary = randstring(48); $P{command} = 'CHECKRECIPIENT'; # HTTP POST variables @pv = qw'from to id command'; foreach my $v (@pv) { if ($P{$v}) { my $name = uc($v); push @hb,"--$boundary"; push @hb,"Content-Disposition: form-data; name=\"$name\""; push @hb,""; push @hb,$P{$v}; } } push @hb,"--$boundary--"; $length = length(join('',@hb)) + scalar(@hb)*2 + $mb*M; # HTTP header push @hh,"POST $proxy_prefix/fup HTTP/1.1"; push @hh,"Host: $server:$port"; push @hh,"User-Agent: $useragent"; push @hh,"Content-Length: $length"; push @hh,"Content-Type: multipart/form-data; boundary=$boundary"; push @hh,"Connection: close"; push @hh,''; if ($opt_v) { printf "--> $_\n" foreach (@hh,@hb); } nvtsend(@hh,@hb) or die "$0: server has closed the connection\n"; while (<$SH>) { s/[\r\n]+//; print "<-- $_\n" if $opt_v; push @r,$_; last if /^$/; } unless (@r and $r[0] =~ / 204 /) { $_ = $r[0] || ''; s/^HTTP.[.\d\s]+//; die "$0: server error: $_\n"; } @hh = (); # HTTP header @hb = (); # HTTP body @r = (); $filename = 'test_'.int(time*1000); serverconnect($server,$port); # HTTP POST variables @pv = qw'from to id keep autodelete comment filesize'; foreach my $v (@pv) { if ($P{$v}) { my $name = uc($v); push @hb,"--$boundary"; push @hb,"Content-Disposition: form-data; name=\"$name\""; push @hb,""; push @hb,$P{$v}; } } # at last, the file push @hb,"--$boundary"; push @hb,"Content-Disposition: form-data; name=\"FILE\"; filename=\"$filename\""; push @hb,"Content-Type: application/octet-stream"; push @hb,""; push @hb,""; push @hb,"--$boundary--"; $length = length(join('',@hb)) + scalar(@hb)*2 + $mb*M; $hb[-2] = '(file content)'; # HTTP header push @hh,"POST $proxy_prefix/fup HTTP/1.1"; push @hh,"Host: $server:$port"; push @hh,"User-Agent: $useragent"; push @hh,"Content-Length: $length"; push @hh,"Content-Type: multipart/form-data; boundary=$boundary"; push @hh,"Connection: close"; push @hh,''; if ($opt_v) { printf "--> $_\n" foreach (@hh,@hb); } pop @hb; pop @hb; nvtsend(@hh,@hb) or die "$0: server has closed the connection\n"; $t0 = $t2 = int(time); $t1 = 0; autoflush $SH 0; for (;;) { print {$SH} $buf or die "$0: server has closed the connection\n"; $b += $bs; $bt += $bs; $t2 = time; if (-t STDOUT and $t2-$t1>1) { # smaller block size is better on slow links if ($t1 and $bs>4096 and $bt/($t2-$t0)<65536) { $bs = 4096; $buf = '#' x $bs; } if ($bs>4096) { printf STDERR "upload: %s MB of %d MB, %d kB/s \r", int($bt/M), $mb, int($b/k/($t2-$t1)); } else { printf STDERR "upload: %s kB of %d MB, %d kB/s \r", int($bt/k), $mb, int($b/k/($t2-$t1)); } $t1 = $t2; $b = 0; } last if $bt >= $mb*M; } autoflush $SH 1; print {$SH} "\r\n--$boundary--\r\n"; while (<$SH>) { s/[\r\n]+//; print "<-- $_\n" if $opt_v; last if @r and $r[0] =~ / 204 / and /^$/ or /<\/html>/i; push @r,$_; } $tt = (time-$t0)||1; printf STDERR "upload: %d MB in %d s, %d kB/s \n", int($bt/M),$tt,int($bt/k/$tt); close $SH; undef $SH; return @r; } sub randstring { my $n = shift; my @rc = ('A'..'Z','a'..'z',0..9 ); my $rn = @rc; my $rs; for (1..$n) { $rs .= $rc[int(rand($rn))] }; return $rs; } sub serverconnect { my ($server,$port) = @_; my $connect = "CONNECT $server:$port HTTP/1.1"; local $_; if ($proxy) { tcpconnect(split(':',$proxy)); if ($port == 443) { printf "--> %s\n",$connect if $opt_v; nvtsend($connect,""); $_ = <$SH>; s/\r//; printf "<-- $_"if $opt_v; unless (/^HTTP.1.. 200/) { die "$0: proxy error : $_"; } eval "use IO::Socket::SSL"; die "$0: cannot load IO::Socket::SSL\n" if $@; $SH = IO::Socket::SSL->start_SSL($SH); } } else { tcpconnect($server,$port); } } # set up tcp/ip connection sub tcpconnect { my ($server,$port) = @_; if ($SH) { close $SH; undef $SH; } if ($port == 443) { eval "use IO::Socket::SSL"; die "$0: cannot load IO::Socket::SSL\n" if $@; $SH = IO::Socket::SSL->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp', ); } else { $SH = IO::Socket::INET->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp', ); } if ($SH) { autoflush $SH 1; } else { die "$0: cannot connect $server:$port - $@\n"; } print "TCPCONNECT to $server:$port\n" if $opt_v; } sub nvtsend { local $SIG{PIPE} = sub { $sigpipe = "@_" }; $sigpipe = ''; die "$0: internal error: no active network handle\n" unless $SH; die "$0: remote host has closed the link\n" unless $SH->connected; foreach my $line (@_) { print {$SH} $line,"\r\n"; if ($sigpipe) { undef $SH; return 0; } } return 1; } sub mtime { my @d = localtime((stat shift)[9]); return sprintf('%d%02d%02d',$d[5]+1900,$d[4]+1,$d[3]); } sub download { my $fop = shift; my ($file); my ($t0,$t1,$t2,$tt,$kBs,$b,$bt,$tb,$B,$buf); my $length = 0; local $_; serverconnect($server,$port); sendheader( "GET $proxy_prefix$fop HTTP/1.1", "User-Agent: $useragent", "Host: $server:$port", ); $_ = <$SH>; die "$0: no response from fex server $server\n" unless $_; s/\r//; if (/^HTTP\/[\d.]+ 2/) { warn "<-- $_" if $opt_v; while (<$SH>) { s/\r//; print "<-- $_" if $opt_v; last if /^\r?\n/; if (/^Content-length:\s*(\d+)/i) { $length = $1; } } } else { s/HTTP\/[\d.]+ \d+ //; die "$0: bad server reply: $_"; } $t0 = $t1 = $t2 = int(time); $tb = $B = 0; while ($B < $length and $b = read $SH,$buf,$bs) { $B += $b; $tb += $b; $bt += $b; $t2 = time; if (int($t2) > $t1) { $kBs = int($bt/k/($t2-$t1)); $kBs = int($tb/k/($t2-$t0)) if $kBs < 10; $t1 = $t2; $bt = 0; # smaller block size is better on slow links $bs = 4096 if $bs>4096 and $tb/($t2-$t0)<65536; printf STDERR "download: %d MB in %d s, %d kB/s \r", int($tb/M),$t2-$t0,$kBs; } } close $SH; $tt = $t2-$t0; $kBs = int($tb/k/($tt||1)); printf STDERR "download: %d MB in %d s, %d kB/s \n", int($tb/M),$tt,$kBs; } sub sendheader { my @head = @_; my $head; foreach $head (@head) { print "--> $head\n" if $opt_v; print {$SH} $head,"\r\n"; } print "-->\n" if $opt_v; print {$SH} "\r\n"; } fex-20160919/bin/afex0000755000174700017470000001032112770010173012327 0ustar fexfex#!/usr/bin/perl -w # client for anonymous FEX or SEX # # Author: Ulli Horlacher # # Perl Artistic Licence $fexserver = ''; $0 =~ s:.*/::;; $u = $ENV{AFEX} || $fexserver || &guessserver; $u = "http://$u" if $u !~ /^http/; if (@ARGV and $ARGV[0] eq '-h' or not @ARGV and -t STDIN) { &usage } $opt_v = (@ARGV and $ARGV[0] eq '-v') ? shift @ARGV : ''; if ($0 eq 'asex') { $a = "$u/anonymous"; if (-t STDIN and @ARGV and "@ARGV" =~ /^(\d+)( -)?$/) { $id = $1; if ($2) { vexec("sexget $opt_v $a $id | tar xvf -"); } else { vexec(ws("sexget $opt_v $a $id")); } } else { if (@ARGV and $ARGV[0] =~ /^\d+$/) { $id = shift @ARGV; } else { $id = sprintf("%06d",rand(1000000)); } print "# commands for SEX recipient:\n"; if (@ARGV) { print "wget -qO- $u/sex?anonymous=$id | tar xvf -\n"; print "asex $id -\n"; print "# streaming files and waiting for SEX recipient:\n"; vexec("tar cvf - @ARGV | sexsend -q $opt_v $a $id"); } else { print "wget -qO- $u/sex?anonymous=$id\n"; print "asex $id\n"; vexec(ws("sexsend -q $opt_v $a $id")); } } exit; } if ($0 eq 'afex') { if ("@ARGV" =~ /^-(\d+)$/) { $n = $1; $cmd = "wget -qO/dev/null $u/fop/anonymous/anonymous/afex_$n.tar?DELETE"; vsystem(ws($cmd)); print "not " if $?; print "deleted\n"; exit; } # download if (-t STDIN and "@ARGV" =~ /^(\d+)( -)?$/) { $id = $1; $nq = $2; $u .= "/fop/anonymous/anonymous/afex_$id.tar"; if ($nq) { vexec("fexget $opt_v -s- $u | tar xvf -"); } else { $aft = "/tmp/afex_$id.tar"; $cmd = "fexget $opt_v -s- $u >$aft"; vsystem($cmd); if (`file $aft` =~ /tar archive/) { print "Files in archive:\n"; $cmd = "tar tvf $aft"; vsystem(ws($cmd)); print "extract these files (Y/n)? "; if ((||'y') =~ /^[Yy\n]/) { $cmd = "tar xvf $aft"; vsystem(ws($cmd)); unlink $aft; } else { print "keeping $aft\n"; } } else { open $aft,$aft or die "$0: cannot open $aft = $!\n"; unlink $aft; print while read($aft,$_,65536); } } exit; } # upload else { if (@ARGV and $ARGV[0] =~ /^\d+$/) { $id = shift @ARGV; } else { $id = sprintf("%06d",rand(1000000)); } $aft = "afex_$id.tar"; my $durl ="$u/fop/anonymous/anonymous/$aft??ID=ANONYMOUS"; if (`wget -S --spider $durl 2>&1` =~ /X-Location:/) { die "$0: afex $id already exists - choose another ID\n"; } @fexsend = ws("fexsend $opt_v -o -K -k 1"); if (@ARGV) { vsystem(@fexsend,'-a',$aft,@ARGV,"$u/anonymous"); exit $? if $?; } elsif (not -t STDIN) { $aft = "/tmp/$aft"; open $aft,'>',$aft or die "$0: cannot write $aft - $!\n"; print {$aft} $_ while read(STDIN,$_,65536); close $aft; $s = vsystem(@fexsend,$aft,"$u/anonymous"); unlink $aft; exit $s if $s; } else { die "say captain, say WHOT?!"; } print "For download use:\n"; print "$u//$aft\n" if -t STDIN; print "afex $id\n"; } exit; } &usage; sub guessserver { my $fexserver = ''; my $rc = '/etc/resolv.conf'; local $_; open $rc,$rc or die "$0: cannot open $rc - $!\n"; while (<$rc>) { if (/^\s*domain\s+([\w.-]+)/) { $fexserver = "http://fex.$1"; last; } if (/^\s*search\s+([\w.-]+)/) { $fexserver = "http://fex.$1"; } } close $rc; return $fexserver; } sub ws { local $_ = shift; return split; } sub vexec { warn "@_\n" if $opt_v; exec @_; } sub vsystem { warn "@_\n" if $opt_v; system @_; } sub usage { if ($0 eq 'afex') { print "file input usage: $0 [ID] files...\n"; print "file output usage: $0 ID [-]\n"; print "pipe input usage: ... | $0 [ID]\n"; print "pipe output usage: $0 ID | ...\n"; print "delete usage: $0 -ID\n"; exit; } if ($0 eq 'asex') { print "file input usage: $0 [ID] files...\n"; print "file output usage: $0 ID -\n"; print "pipe input usage: ... | $0 [ID]\n"; print "pipe output usage: $0 ID | ...\n"; exit; } die "program name must be a afex or asex, not $0\n"; } fex-20160919/bin/zz0000755000174700017470000006106212770010174012060 0ustar fexfex#!/usr/bin/perl -w # # vv : visual versioning # zz : generic shell clip board # ezz : clip board editor # # http://fex.rus.uni-stuttgart.de/fstools/vv.html # http://fex.rus.uni-stuttgart.de/fstools/zz.html # # by Ulli Horlacher # # Perl Artistic Licence # # vv is a script to handle file versions: # list, view, recover, diff, purge, migrate, save, delete # # vv is an extension to emacs idea of backup~ files # # File versions are stored in local subdirectory .versions/ # # To use vv with jed, install to your jed library path: # # http://fex.rus.uni-stuttgart.de/sw/share/jedlib/vv.sl # # To use vv with vim, add to your .vimrc: # # autocmd BufWritePre * execute '! vv -s ' . shellescape(@%) # autocmd BufWritePost * execute '! vv -b ' . shellescape(@%) # # To use vv with emacs, add to your .emacs: # # (add-hook 'before-save-hook (lambda () (shell-command ( # concat "vv -s " (shell-quote-argument (buffer-file-name)))))) # (add-hook 'after-save-hook (lambda () (shell-command ( # concat "vv -b " (shell-quote-argument (buffer-file-name)))))) # (setq make-backup-files nil) # # To use vv with ANY editor, first set: # # export EDITOR=your_favourite_editor # alias ve='vv -e' # # and then edit your file with: # # ve file # # $HOME/.vvrc is the config file for vv # 2013-04-15 initial version # 2013-04-16 added options -m and -v # 2013-04-18 added option -s # 2013-04-22 realfilename() fixes symlink problematics # 2013-04-22 use rsync instead of cp # 2013-04-23 added option -I # 2013-04-23 renamed from jedv to vv # 2013-04-24 added options -e -0 # 2013-05-09 added option -R # 2013-05-22 modified option -d to double argument # 2013-05-22 added vvrc with $exclude and @diff # 2013-07-05 fixed bug potential endless loop in rotate() # 2014-04-16 added change-file-test for opt_s (needs .versions/$file) # 2014-04-18 added option -b : save backup # 2014-05-02 fixed bug wrong file ownership when using as root # 2014-06-18 options -r -d -v : parameter is optional, default is 1 # 2014-06-18 fixed (stupid!) bug option -s does only sometimes saving # 2014-06-20 options -d -v : argument is optional, default is last file # 2014-07-22 fixed bug no (new) backup version 0 on option -r # 2014-11-14 added option -D : delete last saved version # 2014-11-14 make .versions/ mode 777 if parent directory is world writable # 2015-03-19 allow write access by root even if file and .versions/ have different owners # 2015-03-20 better error formating for jed # 2015-06-02 added option -r . to restore last saved backup # 2016-03-07 added options -M -L # 2016-03-08 renamed option -I to -H # 2016-05-02 added -A option to preserve ACLs with rsync # 2016-06-07 option -v : use PAGER=cat if STDOUT is not a tty # 2016-06-08 added zz, ezz and installer vvzz # 2016-07-06 avoid empty $ZZ versioning # 2016-09-12 added option -q quiet mode use Getopt::Std; use File::Basename; use Digest::MD5 'md5_hex'; use Cwd 'abs_path'; $prg = abs_path($0); $0 =~ s:.*/::; $ZZ = $ENV{ZZ} || "$ENV{HOME}/.zz"; &install if $0 eq 'vvzz'; &zz if $0 eq 'zz'; &ezz if $0 eq 'ezz'; # vv $usage = <; $_ = <$prg>; while (<$prg>) { last if /^\s*$/ or /^#\s*\d\d\d\d-\d\d-\d\d/; print; } exit; } if ($opt_r) { die "usage: $0 -r version-number file\n" unless @ARGV; if ($ARGV[0] =~ /^(\d\d?|\.)$/) { $opt_r = shift } else { $opt_r = 1 } die "usage: $0 -r version-number file\n" if scalar @ARGV != 1; } if ($opt_d) { if (@ARGV and $ARGV[0] =~ /^\d\d?(:\d\d?)?$/) { $opt_d = shift } else { $opt_d = 1 } &check_ARGV; die "usage: $0 -d version-number file\n" unless @ARGV; } if ($opt_v) { if (@ARGV and $ARGV[0] =~ /^\d\d?$/) { $opt_v = shift } else { $opt_v = 1 } &check_ARGV; die "usage: $0 -v version-number file\n" unless @ARGV; } if ($0 eq 've' or $opt_e) { $a = pop @ARGV or die $usage; $opt_e = 1; } else { $a = shift @ARGV; die $usage if not $opt_r and @ARGV; } unless (-e $vvrc) { open $vvrc,'>',$vvrc or die "$0: cannot write $vvrc - $!\n"; print {$vvrc} q{ $exclude = q( \.tmp$ ^mutt-.+-\d+ ^#.*#$ ); @diff = qw'diff -u'; }; close $vvrc; } require $vvrc; if ($a) { $file = realfilename($a); $ofile = "$file~"; $bfile = basename($file); $dir = dirname($file); $vdir = "$dir/.versions"; $vfile = "$vdir/$bfile"; $vfile0 = "$vfile~0~"; $vfile1 = "$vfile~1~"; $vfile01 = "$vfile~01~"; # change eugid if root and version directory belongs user my @s = stat($vdir); if ($> == 0 and (not @s or $s[4])) { if (my @s = stat($a)) { $) = $s[5]; $> = $s[4]; } } if ($opt_r ne '.' and not ($opt_M or $opt_L)) { if (not -e $file and -s $vfile) { warn "$0: $a does not exist any more\n"; print "found $vfile - recover it? "; $_ = ; copy($vfile,$file,'.') if /^y/i; exit 0; } die "$0: $a does not exist\n" unless -e $file; die "$0: $a is not a regular file\n" if -l $file or not -f $file; } } else { $file = '*'; $vdir = ".versions"; } if ($opt_M) { if (-d $opt_M and not -l $opt_M) { my $vvv = "$opt_M/.versions"; mkdir $vvv; die "$0: cannot mkdir $vvv - $!\n" unless -d $vvv; opendir $vvv,$vvv or die "$0: cannot opendir $vvv - $!\n"; while (my $v = readdir($vvv)) { mv100("$opt_M/$1") if -f "$vvv/$v" and $v =~ /(.+)~1~$/; } close $vvv; $vvv .= "/.versions"; unless (-d $vvv) { mkdir $vvv or die "$0: cannot mkdir $vvv - $!\n"; } $vvv .= "/n"; unlink $vvv; symlink 100,$vvv or die "$0: cannot create $vvv - $!\n"; } else { die "usage: $0 -M file\n" if @ARGV or $opt_r; mv100($opt_M); } exit; } if ($opt_L) { if (-d $opt_L and not -l $opt_L) { my $vvv = "$opt_L/.versions"; mkdir $vvv; die "$0: cannot mkdir $vvv - $!\n" unless -d $vvv; opendir $vvv,$vvv or die "$0: cannot opendir $vvv - $!\n"; while (my $v = readdir($vvv)) { mv10("$opt_L/$1") if -f "$vvv/$v" and $v =~ /(.+)~01~$/; } closedir $vvv; $vvv .= "/.versions"; unless (-d $vvv) { mkdir $vvv or die "$0: cannot mkdir $vvv - $!\n"; } $vvv .= "/n"; unlink $vvv; symlink 10,$vvv or die "$0: cannot create $vvv - $!\n"; } else { die "usage: $0 -L file\n" if @ARGV or $opt_r; mv10($opt_L); } exit; } if ($opt_e) { die $usage unless $a; $editor = $ENV{EDITOR} or die "$0: environment variable EDITOR not set\n"; system(qw'vv -s',$file) if -f $file; # save current version system($editor,@ARGV,$file); exit $? if $?; unlink $ofile; # delete new file~ created by editor system(qw'vv -0',$file); # post rotating system(qw'vv -b',$file); # save backup exit; } if ($opt_v) { die "$0: no such file $bfile\n" unless $bfile; if (-f "$vfile~0$opt_v~") { $vfile .= "~0$opt_v~" } else { $vfile .= "~$opt_v~" } if (-f $vfile) { if (-t STDOUT) { if (($ENV{EDITOR}||$0) =~ /jed/) { $ENV{JEDINIT} = "SAVE_STATE=0"; exec 'jed',$vfile,qw'-tmp -f set_readonly(1)'; } elsif ($ENV{PAGER}) { exec $ENV{PAGER},$vfile; } else { exec 'view',$vfile; } } else { exec 'cat',$vfile; } } else { die "$0: no $vfile\n"; } exit; } if ($opt_p) { opendir $vdir,$vdir or die "$0: no $vdir\n"; while ($vfile = readdir($vdir)) { next unless -f "$vdir/$vfile"; $bfile = $vfile; $bfile =~ s/~\d\d?~$//; if (not -f $bfile or -l $bfile) { unlink "$vdir/$vfile"; $purge{$bfile}++; } } if (@purge = keys %purge) { foreach $p (@purge) { printf "%2d %s~ purged\n",$purge{$p},$p; } } exit; } if ($opt_m) { migrate('.'); exit; } if (length($opt_r)) { die "$0: no such file $bfile\n" unless $bfile; if ($opt_r eq '.') { die "$0: no $vfile\n" unless -f $vfile; copy($vfile,$file,$opt_r); } else { if ($opt_r =~ /^\d$/ and -f "$vfile~0$opt_r~") { $vfile .= "~0$opt_r~" } else { $vfile .= "~$opt_r~" } die "$0: no version $opt_r for $file\n" unless -f $vfile; if ($nfile = shift @ARGV) { copy($vfile,$nfile); } else { copy($file,$vfile0) if mtime($file) > mtime($vfile0); copy($vfile,$file); } } exit; } if (length($opt_d)) { die "$0: no such file $bfile\n" unless $bfile; @diff = qw'diff -u' unless @diff; if ($opt_d =~ /^(\d\d?):(\d\d?)$/) { if (-f "$vdir/$bfile~0$1~" and -f "$vdir/$bfile~0$2~") { exec @diff,"$vdir/$bfile~0$2~","$vdir/$bfile~0$1~" } else { exec @diff,"$vdir/$bfile~$2~","$vdir/$bfile~$1~" } } else { if (-f "$vdir/$bfile~0$opt_d~") { exec @diff,"$vdir/$bfile~0$opt_d~",$file; } else { exec @diff,"$vdir/$bfile~$opt_d~",$file; } } exit $!; } if ($opt_s) { die $usage unless $file; if ($exclude) { $exclude =~ s/^\s+//; $exclude =~ s/\s+$//; $exclude =~ s/\s+/|/g; if ($bfile =~ /$exclude/) { warn "\r\n$0: ignoring $bfile\n"; exit; } } unless (-d $vdir) { mkdir $vdir or die "$0: cannot mkdir $vdir - $!\n"; } chmod 0777,$vdir if (stat $dir)[2] & 00002; # migrate old file~ to versions if (-f $ofile and not -l $ofile and -r $ofile) { $vfn = rotate($vfile); rename($ofile,$vfn); } # rotate and save if file has changed if (-f $vfile1) { if (md5f($vfile1) ne md5f($file)) { $vfn = rotate($vfile); copy($file,$vfn); } exit; } # rotate and save if file has changed if (-f $vfile01) { if (md5f($vfile01) ne md5f($file)) { $vfn = rotate($vfile); copy($file,$vfn); } exit; } # save new file if ((readlink("$vdir/.versions/n")||10) == 100) { copy($file,$vfile01); } else { copy($file,$vfile1); } exit; } # backup version if ($opt_b) { die $usage unless $file; unless (-d $vdir) { mkdir $vdir or die "\r\n$0: cannot mkdir $vdir - $!\n"; } copy($file,$vfile); if ($ENV{VIMRUNTIME}) { print "\n"; } else { warn "$file --> $vfile\n" unless $opt_q; } exit; } # special post rotating from -e if ($opt_0) { my @sb = stat $file or die "$0: $file - $!\n"; if (-f $vfile1) { while (my @sv = stat $vfile1) { # no version change? if ($sb[7] == $sv[7] and $sb[9] == $sv[9]) { # rotate back rb10($vfile); } else { last; } } } if (-f $vfile01) { while (my @sv = stat $vfile01) { # no version change? if ($sb[7] == $sv[7] and $sb[9] == $sv[9]) { # rotate back rb10($vfile); } else { last; } } } exit; } # delete last version, roll back if ($opt_D) { die "usage: $0 -D file\n" unless $vfile1 or $vfile01; stat $file or die "$0: $file - $!\n"; # 0 version? if (-f $vfile0) { unlink $vfile0; } else { # rotate back rb10($vfile) if -f $vfile1; rb100($vfile) if -f $vfile01; } exec $0,'-l',$file; exit; } # default! if ($opt_l) { `stty -a` =~ /columns (\d+)/; $tw = ($1 || 80)-36; if (opendir $vdir,$vdir) { while ($vfile = readdir($vdir)) { if (-f "$vdir/$vfile") { if ($bfile) { if ($vfile =~ /^\Q$bfile\E~(\d\d?)~$/) { push @{$v{$file}},$1; } } else { if ($vfile =~ /^(.+)~(\d\d?)~$/) { push @{$v{$1}},$2; } else { push @{$v{$vfile}},0; } } } } closedir $vdir; $ct = ''; foreach $file (sort keys %v) { if (not -f $file or -l $file) { warn "$0: orphaned $file~\n"; next; } @v = sort @{$v{$file}}; if ($bfile) { @stat = stat $file or die "$0: $file - $!\n"; print "version bytes date time"; if (${'opt_+'}) { print " content"; $ct = content($file); $ct =~ s/(.{$tw}).+/$1*/; } print "\n"; if (length($v[0]) == 1) { $lf = "%s %10s %s %s\n" } else { $lf = "%2s %10s %s %s\n" } printf $lf,'.',size($stat[7]),isodate($stat[9]),$ct; foreach $v (@v) { $vfile = "$vdir/$bfile~$v~"; @stat = stat $vfile or next; if (${'opt_+'}) { $ct = content($vfile); $ct =~ s/(.{$tw}).+/$1*/; } printf $lf,int($v),size($stat[7]),isodate($stat[9]),$ct; } } else { my $n = scalar(@v); $n-- if $v[0] == 0; # do not count zero version printf "%d %s\n",$n,$file; } } } exit; } sub size { my $s = shift; if ($s > 9999999999) { $s = int($s/2**30).'G' } elsif ($s > 9999999) { $s = int($s/2**20).'M' } elsif ($s > 9999) { $s = int($s/2**10).'k' } return $s; } sub content { my $file = shift; my $ct; local $_; chomp ($ct = `file $file`); $ct =~ s/.*?: //; $ct =~ s/,.*//; if ($ct =~ /text/ and open $file,$file) { read $file,$_,1024; close $file; s/[\x00-\x20]+/ /g; s/^ //; s/ $//; $ct = '"'.$_.'"'; } return $ct; } sub isodate { my @d = localtime shift; return sprintf('%d-%02d-%02d %02d:%02d:%02d', $d[5]+1900,$d[4]+1,$d[3],$d[2],$d[1],$d[0]); } sub rotate { my $vf = shift; # version base file my $vf1 = "$vf~1~"; my $vf01 = "$vf~01~"; my ($vfi,$vfn); if (-f $vf1) { for (my $i = 8; $i >= 0; $i--) { $vfi = sprintf("%s~%d~",$vf,$i); $vfn = sprintf("%s~%d~",$vf,$i+1); if (-e $vfi) { rename $vfi,$vfn or die "$0: $vfi --> $vfn : $!\n"; } } # was there a version 0? if (-e $vf1) { my $bf = $vf; $bf =~ s:/\.versions/:/:; my @sb = stat $bf; my @sv = stat $vf1; # version change? (other size or mtime) if (@sb and @sv and $sb[7] == $sv[7] and $sb[9] == $sv[9]) { # same version unlink $vf1; } else { # other version rotate($vf); } } return "$vf~1~"; } elsif (-f $vf01) { for (my $i = 98; $i >= 0; $i--) { $vfi = sprintf("%s~%02d~",$vf,$i); $vfn = sprintf("%s~%02d~",$vf,$i+1); if (-e $vfi) { rename $vfi,$vfn or die "$0: $vfi --> $vfn : $!\n"; } } # was there a version 0? if (-e $vf01) { my $bf = $vf; $bf =~ s:/\.versions/:/:; my @sb = stat $bf; my @sv = stat $vf01; # version change? (other size or mtime) if (@sb and @sv and $sb[7] == $sv[7] and $sb[9] == $sv[9]) { # same version unlink $vf01; } else { # other version rotate($vf); } } return "$vf~01~"; } return "$vf~1~"; } sub copy { my ($from,$to,$restore) = @_; unless ($restore) { if (-l $file or not -f $file) { die "$0: $file is not a regular file\n"; } } if (open $to,'>>',$to) { close $to; if (system(qw'rsync -aA',$from,$to) == 0) { if ($ENV{VIMRUNTIME}) { print "\n"; } else { warn "$from --> $to\n" unless $opt_q; } } else { exit $?; } } else { die "\r\n$0: cannot write $to - $!\n"; } } sub realfilename { my $file = shift; return $file unless -e $file; if (-l $file) { my $link = readlink($file); if ($link !~ /^\// and $file =~ m:(.*/).:) { $link = $1 . $link; } return realfilename($link); } else { return $file; } } sub migrate { my $dir = shift; my $vdir = "$dir/.versions"; my $dfile; opendir $dir,$dir or die "$0: cannot read directory $dir - $!\n"; while ($file = readdir($dir)) { $dfile = "$dir/$file"; next if -l $dfile or $file eq '.' or $file eq '..'; if (-d $dfile and $opt_R and $file ne '.versions') { migrate($dfile); } elsif (-f $dfile and $file =~ /~$/) { if (-d $vdir) { for ($i = 8; $i > 0; $i--) { $n = $i+1; rename "$vdir/$file$i~","$vdir/$file$n~"; } } else { mkdir $vdir or die "$0: cannot mkdir $vdir - $!\n"; } $nfile = sprintf("%s/%s1~",$vdir,$file); rename $dfile,$nfile or die "$0: cannot move $dfile to $nfile - $!\n"; warn "$dfile --> $nfile\n" unless $opt_q; } } closedir $dir; } sub mtime { my @s = stat shift; return @s ? $s[9] : 0; } sub md5f { my $file = shift; my $md5 = 0; local $/; if (open $file,$file) { $md5 = md5_hex(<$file>); close $file; } return $md5; } # if ARGV is empty use last saved file as default file argument sub check_ARGV { local $_; local *V; if (not @ARGV) { if (-d '.versions' and open V,'ls -at .versions|') { while () { chomp; if (-f) { close V; s/~\d+~$//; @ARGV = ($_); return; } } } } } sub mv10 { my $file = shift; my $vfile = dirname($file).'/.versions/'.basename($file); die "$0: $file has no extended versions\n" unless -f "$vfile~01~"; for (my $i=1; $i<10; $i++) { my $vfile1 = "$vfile~$i~"; my $vfile2 = "$vfile~0$i~"; if (-f $vfile2) { warn "$vfile2 --> $vfile1\n" unless $opt_q; rename $vfile2,$vfile1 or die "$0: $!\n"; } } for (my $i=10; $i<100; $i++) { unlink "$vfile~$i~"; } } sub mv100 { my $file = shift; my $vfile = dirname($file).'/.versions/'.basename($file); die "$0: $file has already extended versions\n" if -f "$vfile~01~"; die "$0: $file has no versions\n" unless -f "$vfile~1~"; for (my $i=1; $i<10; $i++) { my $vfile1 = "$vfile~$i~"; my $vfile2 = "$vfile~0$i~"; if (-f $vfile1) { warn "$vfile1 --> $vfile2\n" unless $opt_q; rename $vfile1,$vfile2 or die "$0: $!\n"; } } } # rotate back sub rb10 { my $vfile = shift; for (my $i = 1; $i <= 8; $i++) { my $vfi = sprintf("%s~%d~",$vfile,$i); my $vfn = sprintf("%s~%d~",$vfile,$i+1); if (-f $vfn) { rename $vfn,$vfi; } else { unlink $vfi if $i == 1; last; } } } # rotate back sub rb100 { my $vfile = shift; for (my $i = 1; $i <= 98; $i++) { my $vfi = sprintf("%s~%02d~",$vfile,$i); my $vfn = sprintf("%s~%02d~",$vfile,$i+1); if (-f $vfn) { rename $vfn,$vfi; } else { unlink $vfi if $i == 1; last; } } } sub pathsearch { my $prg = shift; foreach my $dir (split(':',$ENV{PATH})) { return "$dir/$prg" if -x "$dir/$prg"; } } # zz is the generic clip board program # # to use zz with vim, write to your .vimrc: # # noremap zz> :w !zz # noremap zz< :r !zz -- sub zz { my $bs = 2**16; my $wm = '>'; my ($file,$tee,$x); if ("@ARGV" =~ /^(-h|--help)$/) { print <<'EOD'; zz is the generic clip board program. It can hold any data, ASCII or binary. The clip board itself is $ZZ (default: $HOME/.zz). See also the clip board editor "ezz". Limitation: zz does not work across accounts or hosts! Use xx instead. Options and modes are: "zz" show content of $ZZ "zz file(s)" copy file(s) content into $ZZ "zz -" write STDIN (keyboard, mouse buffer) to $ZZ "zz +" add STDIN (keyboard, mouse buffer) to $ZZ "... | zz" write STDIN from pipe to $ZZ "... | zz +" add STDIN from pipe to $ZZ "... | zz -" write STDIN from pipe to $ZZ and STDOUT "zz | ..." write $ZZ to pipe "... | zz | ..." save pipe data to $ZZ (like tee) "zz --" write $ZZ to STDOUT "zz -v" show clip board versions (history) "zz -1" write $ZZ version 1 to STDOUT "zz -9" write $ZZ version 9 to STDOUT Examples: zz *.txt ls -l | zz zz | wc -l (within vi) :w !zz (within vi) :r !zz (within mutt) |zz EOD exit; } if ("@ARGV" eq '-v') { exec qw'vv -+l',$ZZ; } if ("@ARGV" =~ /^-(\d)$/) { exec "vv -v $1 '$ZZ' | cat"; } # read mode if (-t STDIN and not @ARGV or "@ARGV" eq '--') { exec 'cat',$ZZ; } # write mode system "vv -s '$ZZ' >/dev/null 2>&1" if -s $ZZ; if (@ARGV and $ARGV[0] eq '+') { shift @ARGV; $wm = '>>'; } if ("@ARGV" eq '-') { @ARGV = (); $tee = 1 unless -t STDIN; } $tee = 1 unless @ARGV or -t STDIN or -t STDOUT; $bs = 2**12 if $tee; open $ZZ,$wm,$ZZ or die "$0: cannot write $ZZ - $!\n"; if (@ARGV) { while ($file = shift @ARGV) { if (-f $file) { if (open $file,$file) { while (read($file,$x,$bs)) { my $s = syswrite $ZZ,$x; defined($s) or die "$0: cannot write to $ZZ - $!\n"; } close $file; } else { warn "$0: cannot read $file - $!\n"; } } elsif (-e $file) { warn "$0: $file is not a regular file\n"; } else { warn "$0: $file does not exist\n"; } } close $ZZ; $ZZ1 = $ZZ.'~1~'; $ZZ1 =~ s:(.*)/(.*):$1/.versions/$2:; if (-e $ZZ and not -s $ZZ and -s $ZZ1 ) { system qw'rsync -aA',$ZZ1,$ZZ; } } else { while (read(STDIN,$x,$bs)) { syswrite $ZZ,$x; syswrite STDOUT,$x if $tee; } } exit; } sub ezz { my $bs = 2**16; my $wm = '>'; my $editor = $ENV{EDITOR} || 'vi'; my ($out,$file,$x); $ENV{JEDINIT} = "SAVE_STATE=0"; if ("@ARGV" =~ /^(-h|--help)$/) { print <<'EOD'; ezz is the edit helper for the zz clip board program. The clip board itself is $ZZ (default: $HOME/.zz). Options and modes are: "ezz" edit $ZZ with $EDITOR "... | ezz" write STDIN from pipe to $ZZ and call $EDITOR "... | ezz +" add STDIN from pipe to $ZZ and call $EDITOR "ezz 'perl commands'" execute perl commands on $ZZ "ezz - 'perl commands'" execute perl commands on $ZZ and show result "ezz filter [args]" run filter [with args] on $ZZ "ezz - filter [args]" run filter [with args] on $ZZ and show result Examples: ls -l | ezz ezz 's/ /_/g' ezz head -3 ezz - head -3 EOD exit; } system "vv -s '$ZZ' >/dev/null 2>&1" if -s $ZZ; unless (-t STDIN) { if ("@ARGV" eq '+') { @ARGV = (); $wm = '>>'; } open $ZZ,$wm,$ZZ or die "$0: cannot write $ZZ - $!\n"; syswrite $ZZ,$x while read(STDIN,$x,$bs); close $ZZ; } if (@ARGV) { $out = shift @ARGV if $ARGV[0] eq '-'; $cmd = shift @ARGV or exec 'cat',$ZZ; rename $ZZ,"$ZZ~" or die "$0: cannot move $ZZ to $ZZ~ - $!\n"; $cmd = quotemeta $cmd; @ARGV = map { quotemeta } @ARGV; if (pathsearch($cmd)) { system "$cmd @ARGV <'$ZZ~'>'$ZZ'"; } else { system "perl -pe $cmd @ARGV <'$ZZ~'>'$ZZ'"; } if ($? == 0) { unlink "$ZZ~" } else { rename "$ZZ~",$ZZ } exec 'cat',$ZZ if $out; } else { exec $editor,$ZZ; } exit; } sub install { my ($dir); local $| = 1; print "Installation directory: "; $dir = ||''; chomp $dir; $dir =~ s:/+$::; $dir ||= '.'; if ($dir eq '.') { unlink qw'zz ezz vv'; link $prg,'zz' or die "$0: cannot create zz - $!\n"; link $prg,'ezz' or die "$0: cannot create ezz - $!\n"; rename $prg,'vv' or die "$0: cannot create vv - $!\n"; } else { die "$0: $dir does not exist\n" unless -e $dir; die "$0: $dir is not a directory\n" unless -d $dir; die "$0: $dir is not writable\n" unless -w $dir; chdir $dir or die "$0: cannot cd $dir - $!\n"; unlink qw'zz ezz vv'; system qw'rsync -a',$prg,'vv'; exit $? if $?; link 'vv','zz' or die "$0: cannot create $dir/zz - $!\n"; link 'vv','ezz' or die "$0: cannot create $dir/ezz - $!\n"; } print "Installation completed. See:\n"; print "\t$dir/vv -h\n"; print "\t$dir/zz -h\n"; print "\t$dir/ezz -h\n"; exit; } fex-20160919/bin/ezz0000755000174700017470000006106212770010173012224 0ustar fexfex#!/usr/bin/perl -w # # vv : visual versioning # zz : generic shell clip board # ezz : clip board editor # # http://fex.rus.uni-stuttgart.de/fstools/vv.html # http://fex.rus.uni-stuttgart.de/fstools/zz.html # # by Ulli Horlacher # # Perl Artistic Licence # # vv is a script to handle file versions: # list, view, recover, diff, purge, migrate, save, delete # # vv is an extension to emacs idea of backup~ files # # File versions are stored in local subdirectory .versions/ # # To use vv with jed, install to your jed library path: # # http://fex.rus.uni-stuttgart.de/sw/share/jedlib/vv.sl # # To use vv with vim, add to your .vimrc: # # autocmd BufWritePre * execute '! vv -s ' . shellescape(@%) # autocmd BufWritePost * execute '! vv -b ' . shellescape(@%) # # To use vv with emacs, add to your .emacs: # # (add-hook 'before-save-hook (lambda () (shell-command ( # concat "vv -s " (shell-quote-argument (buffer-file-name)))))) # (add-hook 'after-save-hook (lambda () (shell-command ( # concat "vv -b " (shell-quote-argument (buffer-file-name)))))) # (setq make-backup-files nil) # # To use vv with ANY editor, first set: # # export EDITOR=your_favourite_editor # alias ve='vv -e' # # and then edit your file with: # # ve file # # $HOME/.vvrc is the config file for vv # 2013-04-15 initial version # 2013-04-16 added options -m and -v # 2013-04-18 added option -s # 2013-04-22 realfilename() fixes symlink problematics # 2013-04-22 use rsync instead of cp # 2013-04-23 added option -I # 2013-04-23 renamed from jedv to vv # 2013-04-24 added options -e -0 # 2013-05-09 added option -R # 2013-05-22 modified option -d to double argument # 2013-05-22 added vvrc with $exclude and @diff # 2013-07-05 fixed bug potential endless loop in rotate() # 2014-04-16 added change-file-test for opt_s (needs .versions/$file) # 2014-04-18 added option -b : save backup # 2014-05-02 fixed bug wrong file ownership when using as root # 2014-06-18 options -r -d -v : parameter is optional, default is 1 # 2014-06-18 fixed (stupid!) bug option -s does only sometimes saving # 2014-06-20 options -d -v : argument is optional, default is last file # 2014-07-22 fixed bug no (new) backup version 0 on option -r # 2014-11-14 added option -D : delete last saved version # 2014-11-14 make .versions/ mode 777 if parent directory is world writable # 2015-03-19 allow write access by root even if file and .versions/ have different owners # 2015-03-20 better error formating for jed # 2015-06-02 added option -r . to restore last saved backup # 2016-03-07 added options -M -L # 2016-03-08 renamed option -I to -H # 2016-05-02 added -A option to preserve ACLs with rsync # 2016-06-07 option -v : use PAGER=cat if STDOUT is not a tty # 2016-06-08 added zz, ezz and installer vvzz # 2016-07-06 avoid empty $ZZ versioning # 2016-09-12 added option -q quiet mode use Getopt::Std; use File::Basename; use Digest::MD5 'md5_hex'; use Cwd 'abs_path'; $prg = abs_path($0); $0 =~ s:.*/::; $ZZ = $ENV{ZZ} || "$ENV{HOME}/.zz"; &install if $0 eq 'vvzz'; &zz if $0 eq 'zz'; &ezz if $0 eq 'ezz'; # vv $usage = <; $_ = <$prg>; while (<$prg>) { last if /^\s*$/ or /^#\s*\d\d\d\d-\d\d-\d\d/; print; } exit; } if ($opt_r) { die "usage: $0 -r version-number file\n" unless @ARGV; if ($ARGV[0] =~ /^(\d\d?|\.)$/) { $opt_r = shift } else { $opt_r = 1 } die "usage: $0 -r version-number file\n" if scalar @ARGV != 1; } if ($opt_d) { if (@ARGV and $ARGV[0] =~ /^\d\d?(:\d\d?)?$/) { $opt_d = shift } else { $opt_d = 1 } &check_ARGV; die "usage: $0 -d version-number file\n" unless @ARGV; } if ($opt_v) { if (@ARGV and $ARGV[0] =~ /^\d\d?$/) { $opt_v = shift } else { $opt_v = 1 } &check_ARGV; die "usage: $0 -v version-number file\n" unless @ARGV; } if ($0 eq 've' or $opt_e) { $a = pop @ARGV or die $usage; $opt_e = 1; } else { $a = shift @ARGV; die $usage if not $opt_r and @ARGV; } unless (-e $vvrc) { open $vvrc,'>',$vvrc or die "$0: cannot write $vvrc - $!\n"; print {$vvrc} q{ $exclude = q( \.tmp$ ^mutt-.+-\d+ ^#.*#$ ); @diff = qw'diff -u'; }; close $vvrc; } require $vvrc; if ($a) { $file = realfilename($a); $ofile = "$file~"; $bfile = basename($file); $dir = dirname($file); $vdir = "$dir/.versions"; $vfile = "$vdir/$bfile"; $vfile0 = "$vfile~0~"; $vfile1 = "$vfile~1~"; $vfile01 = "$vfile~01~"; # change eugid if root and version directory belongs user my @s = stat($vdir); if ($> == 0 and (not @s or $s[4])) { if (my @s = stat($a)) { $) = $s[5]; $> = $s[4]; } } if ($opt_r ne '.' and not ($opt_M or $opt_L)) { if (not -e $file and -s $vfile) { warn "$0: $a does not exist any more\n"; print "found $vfile - recover it? "; $_ = ; copy($vfile,$file,'.') if /^y/i; exit 0; } die "$0: $a does not exist\n" unless -e $file; die "$0: $a is not a regular file\n" if -l $file or not -f $file; } } else { $file = '*'; $vdir = ".versions"; } if ($opt_M) { if (-d $opt_M and not -l $opt_M) { my $vvv = "$opt_M/.versions"; mkdir $vvv; die "$0: cannot mkdir $vvv - $!\n" unless -d $vvv; opendir $vvv,$vvv or die "$0: cannot opendir $vvv - $!\n"; while (my $v = readdir($vvv)) { mv100("$opt_M/$1") if -f "$vvv/$v" and $v =~ /(.+)~1~$/; } close $vvv; $vvv .= "/.versions"; unless (-d $vvv) { mkdir $vvv or die "$0: cannot mkdir $vvv - $!\n"; } $vvv .= "/n"; unlink $vvv; symlink 100,$vvv or die "$0: cannot create $vvv - $!\n"; } else { die "usage: $0 -M file\n" if @ARGV or $opt_r; mv100($opt_M); } exit; } if ($opt_L) { if (-d $opt_L and not -l $opt_L) { my $vvv = "$opt_L/.versions"; mkdir $vvv; die "$0: cannot mkdir $vvv - $!\n" unless -d $vvv; opendir $vvv,$vvv or die "$0: cannot opendir $vvv - $!\n"; while (my $v = readdir($vvv)) { mv10("$opt_L/$1") if -f "$vvv/$v" and $v =~ /(.+)~01~$/; } closedir $vvv; $vvv .= "/.versions"; unless (-d $vvv) { mkdir $vvv or die "$0: cannot mkdir $vvv - $!\n"; } $vvv .= "/n"; unlink $vvv; symlink 10,$vvv or die "$0: cannot create $vvv - $!\n"; } else { die "usage: $0 -L file\n" if @ARGV or $opt_r; mv10($opt_L); } exit; } if ($opt_e) { die $usage unless $a; $editor = $ENV{EDITOR} or die "$0: environment variable EDITOR not set\n"; system(qw'vv -s',$file) if -f $file; # save current version system($editor,@ARGV,$file); exit $? if $?; unlink $ofile; # delete new file~ created by editor system(qw'vv -0',$file); # post rotating system(qw'vv -b',$file); # save backup exit; } if ($opt_v) { die "$0: no such file $bfile\n" unless $bfile; if (-f "$vfile~0$opt_v~") { $vfile .= "~0$opt_v~" } else { $vfile .= "~$opt_v~" } if (-f $vfile) { if (-t STDOUT) { if (($ENV{EDITOR}||$0) =~ /jed/) { $ENV{JEDINIT} = "SAVE_STATE=0"; exec 'jed',$vfile,qw'-tmp -f set_readonly(1)'; } elsif ($ENV{PAGER}) { exec $ENV{PAGER},$vfile; } else { exec 'view',$vfile; } } else { exec 'cat',$vfile; } } else { die "$0: no $vfile\n"; } exit; } if ($opt_p) { opendir $vdir,$vdir or die "$0: no $vdir\n"; while ($vfile = readdir($vdir)) { next unless -f "$vdir/$vfile"; $bfile = $vfile; $bfile =~ s/~\d\d?~$//; if (not -f $bfile or -l $bfile) { unlink "$vdir/$vfile"; $purge{$bfile}++; } } if (@purge = keys %purge) { foreach $p (@purge) { printf "%2d %s~ purged\n",$purge{$p},$p; } } exit; } if ($opt_m) { migrate('.'); exit; } if (length($opt_r)) { die "$0: no such file $bfile\n" unless $bfile; if ($opt_r eq '.') { die "$0: no $vfile\n" unless -f $vfile; copy($vfile,$file,$opt_r); } else { if ($opt_r =~ /^\d$/ and -f "$vfile~0$opt_r~") { $vfile .= "~0$opt_r~" } else { $vfile .= "~$opt_r~" } die "$0: no version $opt_r for $file\n" unless -f $vfile; if ($nfile = shift @ARGV) { copy($vfile,$nfile); } else { copy($file,$vfile0) if mtime($file) > mtime($vfile0); copy($vfile,$file); } } exit; } if (length($opt_d)) { die "$0: no such file $bfile\n" unless $bfile; @diff = qw'diff -u' unless @diff; if ($opt_d =~ /^(\d\d?):(\d\d?)$/) { if (-f "$vdir/$bfile~0$1~" and -f "$vdir/$bfile~0$2~") { exec @diff,"$vdir/$bfile~0$2~","$vdir/$bfile~0$1~" } else { exec @diff,"$vdir/$bfile~$2~","$vdir/$bfile~$1~" } } else { if (-f "$vdir/$bfile~0$opt_d~") { exec @diff,"$vdir/$bfile~0$opt_d~",$file; } else { exec @diff,"$vdir/$bfile~$opt_d~",$file; } } exit $!; } if ($opt_s) { die $usage unless $file; if ($exclude) { $exclude =~ s/^\s+//; $exclude =~ s/\s+$//; $exclude =~ s/\s+/|/g; if ($bfile =~ /$exclude/) { warn "\r\n$0: ignoring $bfile\n"; exit; } } unless (-d $vdir) { mkdir $vdir or die "$0: cannot mkdir $vdir - $!\n"; } chmod 0777,$vdir if (stat $dir)[2] & 00002; # migrate old file~ to versions if (-f $ofile and not -l $ofile and -r $ofile) { $vfn = rotate($vfile); rename($ofile,$vfn); } # rotate and save if file has changed if (-f $vfile1) { if (md5f($vfile1) ne md5f($file)) { $vfn = rotate($vfile); copy($file,$vfn); } exit; } # rotate and save if file has changed if (-f $vfile01) { if (md5f($vfile01) ne md5f($file)) { $vfn = rotate($vfile); copy($file,$vfn); } exit; } # save new file if ((readlink("$vdir/.versions/n")||10) == 100) { copy($file,$vfile01); } else { copy($file,$vfile1); } exit; } # backup version if ($opt_b) { die $usage unless $file; unless (-d $vdir) { mkdir $vdir or die "\r\n$0: cannot mkdir $vdir - $!\n"; } copy($file,$vfile); if ($ENV{VIMRUNTIME}) { print "\n"; } else { warn "$file --> $vfile\n" unless $opt_q; } exit; } # special post rotating from -e if ($opt_0) { my @sb = stat $file or die "$0: $file - $!\n"; if (-f $vfile1) { while (my @sv = stat $vfile1) { # no version change? if ($sb[7] == $sv[7] and $sb[9] == $sv[9]) { # rotate back rb10($vfile); } else { last; } } } if (-f $vfile01) { while (my @sv = stat $vfile01) { # no version change? if ($sb[7] == $sv[7] and $sb[9] == $sv[9]) { # rotate back rb10($vfile); } else { last; } } } exit; } # delete last version, roll back if ($opt_D) { die "usage: $0 -D file\n" unless $vfile1 or $vfile01; stat $file or die "$0: $file - $!\n"; # 0 version? if (-f $vfile0) { unlink $vfile0; } else { # rotate back rb10($vfile) if -f $vfile1; rb100($vfile) if -f $vfile01; } exec $0,'-l',$file; exit; } # default! if ($opt_l) { `stty -a` =~ /columns (\d+)/; $tw = ($1 || 80)-36; if (opendir $vdir,$vdir) { while ($vfile = readdir($vdir)) { if (-f "$vdir/$vfile") { if ($bfile) { if ($vfile =~ /^\Q$bfile\E~(\d\d?)~$/) { push @{$v{$file}},$1; } } else { if ($vfile =~ /^(.+)~(\d\d?)~$/) { push @{$v{$1}},$2; } else { push @{$v{$vfile}},0; } } } } closedir $vdir; $ct = ''; foreach $file (sort keys %v) { if (not -f $file or -l $file) { warn "$0: orphaned $file~\n"; next; } @v = sort @{$v{$file}}; if ($bfile) { @stat = stat $file or die "$0: $file - $!\n"; print "version bytes date time"; if (${'opt_+'}) { print " content"; $ct = content($file); $ct =~ s/(.{$tw}).+/$1*/; } print "\n"; if (length($v[0]) == 1) { $lf = "%s %10s %s %s\n" } else { $lf = "%2s %10s %s %s\n" } printf $lf,'.',size($stat[7]),isodate($stat[9]),$ct; foreach $v (@v) { $vfile = "$vdir/$bfile~$v~"; @stat = stat $vfile or next; if (${'opt_+'}) { $ct = content($vfile); $ct =~ s/(.{$tw}).+/$1*/; } printf $lf,int($v),size($stat[7]),isodate($stat[9]),$ct; } } else { my $n = scalar(@v); $n-- if $v[0] == 0; # do not count zero version printf "%d %s\n",$n,$file; } } } exit; } sub size { my $s = shift; if ($s > 9999999999) { $s = int($s/2**30).'G' } elsif ($s > 9999999) { $s = int($s/2**20).'M' } elsif ($s > 9999) { $s = int($s/2**10).'k' } return $s; } sub content { my $file = shift; my $ct; local $_; chomp ($ct = `file $file`); $ct =~ s/.*?: //; $ct =~ s/,.*//; if ($ct =~ /text/ and open $file,$file) { read $file,$_,1024; close $file; s/[\x00-\x20]+/ /g; s/^ //; s/ $//; $ct = '"'.$_.'"'; } return $ct; } sub isodate { my @d = localtime shift; return sprintf('%d-%02d-%02d %02d:%02d:%02d', $d[5]+1900,$d[4]+1,$d[3],$d[2],$d[1],$d[0]); } sub rotate { my $vf = shift; # version base file my $vf1 = "$vf~1~"; my $vf01 = "$vf~01~"; my ($vfi,$vfn); if (-f $vf1) { for (my $i = 8; $i >= 0; $i--) { $vfi = sprintf("%s~%d~",$vf,$i); $vfn = sprintf("%s~%d~",$vf,$i+1); if (-e $vfi) { rename $vfi,$vfn or die "$0: $vfi --> $vfn : $!\n"; } } # was there a version 0? if (-e $vf1) { my $bf = $vf; $bf =~ s:/\.versions/:/:; my @sb = stat $bf; my @sv = stat $vf1; # version change? (other size or mtime) if (@sb and @sv and $sb[7] == $sv[7] and $sb[9] == $sv[9]) { # same version unlink $vf1; } else { # other version rotate($vf); } } return "$vf~1~"; } elsif (-f $vf01) { for (my $i = 98; $i >= 0; $i--) { $vfi = sprintf("%s~%02d~",$vf,$i); $vfn = sprintf("%s~%02d~",$vf,$i+1); if (-e $vfi) { rename $vfi,$vfn or die "$0: $vfi --> $vfn : $!\n"; } } # was there a version 0? if (-e $vf01) { my $bf = $vf; $bf =~ s:/\.versions/:/:; my @sb = stat $bf; my @sv = stat $vf01; # version change? (other size or mtime) if (@sb and @sv and $sb[7] == $sv[7] and $sb[9] == $sv[9]) { # same version unlink $vf01; } else { # other version rotate($vf); } } return "$vf~01~"; } return "$vf~1~"; } sub copy { my ($from,$to,$restore) = @_; unless ($restore) { if (-l $file or not -f $file) { die "$0: $file is not a regular file\n"; } } if (open $to,'>>',$to) { close $to; if (system(qw'rsync -aA',$from,$to) == 0) { if ($ENV{VIMRUNTIME}) { print "\n"; } else { warn "$from --> $to\n" unless $opt_q; } } else { exit $?; } } else { die "\r\n$0: cannot write $to - $!\n"; } } sub realfilename { my $file = shift; return $file unless -e $file; if (-l $file) { my $link = readlink($file); if ($link !~ /^\// and $file =~ m:(.*/).:) { $link = $1 . $link; } return realfilename($link); } else { return $file; } } sub migrate { my $dir = shift; my $vdir = "$dir/.versions"; my $dfile; opendir $dir,$dir or die "$0: cannot read directory $dir - $!\n"; while ($file = readdir($dir)) { $dfile = "$dir/$file"; next if -l $dfile or $file eq '.' or $file eq '..'; if (-d $dfile and $opt_R and $file ne '.versions') { migrate($dfile); } elsif (-f $dfile and $file =~ /~$/) { if (-d $vdir) { for ($i = 8; $i > 0; $i--) { $n = $i+1; rename "$vdir/$file$i~","$vdir/$file$n~"; } } else { mkdir $vdir or die "$0: cannot mkdir $vdir - $!\n"; } $nfile = sprintf("%s/%s1~",$vdir,$file); rename $dfile,$nfile or die "$0: cannot move $dfile to $nfile - $!\n"; warn "$dfile --> $nfile\n" unless $opt_q; } } closedir $dir; } sub mtime { my @s = stat shift; return @s ? $s[9] : 0; } sub md5f { my $file = shift; my $md5 = 0; local $/; if (open $file,$file) { $md5 = md5_hex(<$file>); close $file; } return $md5; } # if ARGV is empty use last saved file as default file argument sub check_ARGV { local $_; local *V; if (not @ARGV) { if (-d '.versions' and open V,'ls -at .versions|') { while () { chomp; if (-f) { close V; s/~\d+~$//; @ARGV = ($_); return; } } } } } sub mv10 { my $file = shift; my $vfile = dirname($file).'/.versions/'.basename($file); die "$0: $file has no extended versions\n" unless -f "$vfile~01~"; for (my $i=1; $i<10; $i++) { my $vfile1 = "$vfile~$i~"; my $vfile2 = "$vfile~0$i~"; if (-f $vfile2) { warn "$vfile2 --> $vfile1\n" unless $opt_q; rename $vfile2,$vfile1 or die "$0: $!\n"; } } for (my $i=10; $i<100; $i++) { unlink "$vfile~$i~"; } } sub mv100 { my $file = shift; my $vfile = dirname($file).'/.versions/'.basename($file); die "$0: $file has already extended versions\n" if -f "$vfile~01~"; die "$0: $file has no versions\n" unless -f "$vfile~1~"; for (my $i=1; $i<10; $i++) { my $vfile1 = "$vfile~$i~"; my $vfile2 = "$vfile~0$i~"; if (-f $vfile1) { warn "$vfile1 --> $vfile2\n" unless $opt_q; rename $vfile1,$vfile2 or die "$0: $!\n"; } } } # rotate back sub rb10 { my $vfile = shift; for (my $i = 1; $i <= 8; $i++) { my $vfi = sprintf("%s~%d~",$vfile,$i); my $vfn = sprintf("%s~%d~",$vfile,$i+1); if (-f $vfn) { rename $vfn,$vfi; } else { unlink $vfi if $i == 1; last; } } } # rotate back sub rb100 { my $vfile = shift; for (my $i = 1; $i <= 98; $i++) { my $vfi = sprintf("%s~%02d~",$vfile,$i); my $vfn = sprintf("%s~%02d~",$vfile,$i+1); if (-f $vfn) { rename $vfn,$vfi; } else { unlink $vfi if $i == 1; last; } } } sub pathsearch { my $prg = shift; foreach my $dir (split(':',$ENV{PATH})) { return "$dir/$prg" if -x "$dir/$prg"; } } # zz is the generic clip board program # # to use zz with vim, write to your .vimrc: # # noremap zz> :w !zz # noremap zz< :r !zz -- sub zz { my $bs = 2**16; my $wm = '>'; my ($file,$tee,$x); if ("@ARGV" =~ /^(-h|--help)$/) { print <<'EOD'; zz is the generic clip board program. It can hold any data, ASCII or binary. The clip board itself is $ZZ (default: $HOME/.zz). See also the clip board editor "ezz". Limitation: zz does not work across accounts or hosts! Use xx instead. Options and modes are: "zz" show content of $ZZ "zz file(s)" copy file(s) content into $ZZ "zz -" write STDIN (keyboard, mouse buffer) to $ZZ "zz +" add STDIN (keyboard, mouse buffer) to $ZZ "... | zz" write STDIN from pipe to $ZZ "... | zz +" add STDIN from pipe to $ZZ "... | zz -" write STDIN from pipe to $ZZ and STDOUT "zz | ..." write $ZZ to pipe "... | zz | ..." save pipe data to $ZZ (like tee) "zz --" write $ZZ to STDOUT "zz -v" show clip board versions (history) "zz -1" write $ZZ version 1 to STDOUT "zz -9" write $ZZ version 9 to STDOUT Examples: zz *.txt ls -l | zz zz | wc -l (within vi) :w !zz (within vi) :r !zz (within mutt) |zz EOD exit; } if ("@ARGV" eq '-v') { exec qw'vv -+l',$ZZ; } if ("@ARGV" =~ /^-(\d)$/) { exec "vv -v $1 '$ZZ' | cat"; } # read mode if (-t STDIN and not @ARGV or "@ARGV" eq '--') { exec 'cat',$ZZ; } # write mode system "vv -s '$ZZ' >/dev/null 2>&1" if -s $ZZ; if (@ARGV and $ARGV[0] eq '+') { shift @ARGV; $wm = '>>'; } if ("@ARGV" eq '-') { @ARGV = (); $tee = 1 unless -t STDIN; } $tee = 1 unless @ARGV or -t STDIN or -t STDOUT; $bs = 2**12 if $tee; open $ZZ,$wm,$ZZ or die "$0: cannot write $ZZ - $!\n"; if (@ARGV) { while ($file = shift @ARGV) { if (-f $file) { if (open $file,$file) { while (read($file,$x,$bs)) { my $s = syswrite $ZZ,$x; defined($s) or die "$0: cannot write to $ZZ - $!\n"; } close $file; } else { warn "$0: cannot read $file - $!\n"; } } elsif (-e $file) { warn "$0: $file is not a regular file\n"; } else { warn "$0: $file does not exist\n"; } } close $ZZ; $ZZ1 = $ZZ.'~1~'; $ZZ1 =~ s:(.*)/(.*):$1/.versions/$2:; if (-e $ZZ and not -s $ZZ and -s $ZZ1 ) { system qw'rsync -aA',$ZZ1,$ZZ; } } else { while (read(STDIN,$x,$bs)) { syswrite $ZZ,$x; syswrite STDOUT,$x if $tee; } } exit; } sub ezz { my $bs = 2**16; my $wm = '>'; my $editor = $ENV{EDITOR} || 'vi'; my ($out,$file,$x); $ENV{JEDINIT} = "SAVE_STATE=0"; if ("@ARGV" =~ /^(-h|--help)$/) { print <<'EOD'; ezz is the edit helper for the zz clip board program. The clip board itself is $ZZ (default: $HOME/.zz). Options and modes are: "ezz" edit $ZZ with $EDITOR "... | ezz" write STDIN from pipe to $ZZ and call $EDITOR "... | ezz +" add STDIN from pipe to $ZZ and call $EDITOR "ezz 'perl commands'" execute perl commands on $ZZ "ezz - 'perl commands'" execute perl commands on $ZZ and show result "ezz filter [args]" run filter [with args] on $ZZ "ezz - filter [args]" run filter [with args] on $ZZ and show result Examples: ls -l | ezz ezz 's/ /_/g' ezz head -3 ezz - head -3 EOD exit; } system "vv -s '$ZZ' >/dev/null 2>&1" if -s $ZZ; unless (-t STDIN) { if ("@ARGV" eq '+') { @ARGV = (); $wm = '>>'; } open $ZZ,$wm,$ZZ or die "$0: cannot write $ZZ - $!\n"; syswrite $ZZ,$x while read(STDIN,$x,$bs); close $ZZ; } if (@ARGV) { $out = shift @ARGV if $ARGV[0] eq '-'; $cmd = shift @ARGV or exec 'cat',$ZZ; rename $ZZ,"$ZZ~" or die "$0: cannot move $ZZ to $ZZ~ - $!\n"; $cmd = quotemeta $cmd; @ARGV = map { quotemeta } @ARGV; if (pathsearch($cmd)) { system "$cmd @ARGV <'$ZZ~'>'$ZZ'"; } else { system "perl -pe $cmd @ARGV <'$ZZ~'>'$ZZ'"; } if ($? == 0) { unlink "$ZZ~" } else { rename "$ZZ~",$ZZ } exec 'cat',$ZZ if $out; } else { exec $editor,$ZZ; } exit; } sub install { my ($dir); local $| = 1; print "Installation directory: "; $dir = ||''; chomp $dir; $dir =~ s:/+$::; $dir ||= '.'; if ($dir eq '.') { unlink qw'zz ezz vv'; link $prg,'zz' or die "$0: cannot create zz - $!\n"; link $prg,'ezz' or die "$0: cannot create ezz - $!\n"; rename $prg,'vv' or die "$0: cannot create vv - $!\n"; } else { die "$0: $dir does not exist\n" unless -e $dir; die "$0: $dir is not a directory\n" unless -d $dir; die "$0: $dir is not writable\n" unless -w $dir; chdir $dir or die "$0: cannot cd $dir - $!\n"; unlink qw'zz ezz vv'; system qw'rsync -a',$prg,'vv'; exit $? if $?; link 'vv','zz' or die "$0: cannot create $dir/zz - $!\n"; link 'vv','ezz' or die "$0: cannot create $dir/ezz - $!\n"; } print "Installation completed. See:\n"; print "\t$dir/vv -h\n"; print "\t$dir/zz -h\n"; print "\t$dir/ezz -h\n"; exit; } fex-20160919/bin/fpg0000755000174700017470000002176512770010173012176 0ustar fexfex#!/usr/bin/perl -w # # Programname: fpg - Frams' Perl grep # Author: framstag@rus.uni-stuttgart.de # Licence: Perl Artistic # # History: # 2003-02-27 Framstag initial version # 2003-02-28 Framstag added exit status # 2007-03-09 Framstag added option -Q # 2007-06-01 Framstag added options -s and -c # and changed default output mode # 2007-06-03 Framstag added ReadLine-support # 2007-08-31 Framstag added option -x # 2008-02-06 Framstag added implicit gunzip # -F ==> -R, new -F option # 2008-10-07 Framstag added option -p # -n ==> -S, new -n option # 2008-10-14 Framstag added option -M # 2008-11-23 Framstag added option -~ # 2016-06-12 Framstag option -o respects (match) use Getopt::Std; use Term::ReadLine; use locale; $0 =~ s:.*/::; $| = 1; $usage = <30 and not /\\w/' script #See "perldoc perlre" for help on regular expressions. $maxlen = 0; $opt_i = $opt_r = $opt_v = $opt_l = $opt_h = $opt_e = $opt_n = $opt_o = 0; $opt_s = $opt_c = $opt_Q = $opt_F = $opt_p = $opt_M = $opt_C = $opt_S = 0; ${'opt_~'} = 0; $opt_S = 4; $opt_x = $opt_X = ''; $opt_R = "\n"; getopts('hirvlLFMopscQen~S:R:C:x:X:') or die $usage; if ($opt_h) { print $usage; exit; } unless ($opt_Q) { $exp = shift or die $usage; } if ($opt_C and ($opt_l or $opt_L or $opt_s or $opt_v or $opt_p or $opt_M)) { die "$0: cannot mix option -C with any of -l -L -s -v -p -M\n"; } if ($opt_M and ($opt_l or $opt_L or $opt_s or $opt_v or $opt_p or $opt_C)) { die "$0: cannot mix option -M with any of -l -L -s -v -p -C\n"; } if ($opt_o and ($opt_v or $opt_l or $opt_L or $opt_c or $opt_F or $opt_C)) { die "$0: cannot mix option -E with any of -l -L -v -c -C -F\n"; } $opt_XX = 0; if (not ${'opt_~'}) { @bfiles = grep(/~$|^#.*#$/,@ARGV); if (@bfiles and (grep(/[^~]$/,@ARGV) or grep(/(^|\/)#[^\/]*#$/,@ARGV))) { $opt_XX = 1; warn "$0: ignoring @bfiles\n"; # unless $opt_r; } } if (-t STDOUT) { $B = "\033[1m"; $N = "\033[m"; } else { $B = $N = ''; } if ($opt_p) { $/ = '' } else { $/ = $opt_R } #else { eval '$/ = "'.$opt_R.'"' } $opt_h = 1 if not $opt_r and @ARGV < 2; if ($opt_Q) { $q = new Term::ReadLine $0; $q->ornaments(0) unless $ENV{PERL_RL}; for (;;) { $exp = $q->readline("$B\nsearch-expression:$N "); last unless $exp; &scan; } } else { &scan; } exit ($found?0:1); sub scan { $egrep = ''; if ($opt_e) { eval "\$egrep = sub { $exp }"; } else { $exp =~ s/([\@\$\%\^\&\*\(\)\+\[\]\{\}\\\|\.\?])/\\$1/g if $opt_F; $exp = '(?i)'.$exp if $opt_i; $exp = '(?s)'.$exp if $opt_p or $opt_R ne "\n"; #? $exp =~ s/\.\*\*/[.\n]*/g; } $found = 0; if (@ARGV) { foreach $file (@ARGV) { next if $opt_X and $file =~ /$opt_X/; next if $opt_XX and ($file =~ /~$/ or $file =~ m{(^|/)#[^/]*#$}); my $error = ''; open $file,$file or $error = $!; close $file; if ($error) { warn "$0: cannot read file $file - $error\n"; next; } unless (-f $file or -d $file or -c $file or -S $file or -p $file) { warn "$0: ignoring special file $file\n"; next; } $maxlen = length $file if $maxlen < length $file; # printf "%s\r",substr("scanning $file".(" " x 255),0,$maxlen+9) if -t STDOUT; # print $B."scanning $file\n".$N if -t STDOUT and not $opt_l||$opt_L; if ($opt_r and -d $file) { $found += grepd($file); next; } # next if -z $file; # Achtung: special files unter /proc sind "empty" ! # $type = `file -L $file`; # if ($type =~ /text/i and open F,$file or open F,"strings $file|") { $fileq = quotemeta $file; if (-T $file) { open $file,$file; # warn "$file\n"; } else { if ($file =~ /\.bz2$/) { open $file,"bunzip2 <$fileq|"; # warn "gunzip <$file|\n"; } elsif ($file =~ /\.gz$/) { open $file,"gunzip <$fileq|"; # warn "gunzip <$file|\n"; } else { open $file,"strings -a -n $opt_S $fileq|"; # warn "strings -n $opt_S $file|\n"; } } if (fileno $file) { $found += grepf($file,$file); close $file; } else { warn "$0: cannot open $file - $!\n"; next; } } # print " " x ($maxlen+9),"\r" if -t STDOUT; } else { $found = grepf(STDIN); } } sub grepd { my $dir = shift; my $file; my $found = 0; opendir $dir,$dir or return; while (defined($file = readdir $dir)) { next if $file eq '.' or $file eq '..'; if (not ${'opt_~'} and $file =~ /~$|^#[^\/]*#$/) { # warn "$0: ignoring $dir/$file\n"; next; } $file = "$dir/$file"; next unless -r $file; if (-d $file and not -l $file) { $found += grepd($file); next; } next unless -f $file or -c $file or -S $file or -p $file or -z $file; $fileq = quotemeta $file; if (-T $file and open $file,$file or open $file,"strings -a -n $opt_S $fileq|") { $found += grepf($file,$file); close $file; } } closedir $dir; return $found; } sub grepf { my $F = shift; my $file = shift; my $found = 0; my ($n,$l,$c); warn $B."scanning $file".$N."\n" if -t STDOUT and $opt_s; while (<$F>) { $_ .= "\n" unless /\n$/; if ($opt_M) { if ($mail and (/^From / or eof $F)) { my $__ = $_; $_ = $mail; $mail = $__; } else { $mail .= $_; next; } } $l++; $n = 0; if ($opt_C) { for (my $i=$opt_C;$i;$i--) { $C{$i} = $C{$i-1} if defined $C{$i-1}; } $C{0} = [$l,$_]; } if ($opt_e) { if ($opt_v) { next if &$egrep; } else { unless (&$egrep) { if ($opt_C and $c) { print "$l:" if $opt_n; print; $L{$l} = $l; $c--; } next; } } $n++; } else { if ($opt_v) { # print ">>>$_" if $opt_i and /$exp/oi or /$exp/o; if ($opt_Q) { next if /$exp/m; } else { next if /$exp/om; } $n++; } else { if ($opt_c) { if ($opt_Q) { $n++ while /$exp/mg } else { $n++ while /$exp/omg } } else { if ($opt_o) { if ($exp =~ /\([^?]+\)/) { if (/$exp/) { $n++; $_ = "$1\n"; } } else { my $m = ''; while (s/($exp)//) { $n++; $m .= "$1\n"; } $_ = $m; } } elsif ($opt_Q) { $n += s/($exp)/$B$1$N/mg; } else { $n += s/($exp)/$B$1$N/omg; } } } } unless ($n) { if ($opt_C and $c) { print "$l:" if $opt_n; print; $L{$l} = $l; $c--; } next; } $found += $n; # print " " x ($maxlen+9),"\r" if -t STDOUT and $found==1; next if $opt_c; last if $opt_l or $opt_L; if ($file and not $opt_s) { print "\n$B$file$N:\n"; $file = ''; } if ($opt_x and $n) { if ($opt_i) { s/($opt_x)/$B$1$N/ogi } else { s/($opt_x)/$B$1$N/og } } for (my $i=$opt_C;$i;$i--) { if (defined $C{$i}) { my ($ln,$ls) = @{$C{$i}}; unless (defined $L{$ln}) { $L{$ln} = $ln; print "$ln:" if $opt_n; print $ls; } } } print "$l:" if $opt_n; print; $L{$l} = $l; $c = $opt_C; } if ($opt_c) { print "$file:" if @ARGV>1; print "$found\n"; } else { print "$file\n" if $opt_l and $found or $opt_L and not $found; } return $found; } fex-20160919/bin/l0000755000174700017470000004160212770010174011646 0ustar fexfex#!/usr/bin/perl -w # # l / ll / lf / llf - better replacement of the classic ls command # # Author: Ulli Horlacher # # Perl Artistic License use Cwd qw'abs_path'; use File::Basename; use Getopt::Std; # the name of the game $0 =~ s:.*/::; $ENV{LC_ALL} = 'C'; # unshift @ARGV,split /\s+/,$ENV{'l_opt'} if $ENV{'l_opt'}; @ARGV = grep { chomp } if "@ARGV" eq '-'; # parse CLI arguments $opt_l = $opt_i = $opt_t = $opt_s = $opt_a = $opt_r = $opt_d = $opt_n = 0; $opt_L = $opt_N = $opt_c = $opt_u = $opt_S = $opt_R = $opt_z = $opt_h = 0; $opt_U = $opt_x = $opt_E = 0; ${'opt_*'} = 0; $opt_m = $opt_f = $opt_F = $opt_D = ''; getopts('hdnlLNitcuarsxUSREz*m:f:D:F:') or usage(1); usage(0) if $opt_h; $opt_z = 1 unless $opt_R; $opt_l = 1 if $0 eq 'll'; $opt_l = $opt_i = $opt_a = $opt_S = 1 if $0 eq 'lll'; &examples if $opt_E; if ($0 eq 'lf' or $0 eq 'llf') { $opt_l = $0 eq 'llf'; if (scalar(@ARGV) == 0) { die usage(1); } elsif (scalar(@ARGV) == 1) { $opt_F = shift; $opt_R = $opt_F if $opt_F eq '.'; } elsif (-d $ARGV[-1]) { $opt_R = pop(@ARGV); $opt_F = join('|',@ARGV); } else { $opt_F = join('|',@ARGV); } @ARGV = (); @ARGV = ($opt_R) if -d $opt_R; } $postsort = $opt_t||$opt_s; $postproc = $postsort||$opt_z; # mark for squeeze operation $z = $opt_z ? "\0" : ''; # default sorting methode if ($opt_U) { $lcsort = sub { return @_ } } elsif ($opt_r) { $lcsort = sub { sort { lc $b cmp lc $a } @_ } } else { $lcsort = sub { sort { lc $a cmp lc $b } @_ } } # default: list only files not beginning with a dot unless ($opt_m) { if ($opt_a) { $opt_m = '.' } else { $opt_m = '^[^\.]' } } $older = $newer = 0; if ($opt_D) { if ($opt_D =~ /:(\d+)([mhd])/) { $older = $1; my $z = $2 || 's'; if ($z =~ /m/) { $older *= 60 } elsif ($z =~ /h/) { $older *= 60*60 } elsif ($z =~ /d/) { $older *= 60*60*24 } } elsif ($opt_D =~ /:(\d\d\d\d-\d\d-\d\d)$/) { $older = $1; } if ($opt_D =~ /(\d+)([mhd]):/) { $newer = $1; my $z = $2 || 's'; if ($z =~ /m/) { $newer *= 60 } elsif ($z =~ /h/) { $newer *= 60*60 } elsif ($z =~ /d/) { $newer *= 60*60*24 } } elsif ($opt_D =~ /^(\d\d\d\d-\d\d-\d\d):/) { $newer = $1; } } # preselect date field number if ($opt_c) { $sdf = 'c' } elsif ($opt_u) { $sdf = 'a' } else { $sdf = 'm' } # any arguments? if (@ARGV) { @ARGV = &$lcsort(@ARGV) } else { @ARGV = &getfiles('.') } # build files list &collect(@ARGV); # post process files list? # remark: if no postprocessing, files list has been already printed in list() if (@LIST && $postproc) { # on -t or -s option sort list on date or size # and then strip of leading sorting pre-string @LIST = grep { s/.{21}// } reverse sort @LIST if $postsort; # squeeze size field (= remove unnecessary spaces) if ($opt_z and not $opt_f) { $opt_z = '%'.$opt_z.'s '; @LIST = grep { s/\0 *([,\d\.\-]+) /sprintf($opt_z,$1)/e } @LIST; } @LIST = reverse @LIST if $opt_r; if (not ($opt_t or $opt_U) and grep /^d[rR-][wW-][xX-]/,@LIST) { foreach (@LIST) { print if /^d/ } foreach (@LIST) { print unless /^d/ } } else { print @LIST; } } # print statistics summary? if ($opt_S && $SS) { print "$SS file(s):"; printf " r=%d (%s Bytes)",$SS{'-'},&d3($Ss) if $SS{'-'}; delete $SS{'-'}; foreach my $type (qw(l d c b p s ?)) { printf " %s=%d",$type,$SS{$type} if $SS{$type}; delete $SS{$type}; } foreach my $type (keys %SS) { printf " %s=%d",$type,$SS{$type} } print "\n"; } exit ($found ? 0 : 1); # collect files and build file lists # # INPUT: filenames # # GLOBAL: @LIST sub collect { my @files = @_; my $f; getacl(@files) if $opt_l and not $opt_n; # loop over all argument files/directories foreach $f (@files) { # skip jed and emacs backup files # next if $f =~ /~$/ and not $opt_a and not $opt_l; # recursive? if ($opt_R) { # list single file if ($opt_L) { unless (-e $f) { warn "$0: dangling symlink $f\n"; next; } $f = abs_path($f); } list($f); # traverse real subdirs if (-d $f and not -l $f) { $f =~ s:/*$:/:; # skip other file systems on -x if ($opt_x) { my @pd = stat(dirname($f)); my @sd = stat($f); next if $pd[0] ne $sd[0]; } collect(getfiles($f)); } } else { # suppress trailing / on -d option $f =~ s:/$:: if $opt_d; # on trailing / list subdirs, too if ($f =~ m:/$:) { list(getfiles($f)) } elsif ($f eq '') { list('/') } else { if ($opt_L) { unless (-e $f) { warn "$0: dangling symlink $f\n"; next; } $f = abs_path($f); } list($f); } } } } # list file(s) # # INPUT: filenames # # GLOBAL: @LIST (filenames-list) sub list { my @files = @_; my ($file,$line,$linkname,$inode,$links,$size,$mode,$uid,$gid,$date,%dates); my ($day); foreach $file (@files) { next if $opt_F and not fmatch($file); next if $opt_N and (not -f $file or -l $file); # get file information # if ($opt_L and stat $file or not $opt_L and lstat $file) { if (lstat $file) { ($linkname,$inode,$links,$size,$mode,$uid,$gid,$date,%dates) = &info($file); } elsif ($! eq "Permission denied") { $linkname = $file; $inode = $links = $size = $uid = $gid = '?'; $mode = $opt_l ? '?---------' : '?---'; $date = '????-??-?? ??:??:??'; %dates = ('m' => 0, 'a' => 0, 'c' => 0); } else { warn "$0: ".quote($file)." - $!\n"; next; } $day = $date; $day =~ s/\s.*//; if ($older) { next if $older =~ /-/ and $day gt $older; next if $older !~ /-/ and $dates{m} > time-$older; } if ($newer) { next if $newer =~ /-/ and $day lt $newer; next if $newer !~ /-/ and $dates{m} < time-$newer; } if (defined $linkname) { # prepend sorting string $line = ''; $line = sprintf '%21s',$date if $opt_t; $line = sprintf '%21s',$size if $opt_s; unless ($opt_n) { $uid = substr($uid,0,8); $gid = substr($gid,0,8); } # user defined format? if ($opt_f) { foreach my $i (split '',$opt_f) { if ($opt_n) { $i =~ tr/AD/ad/; if ($i eq 'm') { $line .= sprintf '%06o ', $mode } elsif ($i eq 'u') { $line .= sprintf '%6d ', $uid } elsif ($i eq 'g') { $line .= sprintf '%6d ', $gid } elsif ($i eq 's') { $line .= sprintf "$z%16s ",$size } elsif ($i eq 'l') { $line .= sprintf '%3s ', $links } elsif ($i eq 'i') { $line .= sprintf '%14s ', $inode } elsif ($i eq 'd') { $line .= sprintf '%10s ', $date } elsif ($i eq 'a') { $line .= sprintf '%10s %10s %10s ', $dates{'a'},$dates{'m'},$dates{'c'} } } else { # $mode =~ s/(....)(...)/sprintf($1.uc($2))/e if $ACL{$file}; substr($mode,4,3) = uc(substr($mode,4,3)) if $ACL{$file}; if ($i eq 'm') { $line .= $mode.' ' } elsif ($i eq 'u') { $line .= sprintf '%-8s ', $uid } elsif ($i eq 'g') { $line .= sprintf '%-8s ', $gid } elsif ($i eq 's') { $line .= sprintf "$z%19s ",$size } elsif ($i eq 'l') { $line .= sprintf '%3s ', $links } elsif ($i eq 'i') { $line .= sprintf '%14s ', $inode } elsif ($i eq 'd') { $line .= $date.' ' } elsif ($i eq 'D') { $line .= $date.' ' } elsif ($i eq 'a') { $line .= &isodate($dates{'a'}).' '. &isodate($dates{'m'}).' '. &isodate($dates{'c'}).' ' } elsif ($i eq 'A') { $line .= &isodate($dates{'a'}).' '. &isodate($dates{'m'}).' '. &isodate($dates{'c'}).' ' } } } # predefined formats } else { if ($opt_n) { if ($opt_l) { $line .= sprintf "%06o %6d %6d $z%15s %10d ", $mode,$uid,$gid,$size,$date; } else { $line .= sprintf "%06o $z%15s %10d ",$mode,$size,$date; } } else { if ($opt_l) { # $mode .= $ACL{$file} ? '+' : ' '; # $mode =~ s/(....)(...)/sprintf($1.uc($2))/e if $ACL{$file}; substr($mode,4,3) = uc(substr($mode,4,3)) if $ACL{$file}; $line .= sprintf "%s %-8s %-8s $z%19s %s ", $mode,$uid,$gid,$size,$date; } else { $line .= sprintf "%s $z%19s %s ",$mode,$size,substr($date,0,-3); } } if ($opt_i) { $line .= sprintf '%3s %10s ',$links,$inode } } $line .= $linkname."\n"; if ($postproc) { push @LIST,$line; } else { $line =~ s/\0//; print $line; } $found++; } else { lstat $file; warn "$0: cannot get dir-info for ".quote($file)." - $!\n"; } } } # get file information # # INPUT: file name # # OUTPUT: filename with linkname, inode, hard link count, size, mode string, # UID, GID, isodate sub info { my $file = shift; my ($linkname,$links,$mode,$bmode,$uid,$gid,$date,%dates,@stat); my $size = '-'; my $inode = '?'; my @rwx = qw/--- --x -w- -wx r-- r-x rw- rwx/; my $type; if ($opt_L) { @stat = stat $file } else { @stat = lstat $file } if (@stat) { $inode = $stat[1]; $bmode = $stat[2]; $links = $stat[3]; %dates = ('m' => $stat[9], 'a' => $stat[8], 'c' => $stat[10]); if ($opt_n) { $uid = $stat[4]; $gid = $stat[5]; $date = $dates{$sdf}; } else { $uid = getpwuid($stat[4]) || $stat[4]; $gid = getgrgid($stat[5]) || $stat[5]; $date = &isodate($dates{$sdf}); } if (-f _) { $type = '-'; $size = $stat[7]; } elsif (!$opt_L && -l _) { $type = 'l'; } elsif (-d _) { $type = 'd'; } elsif (-c _) { $type = 'c'; $size = &nodes($stat[6]); } elsif (-b _) { $type = 'b'; $size = &nodes($stat[6]); } elsif (-p _) { $type = 'p'; } elsif (-S _) { $type = 's'; } else { $type = '?'; } if ($opt_n) { $mode = $stat[2]; $size = $stat[7] if $size eq '-'; } else { if ($opt_l) { $mode = $rwx[$bmode & 7]; $bmode >>= 3; $mode = $rwx[$bmode & 7] . $mode; $bmode >>= 3; $mode = $rwx[$bmode & 7] . $mode; substr($mode,2,1) =~ tr/-x/Ss/ if -u _; substr($mode,5,1) =~ tr/-x/Ss/ if -g _; substr($mode,8,1) =~ tr/-x/Tt/ if -k _; $mode = $type.$mode; } else { # with short list display only effective file access modes use filetest 'access'; # respect ACLs ==> cannot use pseudofile _ $mode = $type . (-r $file ? 'R' : '-') . (-w $file ? 'W' : '-') . (-x $file ? 'X' : '-'); substr($mode,2,1) =~ tr/-x/Ss/ if -u $file or -g $file; substr($mode,3,1) =~ tr/-x/Tt/ if -k $file; } } # fall back to ls command if perl lstat failed } else { if ($opt_L) { return; } else { ($mode,$links,$uid,$gid,$size) = split /\s+/,`ls -ld $file 2>/dev/null`; return undef unless defined $mode; $type = substr($mode,0,1); # for (my $i=0;$i<3;$i++) { push @dates,'????-??-?? ??:??:??' } # $date = `gfind $dir -maxdepth 1 -name $file -printf '%Ty-%Tm-%Td %TT\n'`; } } # summarize statistics if ($opt_S) { $SS++; $SS{$type}++; $Ss += $size if $type eq '-'; } $size = &d3($size); # determine longest size field if ($opt_z) { my $x = length $size; $opt_z = $x if $x>$opt_z; } $linkname = ${'opt_*'} ? $file : quote($file) ; if ($type eq 'l' and $opt_f !~ /n/) { my $link = readlink($file); if (defined $link) { $linkname .= ' -> ' . (${'opt_*'} ? $link : quote($link)); } } $mode =~ s/\+$//; #$mode .= ' ' unless $mode =~ /\+$/; return ($linkname,$inode,$links,$size,$mode,$uid,$gid,$date,%dates); } # get ACLs # # INPUT: filenames # # GLOBAL: @ACL sub getacl { my @files; $getfacl ||= pathsearch('getfacl') or return; # warn "### @_\n"; foreach my $file (@_) { push @files,$file if -e $file } if (@files and open my $acl,'-|',$getfacl,'-ps',@files) { while (<$acl>) { $ACL{$1} = $1 if /^# file: (.+)/; } close $acl; } } # reformat integer into 3-digit doted format # (when non-numerical mode is set) # # INPUT: integer or '-' # # OUTPUT: d3-string sub d3 { local $_ = shift; if ($opt_n) { s/-/0/ } else { while (s/(\d)(\d\d\d\b)/$1,$2/) {} } return $_; } # get all files matching pattern $opt_m # # INPUT: directory to scan # # OUTPUT: files which match (sorted, directories first) sub getfiles { my $dir = shift; my @files = (); my @dirs = (); my $f; if (opendir D,$dir) { $dir = '' if $dir eq '.'; while (defined($f = readdir D)) { # skip . and .. pseudo-subdirs next if $f =~ m:(^|/)\.\.?/*$:; # skip ONTAP snapshot dir next if $f =~ m:(^|/)\.snapshot/*$:; # skip jed and emacs backup files # next if $f =~ /~$/ and not $opt_a and not $opt_l; if ($f =~ /$opt_m/) { my $x = $dir.$f; if (not -l $x and -d $x and not ($opt_R or $postsort or $opt_U)) { push @dirs,$x; } else { push @files,$x; } } } closedir D; unless ($postsort) { @files = &$lcsort(@files); @dirs = &$lcsort(@dirs); } } else { warn "$0: cannot read $dir : $!\n"; } getacl(@dirs,@files) if $opt_l and not $opt_n; return (@dirs,@files); } # reformat integer to string node # # INPUT: integer node # # OUTPUT: string node sub nodes { my $rdev = shift; return sprintf("%03d,%03d", ($rdev >> 8) & 255, $rdev & 255); } sub pathsearch { my $prg = shift; foreach my $dir (split(':',$ENV{PATH})) { return "$dir/$prg" if -x "$dir/$prg"; } } # reformat timetick to ISO date string # # INPUT: timetick # # OUTPUT: ISO date string sub isodate { my @d = localtime shift; return sprintf('%d-%02d-%02d %02d:%02d:%02d', $d[5]+1900,$d[4]+1,$d[3],$d[2],$d[1],$d[0]); } # quote file name to printable name and escape shell meta chars # # INPUT: original file name # # OUTPUT: printable file name sub quote { local $_ = shift; my $mc = '\'\[\]\\\\ `"$?&<>$*()|{};'; unless (defined $_) { die "@_"; @x = caller; die "@x"; } if (s/[\000-\037\200-\237\241-\250]/?/g or /\'/) { s/([$mc])/\\$1/g; s/^~/\\~/; # } elsif (/[$mc]/ or -d and /:/) { } elsif (/[$mc]/) { $_ = "'$_'"; } return $_; } sub fmatch { my $file = shift; my $link = readlink($file)||''; return $file if basename($file) =~ /$opt_F/i; return $link if basename($link) =~ /$opt_F/i; } sub usage { my $status = shift; my $opts = '[-lastcuidnrzLRxNS*] [-f format] [-D X:Y]'; local *OUT = $status ? *STDERR : *STDOUT; if ($0 ne 'lf') { print OUT "usage: $0 $opts [-F regexp] [file...]\n"; } $opts =~ s/R//; print OUT "usage: lf $opts regexp [regexp...] [directory]\n"; print OUT < # use 5.008; use Socket; use IO::Handle; use Fcntl qw':flock :seek'; use warnings; BEGIN { # stunnel workaround $SIG{CHLD} = "DEFAULT"; $ENV{PERLINIT} = q{ $ENV{LC_ALL} = 'en_US.UTF-8'; unshift @INC,(getpwuid($<))[7].'/perl'; # web error handler $SIG{__DIE__} = $SIG{__WARN__} = sub { my $info = ''; my $url = $ENV{REQUEST_URL}||''; my @d = localtime time; my $time = sprintf('%d-%02d-%02d %02d:%02d:%02d', $d[5]+1900,$d[4]+1,$d[3],$d[2],$d[1],$d[0]); if ($admin) { my $mailto = "mailto:$admin?subject=fex%20bug"; $info = "

send this error to $admin

"; } $_ = join("\n",@_); chomp; s/&/&/g; s/", "

INTERNAL ERROR in $0

", "
\n$_\n
\n

", "$url\n

", "$time\n

", "$info\n

", "" ); $length = length; unless ($HTTP_HEADER) { print "HTTP/1.0 200 ERROR\r\n"; print "Content-Type: text/html\r\n"; print "Content-Length: $length\r\n"; print "\r\n"; } print; exit 99; } }; eval $ENV{PERLINIT}; } # use BSD::Resource; # setrlimit(RLIMIT_CPU,999,999) or die "$0: $!\n"; # SSL remote address provided by stunnel if (@ARGV and $ARGV[0] eq 'stunnel' and $ENV{REMOTE_HOST} =~ /(.+)/) { $ssl_ra = $1; } # KEEP_ALIVE <== callback from CGI if ($ENV{KEEP_ALIVE}) { $keep_alive = $ENV{KEEP_ALIVE}; } else { %ENV = ( PERLINIT => $ENV{PERLINIT} ); # clean environment } $ENV{HOME} = (getpwuid($<))[7] or die "no HOME"; # fexsrv MUST be run with full path! if ($0 =~ m:^(/.+)/bin/fexsrv:) { $FEXHOME = $1; $FEXHOME =~ s:/+:/:g; $FEXHOME =~ s:/$::; $ENV{FEXHOME} = $FEXHOME; } foreach my $lib ( $FEXHOME, '/usr/local/fex', '/usr/local/share/fex', '/usr/share/fex', ) { $ENV{FEXLIB} = $FEXLIB = $lib and last if -f "$lib/fex.pp"; $ENV{FEXLIB} = $FEXLIB = "$lib/lib" and last if -f "$lib/lib/fex.pp"; } # import from fex.pp our ($hostname,$debug,$timeout,$max_error,$max_error_handler); our ($spooldir,@logdir,$docdir,$xkeydir,$akeydir,$lockdir); our ($force_https,$default_locale,$bs,$MB,$adlm,@forbidden_user_agents); our (@locales); # load common code (local config: $FEXHOME/lib/fex.ph) require "$FEXLIB/fex.pp" or die "cannot load $FEXLIB/fex.pp - $!\n"; chdir $spooldir or http_die("$0: $spooldir - $!\n"); our $log = 'fexsrv.log'; our $error = 'F*EX ERROR'; our $htmlsource; our $hid = ''; # header ID our @log; $0 = untaint($0); $ENV{GATEWAY_INTERFACE} = 'CGI/1.1f'; $ENV{SERVER_NAME} = $hostname; $ENV{REQUEST_METHOD} = ''; $ENV{QUERY_STRING} = ''; $ENV{HTTP_COOKIE} = ''; $ENV{PATH_INFO} = ''; $ENV{RANDOM} = randstring(8); $ENV{FEATURES} = join(',',qw( SID CHECKRECIPIENT GROUPS QUOTA FILEID MULTIPOST XKEY FILEQUERY FILESTREAM JUP NOSTORE AXEL FEXMAIL FILELINK )); $port = 0; # continue session? if ($keep_alive) { if ($ENV{HTTP_HOST} =~ /(.+):(.+)/) { $hostname = $1; $port = $2; } else { $hostname = $ENV{HTTP_HOST}; if ($ENV{PROTO} eq 'https') { $port = 443 } else { $port = 80 } } $ra = $ENV{REMOTE_ADDR}; $rh = $ENV{REMOTE_HOST}; } # new session else { my $iaddr; # HTTPS connect if ($ssl_ra) { $ENV{PROTO} = 'https'; $ENV{REMOTE_ADDR} = $ra = $ssl_ra; if ($ssl_ra =~ /[\w:]:\w/) { # ($rh) = `host $ssl_ra 2>/dev/null` =~ /name pointer (.+)\.$/; $^W = 0; eval 'use Socket6'; $^W = 1; http_error(503) if $@; $iaddr = inet_pton(AF_INET6,$ssl_ra) and $rh = gethostbyaddr($iaddr,AF_INET6); } else { $rh = gethostbyaddr(inet_aton($ra),AF_INET); } $rh ||= '-'; $port = 443; # print {$log} "X-SSL-Remote-Host: $ssl_ra\n"; } # HTTP connect else { $ENV{PROTO} = 'http'; my $sa = getpeername(STDIN) or die "no network stream on STDIN\n"; if (sockaddr_family($sa) == AF_INET) { ($ENV{REMOTE_PORT},$iaddr) = sockaddr_in($sa); $ENV{REMOTE_ADDR} = $ra = inet_ntoa($iaddr); $rh = gethostbyaddr($iaddr,AF_INET); ($port) = sockaddr_in(getsockname(STDIN)); } elsif (sockaddr_family($sa) == AF_INET6) { $^W = 0; eval 'use Socket6'; $^W = 1; http_error(503) if $@; ($ENV{REMOTE_PORT},$iaddr) = unpack_sockaddr_in6($sa); $ENV{REMOTE_ADDR} = $ra = inet_ntop(AF_INET6,$iaddr); $rh = gethostbyaddr($iaddr,AF_INET6); ($port) = unpack_sockaddr_in6(getsockname(STDIN)); } else { die "unknown IP version\n"; } $port = 80 unless $port; } $ENV{REMOTE_HOST} = $rh || ''; $ENV{HTTP_HOST} = ($port == 80 or $port == 443) ? $hostname : "$hostname:$port"; $ENV{PORT} = $port; } if ($reverse_proxy_ip and $reverse_proxy_ip eq $ra) { $ENV{FEATURES} =~ s/SID,//; } if (@anonymous_upload and ipin($ra,@anonymous_upload)) { $ENV{FEATURES} .= ',ANONYMOUS'; } $| = 1; $SIG{CHLD} = "DEFAULT"; # stunnel workaround $SIG{ALRM} = sub { # printf {$log} "\nTIMEOUT %s %s\n",isodate(time),$connect; if (@log) { debuglog('TIMEOUT',isodate(time)); fexlog($connect,@log,"TIMEOUT"); } exit; }; REQUEST: while (*STDIN) { if (defined $ENV{REQUESTCOUNT}) { $ENV{REQUESTCOUNT}++ } else { $ENV{REQUESTCOUNT} = 0 } $connect = sprintf "%s:%s %s %s %s [%s_%s]", $keep_alive ? 'CONTINUE' : 'CONNECT', $port, isodate(time), $rh||'-', $ra, $$,$ENV{REQUESTCOUNT}; $hid = sprintf("%s %s\n",$rh||'-',$ra); @header = @log = (); $header = ''; # read complete HTTP header while (defined ($_ = &getaline)) { last if /^\s*$/; $hl += length; $header .= $_; s/[\r\n]+$//; # URL-encode non-printable chars s/([\x00-\x08\x0E-\x1F\x7F-\x9F])/sprintf "%%%02X",ord($1)/ge; s/%21/!/g; if (@header and s/^\s+/ /) { $header[-1] .= $_; } else { push @header,$_; $header{$1} = $2 if /(.+)\s*:\s*(.+)/; push @log,$_; } if ($hl > $MB) { fexlog($connect,@log,"OVERRUN"); http_error(413); } if (/^(GET \/|\S*Forwarded|\S*Client-IP|\S*Coming-From|User-Agent)/i) { $hid .= $_."\n"; } # reverse-proxy? # (only IPv4 support!) if ($reverse_proxy_ip and $reverse_proxy_ip eq $ra and /^\S*(Forwarded|Client-IP|Coming-From)\S*: ([\da-f:.]+)/i ) { $ENV{REMOTE_ADDR} = $ra = $2; $ENV{REMOTE_HOST} = $rh = gethostbyaddr(inet_aton($ra),AF_INET) || ''; $ENV{HTTP_HOST} = $hostname; if ($ENV{PROTO} eq 'https') { $port = 443 } else { $port = 80 } } } exit unless @header; exit if $header =~ /^\s*$/; $ENV{HTTP_HEADER} = $header; debuglog($header); # http_die("

$header
"); $ENV{'HTTP_HEADER_LENGTH'} = $hl; $ENV{REQUEST_URI} = $uri = ''; $cgi = ''; # is it a HTTP-request at all? $request = shift @header; if ($request !~ /^(GET|HEAD|POST|OPTIONS).*HTTP\/\d\.\d$/i) { fexlog($connect,$request,"DISCONNECT: no HTTP request"); badlog("no HTTP request: $request"); exit; } if ($force_https and $port != 443 and $request =~ /^(GET|HEAD|POST)\s+(.+)\s+(HTTP\/[\d\.]+$)/i) { $request = $2; nvt_print( "HTTP/1.1 301 Moved Permanently", "Location: https://$hostname$request", "Content-Length: 0", "" ); fexlog($connect,@log); exit; } $request =~ s{^(GET|HEAD|POST) https?://$hostname(:\d+)?}{$1 }i; if ($request =~ m"^(GET|HEAD) /fop/\w+/") { # no header inquisition on regular fop request $header_hook = ''; } else { &$header_hook($connect,$request,$ra) if $header_hook; } unless ($keep_alive) { if ($request =~ m:(HTTP/1.(\d)): and $2) { $ENV{KEEP_ALIVE} = $keep_alive = $ra } else { $ENV{KEEP_ALIVE} = $keep_alive = ''; } } if ($request =~ /^OPTIONS \/?FEX HTTP\/[\d\.]+$/i) { fexlog($connect,@log); nvt_print( "HTTP/1.1 201 OK", "X-Features: $ENV{FEATURES}", "X-Timeout: $timeout", '' ); next REQUEST if $keep_alive; exit; } if ($request =~ m:^GET /?SID HTTP/[\d\.]+$:i) { if ($ENV{FEATURES} !~ /\bSID\b/) { fexlog($connect,@log); nvt_print( "HTTP/1.1 501 Not Available", "Server: fexsrv", "X-Features: ".$ENV{FEATURES}, "X-Timeout: ".$timeout, 'Content-Length: 0', '' ); } else { $ENV{SID} = randstring(8); fexlog($connect,@log); nvt_print( "HTTP/1.1 201 ".$ENV{SID}, "Server: fexsrv", "X-Features: ".$ENV{FEATURES}, "X-SID: ".$ENV{SID}, "X-Timeout: ".$timeout, 'Content-Length: 0', '' ); } next REQUEST if $keep_alive; exit; } if ($request =~ /^(GET|HEAD|POST)\s+(.+)\s+(HTTP\/[\d\.]+$)/i) { $ENV{REQUEST} = $_; $ENV{REQUEST_METHOD} = uc($1); $ENV{REQUEST_URI} = $uri = $cgi = $2; $ENV{HTTP_VERSION} = $protocol = $3; $ENV{QUERY_STRING} = $1 if $cgi =~ s/\?(.*)//; $ENV{PATH_INFO} = $1 if $cgi =~ m:/.+?(/.+?)(\?|$):; $ENV{KEEP_ALIVE} = $keep_alive = '' if $protocol =~ /1\.0/; $ENV{REQUEST_URL} = "$ENV{PROTO}://$ENV{HTTP_HOST}$ENV{REQUEST_URI}"; if ($uri =~ /<|%3c/i) { badchar("<") } if ($uri =~ />|%3e/i) { badchar(">") } if ($uri =~ /\||%7c/i) { badchar("|") } if ($uri =~ /\\|%5c/i) { badchar("\\") } } my $fua = join('|',@forbidden_user_agents); while ($_ = shift @header) { # header inquisition! &$header_hook($connect,$_,$ra) if $header_hook; # mega stupid "Download Manager" FlashGet if ($uri =~ m{^/fop/} and m{^Referer: https?://.*\Q$uri$}) { fexlog($connect,@log,"NULL: FlashGet"); debuglog("NULL: FlashGet"); exec qw'cat /dev/zero' or sleep 30; exit; } if ($fua and /^User-Agent: ($fua)/) { disconnect($1,"499 User Agent $1 Not Supported",30); } if (/^Range:.*,/) { disconnect("Range a,b","416 Requested Range Not Satisfiable",30); } if (/^Range:.*(\d+)-(\d+)/) { if ($1 > $2) { disconnect("Range a>b","416 Requested Range Not Satisfiable",0); } if (($header{'User-Agent'}||'') !~ /$adlm/ ) { disconnect("Range a-b","416 Requested Range Not Satisfiable",30); } } if (/^Range:.*\d+-$/ and $hid) { my $lock = untaint($lockdir.'/'.md5_hex($hid)); if (open $lock,'+>>',$lock) { if (flock($lock,LOCK_EX|LOCK_NB)) { seek $lock,0,0; truncate $lock,0; print {$lock} $hid; } else { disconnect( "multiple Range request", "400 Multiple Requests Not Allowed", 10, ); } } } # client signed int bug if (/^Range:.*-\d+-/) { disconnect("Range -a-","416 Requested Range Not Satisfiable",0); } # if (/^Range:/ and $protocol =~ /1\.0/) { # &$header_hook($connect,$_,$ra) while ($header_hook and $_ = shift @header); # fexlog($connect,@log,"DISCONNECT: Range + HTTP/1.0"); # debuglog("DISCONNECT: Range + HTTP/1.0"); # http_error(416); # exit; # } if (/^Connection:\s*close/i) { $ENV{KEEP_ALIVE} = $keep_alive = ''; } # HTTP header ==> environment variables if (/^([\w\-_]+):\s*(.+)/s) { $http_var = $1; $http_val = $2; $http_var =~ s/-/_/g; $http_var = uc($http_var); $http_val =~ s/^\s+//; $http_val =~ s/\s+$//; if ($http_var =~ /^X_(FEX_\w+|CONTENT_LENGTH)$/) { $http_var = $1; } else { $http_val =~ s/\s+/ /g; if ($http_var =~ /^HTTP_(HOST|VERSION)$/) { $http_var = 'HTTP_X_'.$1; } elsif ($http_var =~ /^PROXY/) { # http://cert.at/warnings/all/20160718.html $http_var = 'HTTP_X_'.$http_var; } elsif ($http_var !~ /^CONTENT_/) { $http_var = 'HTTP_'.$http_var; } } $ENV{$http_var} = $http_val; } } # multiline header inquisition &$header_hook($connect,$header,$ra) if $header_hook; exit unless $cgi; # extra download request? (request http://fexserver//xkey) if ($cgi =~ m{^//([^/]+)$}) { my $xkey = $1; my $dkey; if ($xkey =~ /^afex_\d/) { $dkey = readlink "$xkeydir/$xkey" and $dkey =~ s/^\.\.\///; } else { $dkey = readlink "$xkeydir/$xkey/dkey" and $dkey .= "/$xkey"; } if ($dkey) { # xkey downloads are only one time possible - besides afex if ($xkey !~ /^afex_\d/) { unlink "$xkeydir/$xkey/xkey"; unlink "$xkeydir/$xkey"; } nvt_print( "HTTP/1.1 301 Moved Permanently", "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/fop/$dkey", "Content-Length: 0", "" ); fexlog($connect,@log); exit; } fexlog($connect,@log); http_error(404); exit; } # get locale if (($ENV{QUERY_STRING} =~ /.*locale=([\w-]+)/ or $ENV{HTTP_COOKIE} =~ /.*locale=([\w-]+)/) and -d "$FEXHOME/locale/$1") { $ENV{LOCALE} = $locale = $1; } else { $ENV{LOCALE} = $locale = $default_locale; } # for dynamic HTML documents if ($ENV{HTTP_COOKIE} =~ /akey=(\w+)/) { my $akey = $1; my ($user,$id); if ($user = readlink "$akeydir/$akey") { $user =~ s:.*/::; $user = untaint($user); if ($id = slurp("$spooldir/$user/@")) { chomp $id; $ENV{AKEY} = $akey; $ENV{USER} = $user; $ENV{ID} = $id; } } } # check for name based virtual host $vhost = vhost($ENV{'HTTP_HOST'}); if ($debug) { debuglog("ENV:\n"); foreach $var (sort keys %ENV) { if (defined($ENV{$var})) { debuglog(sprintf " %s = >%s<\n",$var,$ENV{$var}); } } debuglog("\n"); } # locale definitions in fex.ph? if (@locales) { if (@locales == 1) { $locale = $locales[0]; } elsif (not grep /^$locale$/,@locales) { $locale = $default_locale; } } # prepare document file name if ($ENV{REQUEST_METHOD} =~ /^GET|HEAD$/) { if (%redirect) { foreach my $r (keys %redirect) { if ($uri =~ /^\Q$r/) { redirect($uri,$r); exit; } } } $doc = untaint($uri); $doc =~ s/%([\dA-F]{2})/unpack("a",pack("H2",$1))/ge; $doc =~ m:/\.\./: and http_error(403); $doc =~ s:^/+::; $doc =~ s/\?.*//; if ($locale and $locale ne 'english' and -e "$docdir/locale/$locale/$doc") { $doc = "$docdir/locale/$locale/$doc"; } else { $doc = "$docdir/$doc"; } } # CGI or document request? if ($cgi =~ s:^/+::) { $cgi =~ s:/.*::; unless ($cgi) { my $login = "$FEXHOME/cgi-bin/login"; if (-x $login) { $cgi = untaint(readlink($login) || $login); $cgi =~ s:.*/::; } } $ENV{SCRIPT_NAME} = $cgi; # locale CGIs? (vhost comes already with own FEXLIB) if ($locale and $locale ne 'english' and -f "$FEXHOME/locale/$locale/cgi-bin/$cgi") { $ENV{SCRIPT_FILENAME} = $cgi = "$FEXHOME/locale/$locale/cgi-bin/$cgi"; $ENV{FEXLIB} = $FEXLIB = "$FEXHOME/locale/$locale/lib" unless $vhost; } else { $ENV{SCRIPT_FILENAME} = $cgi = "$FEXHOME/cgi-bin/$cgi"; $ENV{FEXLIB} = $FEXLIB = "$FEXHOME/lib" unless $vhost; } $status = ''; if (-x $cgi and -f $cgi) { if (@forbidden_hosts and ipin($ra,@forbidden_hosts)) { fexlog($connect,@log,"FORBIDDEN"); http_error(403); } unlink "$spooldir/.error/$ra"; # push @log,"DEBUG: locale=$locale locales=(@locales)"; fexlog($connect,@log,"EXEC $cgi"); eval { local $^W = 0; exec $cgi }; $status = "$! or bad interpreter"; fexlog($connect,@log,"FAILED to exec $cgi : $status"); http_error(555); } else { if (-f "$doc/.htindex") { require "$FEXLIB/dop"; fexlog($connect,@log); showindex($doc); STDOUT->flush; next REQUEST if $keep_alive; exit; } if (-f "$doc/index.html") { # force redirect if trailing / is missing # this is mandatory for processing further HTTP request! if ($doc !~ m{/$}) { nvt_print( "HTTP/1.1 301 Moved Permanently", "Location: $ENV{REQUEST_URL}/", "Content-Length: 0", "" ); fexlog($connect,@log); next REQUEST if $keep_alive; exit; } $doc .= '/index.html'; $doc =~ s:/+:/:g; } $doc =~ s/#.*//; # ignore HTML anchors (stupid msnbot) # special request for F*EX UNIX clients if ($ENV{SCRIPT_NAME} eq 'xx.tar') { bintar(qw'fexget fexsend xx zz ezz'); } if ($ENV{SCRIPT_NAME} eq 'sex.tar') { bintar(qw'sexsend sexget sexxx'); } if ($ENV{SCRIPT_NAME} eq 'afex.tar') { bintar(qw'afex asex fexget fexsend sexsend sexget'); } if ($ENV{SCRIPT_NAME} eq 'afs.tar') { bintar(qw'afex asex fexget fexsend xx sexsend sexget sexxx zz ezz'); } # URL ends with ".html!" or ".html?!" if ($doc =~ s/(\.html)!$/$1/ or $doc =~ /\.html$/ and $ENV{'QUERY_STRING'} eq '!') { $htmlsource = $doc } else { $htmlsource = '' } if (-f $doc or $doc =~ /(.+)\.(tar|tgz|zip)$/ and lstat("$1.stream") or $doc =~ /(.+)\.tgz$/ and -f "$1.tar" or $doc =~ /(.+)\.gz$/ and -f $1) { unlink "$spooldir/.error/$ra"; delete $ENV{SCRIPT_FILENAME}; $ENV{DOCUMENT_FILENAME} = $doc; require "$FEXLIB/dop"; fexlog($connect,@log); dop($doc); STDOUT->flush; next REQUEST if $keep_alive; exit; } elsif ($uri eq '/bunny') { fexlog($connect,@log); nvt_print( 'HTTP/1.1 200 OK', 'Server: fexsrv', "Content-Type: text/plain", '', '=:3', ); exit; } elsif ($uri eq '/camel') { fexlog($connect,@log); nvt_print( 'HTTP/1.1 200 OK', 'Server: fexsrv', "Content-Type: text/plain", '', ); local $/; print unpack('u',); exit; } elsif (-e $cgi) { $status = 'not executable'; } } } # neither document nor CGI ==> error if ($status) { fexlog($connect,@log,"FAILED to exec $cgi : $status"); http_error(666); } else { fexlog($connect,@log,"UNKNOWN URL"); badlog($request); http_error(404); } exit; } # read one text line unbuffered from STDIN sub getaline { my $line = ''; my $n = 0; my $c; alarm($timeout); # must use sysread to avoid perl line buffering # (later exec would destroy line buffer) while (sysread STDIN,$c,1) { $line .= $c; $n++; last if $c eq "\n"; if ($n > $bs) { fexlog($connect,@log,$line,"OVERRUN"); http_error(413); } } alarm(0); return $line; } sub fexlog { my @log = @_; foreach my $logdir (@logdir) { if (open $log,'>>',"$logdir/$log") { flock $log,LOCK_EX; seek $log,0,SEEK_END; print {$log} "\n",join("\n",@log),"\n"; close $log; } else { http_die("$0: cannot write to $logdir/$log - $!\n"); } } } sub badchar { my $bc = shift; fexlog($connect,@log,"DISCONNECT: bad characters in URL"); debuglog("DISCONNECT: bad characters in URL $uri"); badlog($request); http_die("\"$bc\" is not allowed in URL"); } sub bintar { my $tmpdir = "$FEXHOME/tmp"; my $fs = "$ENV{PROTO}://$ENV{HTTP_HOST}"; if (chdir "$FEXHOME/bin") { fexlog($connect,@log); chdir $fstb if $fstb; mkdir $tmpdir; foreach my $f (@_) { copy($f,"$tmpdir/$f","s#fexserver = ''#fexserver = '$fs'#"); chmod 0755,"$tmpdir/$f"; } chdir $tmpdir or http_die("internal error: $tmpdir - $!"); my $tar = `tar cf - @_ 2>/dev/null`; unlink @_; nvt_print( 'HTTP/1.1 200 OK', 'Server: fexsrv', "Content-Length: ".length($tar), "Content-Type: application/x-tar", '', ); print $tar; exit; } } sub http_error { my $error = shift; my $URL = $ENV{REQUEST_URL}||''; my $URI = $ENV{REQUEST_URI}||''; if ($error eq 400) { http_error_header("400 Bad Request"); nvt_print("Your request $URL is not acceptable."); } elsif ($error eq 403) { http_error_header("403 Forbidden"); nvt_print("You have no permission to request $URL"); } elsif ($error eq 404) { http_error_header("404 Not Found"); nvt_print("The requested URI $URI was not found on this server."); } elsif ($error eq 413) { http_error_header("413 Payload Too Large"); nvt_print("Your HTTP header is too large."); } elsif ($error eq 416) { http_error_header("416 Requested Range Not Satisfiable"); } elsif ($error eq 503) { http_error_header("503 Service Unavailable"); # nvt_print("No Perl ipv6 support on this server."); } else { http_error_header("555 Unknown Error"); nvt_print("The requested URL $URL produced an internal error."); } nvt_print( "
", "
fexsrv at $hostname:$port
", "", ); exit; } sub disconnect { my $info = shift; my $error = shift; my $wait = shift||0; # &$header_hook($connect,$_,$ra) while ($header_hook and $_ = shift @header); fexlog($connect,@log,"DISCONNECT: $info"); debuglog("DISCONNECT: $info"); errorlog("$ENV{REQUEST_URI} ==> $error"); badlog("$ENV{REQUEST_URI} ==> $error ($info)"); sleep $wait; nvt_print("HTTP/1.0 $error"); exit; } sub http_error_header { my $error = shift; my $uri = $ENV{REQUEST_URI}; errorlog("$uri ==> $error") if $uri; nvt_print( "HTTP/1.1 $error", "Connection: close", "Content-Type: text/html; charset=iso-8859-1", "", '', "", "$error", "", "

$error

", ); } sub redirect { my $uri = shift; my $r = shift; my $rr = $redirect{$r}; my $newurl; $uri =~ s/\Q$r//; if ($rr =~ s/^!//) { $newurl = $rr.$uri; nvt_print( "HTTP/1.1 301 Moved Permanently", "Location: $newurl", "Content-Length: 0", "" ); } else { if ($rr =~ /^http/) { $newurl = $rr.$uri; } else { $newurl = "$ENV{PROTO}://$ENV{HTTP_HOST}$rr$uri"; } http_header("200 OK"); print html_header("$hostname page has moved"); pq(qq( '

Please use new URL: $newurl

' '' )); } fexlog($connect,@log,"REDIRECT $newurl"); if ($rr =~ /^http/) { exit; } else { &reexec; } } sub badlog { my $request = shift; my @n; my $ed = "$spooldir/.error"; local $_; if (@ignore_error) { foreach (@ignore_error) { return if $request =~ /$_/; } } if ($ra and $max_error and $max_error_handler) { mkdir($ed) unless -d $ed; if (open $ra,"+>>$ed/$ra") { flock($ra,LOCK_EX); seek $ra,0,SEEK_SET; @n = <$ra>; printf {$ra} "%s %s\n",isodate(time),$request; close $ra; &$max_error_handler($ra,@n) if scalar(@n) > $max_error; } } } __END__ M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("PM)R(G+5P*("`@ M("`@("`@("`@("`@("`@("`@("`@("]@8&`M+B`@(&!<("`@("Q=+B`@("`@ M("`@("`@("`@("`@("`@("`L+BY?"B`@("`@("`@("`@("`@("`@("`@("`@ M+&`@("`@(&`B+B`@72X@("`@(&`N("`@("`@("`@("`@("`@7U]?+BY>(&!? M)V`B(B(*("`@("`@("`@("`@("`@("`@("`@("`I("`@("`@("`G+"TG+2T@ M+B`@("!@+B`@("`@(%]?7RPN+2<@("XN("T@("`G("TP("Y?"B`@("`@("`@ M("`@+"X@("`@("`@("`@?%]?+"Y?("!?("`N+5\@("!<("`\("Y@(B # use Getopt::Std; use File::Basename; use IO::Socket::INET; use Cwd 'abs_path'; use Digest::MD5 'md5_hex'; use constant DS => 60*60*24; # do not run as CGI! exit if $ENV{SCRIPT_NAME}; unless ($FEXLIB = $ENV{FEXLIB}) { if ($ENV{FEXHOME}) { $FEXLIB = $ENV{FEXHOME}.'/lib'; } elsif (-f '/usr/share/fex/lib/fex.ph') { $FEXLIB = '/usr/share/fex/lib'; } else { $FEXLIB = dirname(dirname(abs_path($0))).'/lib'; } $ENV{FEXLIB} = $FEXLIB; } die "$0: no FEXLIB\n" unless -r "$FEXLIB/fex.pp"; # program name $_0 = $0; $0 =~ s:.*/::; $| = 1; # use fex.ph for site configuration! our ($FEXHOME); our ($spooldir,@logdir,$docdir); our ($akeydir,$ukeydir,$dkeydir,$skeydir,$gkeydir,$xkeydir,$lockdir); our ($durl,$debug,$autodelete,$hostname,$admin,$admin_pw,$bcc); our $keep_default = 5; our $purge = $keep_default*3; # load common code, local config : $HOME/lib/fex.ph require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n"; my $logdir = $logdir[0]; # localized functions # (needed for reminder and account reactivation e-mails) foreach my $lf (glob "$FEXHOME/locale/*/lib/lf.pl") { require $lf } # default locale functions (from fex.pp) $notify{english} = \¬ify; $reactivation{english} = \&reactivation; @_ARGV = @ARGV; $opt_v = $opt_V = $opt_d = 0; getopts('vVd'); $opt_v = $opt_d if $opt_d; # debug mode, no real action $today = time; $isodate = isodate($today); chdir $spooldir or die "$0: $spooldir - $!\n"; # open L,">>$logdir/cleanup.log"; # clean up regular spool opendir $spooldir,'.' or die "$0: $spooldir - $!\n"; while ($to = readdir $spooldir) { next if $to =~ /^\./; next if $to !~ /@/ or $_ = readlink($to) and not /\//; next unless -d $to; if (@demo and -f "$to/.demo" and time > lmtime("$to/.demo")+$demo[1]*DS) { logdel($to,"demo user $to deleted"); next; } unless (opendir TO,$to) { warn "$0: $spooldir/$to - $!\n"; next; } while ($from = readdir TO) { next if $from !~ /@/; if ($from eq '@GROUP') { foreach $group (glob "$to/$from/*") { if (readlink $group and not -f $group) { logdel($group,"$group deleted (master has gone)"); } } } else { if (-d "$to/$from" and $from !~ /^\./) { unless (opendir FROM,"$to/$from") { warn "$0: $spooldir/$to/$from - $!\n"; next; } while ($file = readdir FROM) { next if $file eq '.' or $file eq '..'; if (-d "$to/$from/$file" and $file !~ /^\./) { cleanup($to,$from,$file); rmdir "$to/$from/$file" unless $opt_d; } } closedir FROM; rmdir "$to/$from" unless $opt_d; } } } closedir TO; unless (-f "$to/\@PERSISTENT" or $to eq $admin) { @glob = glob "$to/*/* $to/\@MAINUSER/* $to/\@GROUP/*"; unless (@glob or -f "$to/\@") { logdel($to,"$to deleted"); } $user = $to; if ($login_check and -l "$user/.login") { my $lc = &$login_check(readlink("$user/.login")); if ($lc) { if (-f "$user/\@~" and not "$user/@") { rename "$user/\@~","$user/@" unless $opt_d; logv("$user reanimated (login_check)"); } } else { rename "$user/@","$user/\@~" unless $opt_d; logv("$user deactivated (login_check)"); } } } } closedir $spooldir; # clean up download key lookup directory if (chdir $dkeydir and opendir D,'.') { while ($file = readdir D) { if ($link = readlink $file and (not -l "$link/dkey" or readlink "$link/dkey" ne $file)) { logdel($file,".dkeys/$file deleted"); } } closedir D; } # clean up upload key lookup directory if (chdir $ukeydir and opendir D,'.') { while ($file = readdir D) { next if $file eq '.' or $file eq '..'; if (($link = readlink $file and not -e "$link/upload" or -f $file and time > lmtime($file)+DS)) { logdel($file,".ukeys/$file deleted"); } } closedir D; } # clean up authorization key lookup directory if (chdir $akeydir and opendir D,'.') { while ($file = readdir D) { if (-l $file and time > (lmtime($file)||0)+DS) { logdel($file,".akeys/$file deleted"); } } closedir D; } # clean up extra download key lookup directory if (chdir $xkeydir and opendir D,'.') { while ($file = readdir D) { next if $file eq '.' or $file eq '..'; if (-l $file and not (-f "$file/upload" or -f "$file/data")) { logdel($file,".xkeys/$file deleted"); } } closedir D; } # clean up lock directory if (chdir $lockdir and opendir D,'.') { while ($file = readdir D) { if (-f $file and time > lmtime($file)+DS) { logdel($file,".locks/$file deleted"); } } closedir D; } # clean up error directory if (chdir "$spooldir/.error" and opendir D,'.') { while ($file = readdir D) { if (-f $file) { $mtime = lmtime($file); if ($mtime and $today > 10*$keep_default*DS+$mtime) { if ($opt_d) { print "unlink .error/$file\n" } else { logdel($file,".error/$file deleted") } } } } closedir D; } # clean up debug directory if (chdir "$spooldir/.debug" and opendir D,'.') { while ($file = readdir D) { if (-f $file) { $mtime = lmtime($file); if ($mtime and $today > $keep_default*DS+$mtime) { # logdel($file,".debug/$file deleted"); if ($opt_d) { print "unlink .debug/$file\n" } else { unlink $file } } } } closedir D; } # clean up subuser keys directory if (chdir $skeydir and opendir D,'.') { while ($file = readdir D) { if (-f $file and open F,$file) { $delete = 1; $from = $to = $id = ''; while () { if (/^(\w+)=(.+)/) { $from = $2 if $1 eq 'from'; $to = $2 if $1 eq 'to'; $id = $2 if $1 eq 'id'; } } close F; if ($from and $to and $id and open F,"$spooldir/$to/\@SUBUSER") { while () { if (/^\Q$from:$id\E$/) { $delete = 0; last; } } close F; } if ($delete) { logdel($file,".skeys/$file deleted"); } } } closedir D; } # clean up orphan subuser links chdir $spooldir; foreach $subuser (glob '*/@MAINUSER/*') { if ($skey = readlink $subuser and not -f "$skeydir/$skey") { logdel($subuser,"$subuser deleted"); } } foreach $subuser (glob '*/@MAINUSER') { unlink $subuser unless $opt_d; } # clean up old OKEYs chdir $spooldir; foreach my $okey (glob '*/@OKEY/*') { if (time > lmtime($okey)+30*DS) { logdel($okey,"$okey deleted"); } } # clean up group keys directory if (chdir $gkeydir and opendir D,'.') { while ($gkey = readdir D) { if (-f $gkey and open F,$gkey) { $delete = 1; $from = $group = $id = ''; while () { if (/^(\w+)=(.+)/) { $from = $2 if $1 eq 'from'; $group = $2 if $1 eq 'to'; $id = $2 if $1 eq 'id'; } } close F; $group =~ s/^@//; $gf = "$spooldir/$from/\@GROUP/$group"; if ($from and $group and $id and open F,$gf) { while () { if (/^\Q$from:$id\E$/) { $delete = 0; last; } } close F; } if ($delete) { logdel($gkey,".gkeys/$gkey deleted"); logdel($gf,"$gf deleted") if -l $gf; } } } closedir D; } # clean up self registration directory if (chdir "$spooldir/.reg" and opendir D,'.') { while ($file = readdir D) { if (-f $file) { $mtime = lmtime($file); if ($mtime and $today > $mtime+DS) { logdel($file,".reg/$file deleted"); } } } closedir D; } # send account expiration warning if ($account_expire and $account_expire =~ /^(\d+)/) { my $expire = $1; if (chdir $spooldir) { chomp($admin_pw = slurp("$admin/\@")||''); unless ($admin_pw) { warn "create new fex account for $admin\n"; $admin_pw = randstring(8); system("$FEXHOME/bin/fac -u $admin $admin_pw"); } my $fid = "$FEXHOME/.fex/id"; unless (-f $fid) { mkdir "$FEXHOME/.fex",0700; if (open $fid,'>',$fid) { if ($durl =~ m{(https?://.+?)/}) { print {$fid} "$1\n"; } else { print {$fid} "$hostname\n"; } print {$fid} "$admin\n"; print {$fid} "$admin_pw\n"; close $fid; } else { warn"$0: cannot create $fid - $!"; } } chmod 0600,$fid; opendir $spooldir,'.'; while ($user = readdir $spooldir) { next unless -f "$user/\@"; next if -e "$user/$admin/reactivation.txt"; next if -e "$user/\@PERSISTENT"; next if $user !~ /@/ or -l $user; next if $user =~ /^(fexmaster|fexmail)/ or $user eq $admin; next if -l "$user/.login"; if (time > lmtime($user)+$expire*DS) { # print "$spooldir/$user\n"; local $locale = readlink "$user/\@LOCALE"; $locale = 'english' unless $locale and $reactivation{$locale}; &{$reactivation{$locale}}($expire,$user); sleep 1; } } closedir $spooldir; } } # vhosts exit if $opt_V; if (%vhost) { foreach $vhost (keys %vhost) { my $fexlib = $vhost{$vhost}.'/lib'; if (-f "$fexlib/fex.ph") { warn "run $0 for $vhost :\n" if -t or $opt_v; my $cmd = "HTTP_HOST=$vhost FEXLIB=$fexlib $_0 -V @_ARGV"; if ($opt_d) { print "$cmd\n" } else { system $cmd } } } } if ($notify_newrelease and $notify_newrelease !~ /^no$/i or not defined $notify_newrelease) { $notify_newrelease ||= $admin; $newnew = $new = ''; $snew = $FEXHOME.'/doc/new'; $new = slurp($snew)||''; $_ = slurp("$FEXHOME/doc/version")||''; if (/(\d+)/) { $qn = "new?$hostname:$1" } else { $qn = "new?$hostname:0" } print "checking for new F*EX release\n" if $opt_v; for (1..3) { sleep rand(10); $newnew = `wget -qO- http://fex.belwue.de/$qn 2>/dev/null`; last if $newnew =~ /release/; # $newnew = `wget -qO- http://fex.rus.uni-stuttgart.de/$qn 2>/dev/null`; # last if $newnew =~ /release/; }; if ($newnew =~ /release/) { if ($newnew ne $new) { if (open $sendmail,"|$sendmail $notify_newrelease $bcc") { pq($sendmail,qq( 'From: fex\@$hostname' 'To: $notify_newrelease' 'Subject: new F*EX release' '' '$newnew' )); close $sendmail; if (open $snew,'>',$snew) { print {$snew} $newnew; close $snew; } } } } } exit; # file clean up sub cleanup { my ($to,$from,$file) = @_; my ($data,$download,$notify,$mtime,$warn,$dir,$filename,$dkey,$delay); my $keep = $keep_default; my $purge = $::purge || 3*$keep; my $comment = ''; my $kf = "$to/$from/$file/keep"; my $ef = "$to/$from/$file/error"; local $_; $keep = readlink $kf || readlink "$to/\@KEEP" || $keep_default; $file = "$to/$from/$file"; $data = "$file/data"; $download = "$file/download"; $notify = "$file/notify"; if ($file =~ /\/ADDRESS_BOOK/) { logdel($file,"$file deleted"); } elsif (-d $file and not -f $data) { if ($mtime = lmtime("$file/upload")) { if ($today > $mtime+DS) { verbose("rmrf $file (today=$today mtime_upload=$mtime)"); logdel($file,"$file deleted"); } } elsif ($mtime = lmtime("$file/error")) { $purge = $1*$keep if $purge =~ /(\d+).*keep/; if ($today > $purge*DS+$mtime) { verbose("rmrf $file (today=$today mtime_error=$mtime keep=$keep purge=$purge)"); logdel($file,"$file deleted"); } } else { logdel($file,"$file deleted"); } } elsif (-s $download and -s $data and autodelete($file) !~ /NO/i) { $delay = autodelete($file); $delay = 1 if $delay !~ /^\d+$/; $delay--; $mtime = lmtime($download); if ($mtime and $today > $delay*DS+$mtime and logdel($data,"$data deleted")) { if (open $ef,'>',$ef) { printf {$ef} "%s has been autodeleted after download at %s\n", filename($file),isodate(lmtime($download)); close $ef; } } } elsif (-f $data) { my $reactivation = $file =~ m{/\Q$admin/reactivation.txt\E$}; $warn = $reactivation ? $keep-5 : $keep-2; $mtime = lmtime("$file/filename") || lmtime($data) || 0; if ($today > $mtime+$keep*DS) { if ($account_expire and $reactivation) { if ($account_expire =~ /delete/) { logdel($to,"$to removed - expired"); } else { if (open $sendmail,"|$sendmail $admin $bcc") { $account_expire =~ /(\d+)/; my $expire = $1 || 0; pq($sendmail,qq( 'From: fex\@$hostname' 'To: $admin' 'Subject: user $to expired' '' 'F*EX user $to has been inactive for $expire days' 'and has ignored the account reactivation mail.' 'You may want to delete this account.' )); close $sendmail; unlink $data; } else { warn "$0: cannot send mail - $!\n"; } } } else { if ($file =~ /^anonymous.*\/afex_\d/ or $to =~ /^_.+_/) { # also _fexmail_* logdel($file,"$file deleted") and verbose("rmrf $file (today=$today mtime_upload=$mtime)"); } elsif (logdel($data,"$data deleted")) { verbose("unlink $data (today=$today mtime=$mtime keep=$keep)"); if (open $ef,'>',$ef) { $filename = $file; $filename =~ s:.*/::; print $ef "$filename is expired"; close $ef; } } } } elsif ($file !~ /STDFEX$/ and $mtime+$warn*DS < $today and $dkey = readlink("$file/dkey") and not -s $download and not -f $notify and (readlink("$to/\@REMINDER")||'yes') ne 'no') { my $locale = readlink "$to/\@LOCALE" || readlink "$file/\@LOCALE"; $locale = 'english' unless $locale and $notify{$locale}; if (open my $c,"$file/comment") { chomp ($comment = <$c>||''); close $c; } if (&{$notify{$locale}}( status => 'remind', dkey => $dkey, filename => filename($file), keep => $keep, comment => $comment, warn => int(($mtime-$today)/DS)+$keep, autodelete => autodelete($file), )) { open $notify,'>',$notify; close $notify; print "sent reminder for $file\n" if -t or $opt_v; } else { warn "$0: reminder notification for $file failed\n"; } } } } sub autodelete { my $file = shift; my $adf = "$file/autodelete"; my $autodelete; if (-l $adf) { $autodelete = readlink $adf || ''; } elsif (open $adf,$adf) { chomp($autodelete = <$adf>||''); close $adf; } return $autodelete||$::autodelete; } sub logdel { my ($file,$msg) = @_; my $status = 0; if ($opt_d) { print "$msg\n"; } else { if ($status = rmrf($file)) { logv($msg); } else { logv("$file DEL FAILED : $!"); warn "$file DEL FAILED : $!\n" if -t or $opt_v; } } return $status; } sub logv { my $msg = shift; print "$msg\n" if -t or $opt_v; unless ($opt_d) { foreach my $ld (@logdir) { if (open my $log,">>$ld/cleanup.log") { print {$log} "$isodate $msg\n"; close $log; } } } } sub verbose { local $_; if ($opt_v) { while ($_ = shift @_) { s/\n*$/\n/; print; } } } sub lmtime { my @s = lstat(shift); return @s?$s[9]:0; } fex-20160919/bin/fexwall0000755000174700017470000000456612644735371013102 0ustar fexfex#!/usr/bin/perl -w # send e-mail to all registered F*EX users # # Author: Ulli Horlacher # use Getopt::Std; use File::Basename; use Cwd 'abs_path'; # do not run as CGI! exit if $ENV{SCRIPT_NAME}; unless ($ENV{FEXLIB}) { if ($ENV{FEXHOME}) { $ENV{FEXLIB} = $ENV{FEXHOME}.'/lib'; } else { $ENV{FEXLIB} = dirname(dirname(abs_path($0))).'/lib'; } } $FEXLIB = $ENV{FEXLIB}; die "$0: no FEXLIB\n" unless -f "$FEXLIB/fex.pp"; # program name $0 =~ s:.*/::; # become effective user fex unless ($<) { if (my @pw = getpwnam('fex')) { $) = $pw[3]; $> = $pw[2]; $ENV{HOME} = $pw[7]; } else { die "$0: no such user 'fex'\n"; } } # import from fex.pp our ($FEXHOME,$hostname,$sendmail,$spooldir,$admin,$bcc); # load common code, local config : $HOME/lib/fex.ph require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n"; die "$0: \$admin not configured in $FEXLIB/fex.ph\n" if not $admin or $admin =~ /example.org/; $opt_h = 0; getopts('h') or usage(2); usage(0) if $opt_h; $subject = "@ARGV"; die usage(1) unless $subject; local $/; $text = ; die usage(1) unless $text; if (open my $sig,$ENV{HOME}.'/.signature') { $text .= "\n-- \n" . <$sig>; close $sig; } local $/ = "\n"; chdir $spooldir or die "$0: $spooldir - $!\n"; # @users = grep { chomp;s:/@:: } glob("*/@"); foreach $user (glob("*@*")) { if (-f "$user/@" and (readlink "$user/\@NOTIFICATION"||'') !~ /no/i) { push @users,$user; } } foreach $group (glob "*/\@GROUP/*") { if (open $group,$group) { while (<$group>) { s/#.*//; s/:.*\n//; push @users,$_ if /@/; } close $group; } } foreach $subuser (glob "*/\@SUBUSER") { if (open $subuser,$subuser) { while (<$subuser>) { s/#.*//; s/:.*\n//; push @users,$_ if /@/; } close $subuser; } } # @users = qw'framstag@fex'; die "$0: no users found\n" unless @users or grep /@/,@users; push @users,$bcc; @users = uniq(@users); open $sendmail,'|-',$sendmail,@users or die "$0: $sendmail - $!\n"; print {$sendmail} "From: $admin\n", "To: fexusers\@$hostname\n", "Subject: $subject\n", "\n", $text; close $sendmail or die "$0: $sendmail - $!\n"; print "mail sent to:\n",map { "$_\n" } @users; exit; sub uniq { my %x; grep !$x{$_}++,@_; } sub usage { print "usage: $0 \"SUBJECT\" < mail.text\n"; exit shift||0; } fex-20160919/bin/fac0000755000174700017470000006364112571314241012154 0ustar fexfex#!/usr/bin/perl -w # CLI admin client for the FEX service # # Author: Ulli Horlacher # use 5.006; use Getopt::Std; use File::Basename; use Cwd 'abs_path'; use Digest::MD5 'md5_hex'; use constant M => 1024*1024; use constant DS => 60*60*24; # do not run as CGI! exit if $ENV{SCRIPT_NAME}; unless ($FEXLIB = $ENV{FEXLIB}) { if ($ENV{FEXHOME}) { $FEXLIB = $ENV{FEXHOME}.'/lib'; } elsif (-f '/usr/share/fex/lib/fex.ph') { $FEXLIB = '/usr/share/fex/lib'; } else { $FEXLIB = dirname(dirname(abs_path($0))).'/lib'; } $ENV{FEXLIB} = $FEXLIB; } die "$0: no FEXLIB\n" unless -f "$FEXLIB/fex.pp"; # become effective user fex unless ($<) { if (my @pw = getpwnam('fex')) { $) = $pw[3]; $> = $pw[2]; $ENV{HOME} = $pw[7]; } else { die "$0: no such user 'fex'\n"; } } umask 077; # import from fex.pp our ($FEXHOME,$FHS,$hostname,$spooldir,@logdir,$logdir,$akeydir,$docdir); our ($durl,@durl,$mdomain,$admin,$mailmode); our ($autodelete,$keep_default,$keep_max,$recipient_quota,$sender_quota); our (@local_rdomains); local $notification = 'full'; # load common code, local config : $HOME/lib/fex.ph require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n"; die "$0: \$admin not configured in $FEXLIB/fex.ph\n" unless $admin; $EDITOR = $ENV{EDITOR} || $ENV{VISUAL} || (-x '/usr/bin/editor' ? '/usr/bin/editor' : 'vi'); $opt_c = $opt_v = $opt_l = $opt_L = $opt_h = $opt_w = $opt_u = 0; $opt_M = $opt_E = 0; $opt_r = $opt_d = $opt_q = $opt_a = $opt_n = $opt_k = $opt_m = ''; $opt_y = $opt_S = $opt_C = $opt_D = $opt_A = $opt_V = $opt_P = $opt_R = ''; ${'opt_/'} = ''; @__ = @ARGV; while (my $a = shift @__) { if ($a eq '-V') { shift @__; } else { push @_ARGV,$a; } } chdir $spooldir or die "$0: no $spooldir\n"; @stat = stat $spooldir or die "$0: cannot access $spooldir - $!\n"; warn "WARNING: $spooldir with owner=root !?\n" unless $stat[4]; if (abs_path($spooldir) ne abs_path("$FEXHOME/spool")) { warn "WARNING: \$spooldir differs from $FEXHOME/spool !\n"; } getopts('hcvlLwuME/q:r:d:a:n:k:m:y:S:C:A:V:D:P:R:') or usage(2); usage(0) if $opt_h; examples() if $opt_E; if (${'opt_/'}) { my $admin = shift; my $id = shift or die "usage: $0 -/ admin-email-address auth-ID\n"; if ($admin !~ /.\@[\w.-]+\.[a-z]+$/) { die "$0: $admin is not an email address\n"; } mkdir $admin; my $aa = "$spooldir/$admin/@"; open $aa,'>',$aa or die "$0: cannot write $aa - $!\n"; print {$aa} $id,"\n"; close $aa or die "$0: cannot write $aa - $!\n"; my $fph = "$FEXLIB/fex.ph"; $_ = slurp($fph) or die "$0: cannot read $fph\n"; s/^\s*\$admin\s*=.*/\$admin = '$admin';/m or $_ = "\$admin = '$admin';\n".$_; open $fph,">$fph.new" or die "$0: cannot write $fph.new\n"; print {$fph} $_; close $fph; rename "$fph.new",$fph or die "$0: cannot rename $fph.new to $fph\n"; my $fid = "$ENV{HOME}/.fex/id"; mkdir dirname($fid); rename $fid,$fid.'_save'; open $fid,'>',$fid or die "$0: cannot create $fid - $!\n"; if ($durl =~ m{(https?://.+?)/}) { print {$fid} "$1\n"; } else { print {$fid} "$hostname\n"; } print {$fid} "$admin\n"; print {$fid} "$id\n"; close $fid; print "new admin account: $admin\n"; exit; } &check_admin; if ($opt_V) { while (my ($hh,$vh) = each (%vhost)) { if ($opt_V eq basename($vh) or $opt_V eq $hh) { $ENV{HTTP_HOST} = $hh; $ENV{VHOST} = "$hh:$vh"; $ENV{FEXLIB} = "$vh/lib"; die "$0: no $ENV{FEXLIB}/fex.ph\n" unless -f "$ENV{FEXLIB}/fex.ph"; exec $0,@_ARGV; die "$0: cannot re-exec\n"; } } die "$0: no virtual host $opt_V defined\n"; } $fup = $durl; $fup =~ s:/[^/]+$:/fup:; # maintenance mode if ($opt_m) { if ($opt_m eq 'exit') { if (unlink '@MAINTENANCE') { warn "$0: leaving maintenance mode\n"; } else { warn "$0: no maintenance mode\n"; } } else { unlink '@MAINTENANCE'; symlink $opt_m,'@MAINTENANCE' or die "$0: cannot write $spooldir/\@MAINTENANCE - $!"; warn "$0: entering maintenance mode\n"; } exit; } # list files or resend notification e-mails if ($opt_M) { my ($mtime,$comment,$file,$keep); local $_; if (@ARGV) { foreach $file (glob("@ARGV")) { $mtime = mtime("$file/data") or next; $comment = slurp("$file/comment")||''; next if $comment =~ /NOMAIL/; $keep = readlink "$file/keep" || readlink "$file/../../\@KEEP" || $keep_default; $keep = $keep - int((time-mtime("$file/data"))/60/60/24); notify( status => 'new', dkey => readlink "$file/dkey", filename => filename($file), keep => $keep, comment => $comment, warn => int(($mtime-time)/DS)+$keep, autodelete => readlink "$file/autodelete" || $autodelete, ); print "send notification e-mail for $file\n"; } } else { # just list files foreach $file (glob "*/*/*/data") { next if $file =~ /^_?(anonymous|fexmail)/; $file =~ s:/data$::; $comment = "$file/comment"; if (open $comment,$comment and <$comment> =~ /NOMAIL/) { next; } print "$file\n"; } } exit; } # show logfile if ($opt_w) { $log = "$logdir/fexsrv.log"; warn "$0: polling $log\n\n"; exec "$FEXHOME/bin/logwatch",$log; die "$0: logwatch not found\n"; } # list files and download URLs if ($opt_l) { my ($file,$dkey,@L); chdir $spooldir or die "$0: $spooldir - $!\n"; foreach $file (glob "*/*/*") { if (-s "$file/data" and $dkey = readlink("$file/dkey") and -l ".dkeys/$dkey" ) { push @L,sprintf "%2\$s --> %1\$s : $durl/$dkey/%3\$s\n",split "/",$file; } } print sort @L if @L; exit; } # list files detailed if ($opt_L) { my $filter = shift; my ($comment,$file,$keep,$old,$size,$download); local $_; foreach $file (glob "*/*/*/data") { next if $file =~ m:(.+?)/: and -l $1; $size = -s $file or next; $file =~ s:/data$::; next if $filter and $file !~ /$filter/; $comment = slurp("$file/comment")||''; $dkey = readlink("$file/dkey")||''; $keep = readlink("$file/keep")||$keep_default; $old = int((time-mtime("$file/data"))/60/60/24); $download = join(' & ',split("\n",(slurp("$file/download")||''))); print "\n$file\n"; printf " comment: %s\n",decode_utf8($comment); printf " size: %s\n",d3($size); printf " sender ip: %s\n",readlink("$file/ip")||''; printf " expire in: %s days\n",$keep-$old; printf " upload speed: %s kB/s\n",readlink("$file/speed")||0; printf " URL: $durl/$dkey/%3\$s\n",split "/",$file; printf " download: %s\n",$download; } exit; } # delete user if ($opt_d) { $idf = "$spooldir/$opt_d/\@"; die "$0: no such user $opt_d\n" unless -f $idf; unlink $idf or die "$0: cannot remove $idf - $!\n"; foreach $rf (glob "$spooldir/$opt_d/\@*") { unlink $rf } print "$opt_d deleted\n"; exit; } # set user restriction file if ($opt_R) { if ($opt_R eq 'i') { $user = shift or die "usage: $0 -Ri user\n"; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; die "$0: no user $user\n" unless -d "$spooldir/$user"; unless (@local_rdomains) { die "$0: no \@local_rdomains in server config\n"; } my $rf = "$spooldir/$user/\@ALLOWED_RECIPIENTS"; open $rf,'>',$rf or die "$0: cannot open $rf - $!"; print {$rf} "\@LOCAL_RDOMAINS\n"; close $rf; print "$user restricted to internal recipients\n"; exit; } elsif ($opt_R eq 'l') { $user = shift or die "usage: $0 -Rl user\n"; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; die "$0: no user $user\n" unless -d "$spooldir/$user"; my $rf = "$spooldir/$user/\@ALLOWED_RECIPIENTS"; open $rf,'>',$rf or die "$0: cannot open $rf - $!"; print {$rf} "\@LOCAL_USERS\n"; close $rf; print "$user restricted to local recipients\n"; exit; } else { usage(2); } exit; } # edit user restriction file if ($opt_r) { if ($opt_r =~ /^r/i) { $opt_r = 'ALLOWED_RECIPIENTS' } elsif ($opt_r =~ /^u/i) { $opt_r = 'UPLOAD_HOSTS' } elsif ($opt_r =~ /^d/i) { $opt_r = 'DOWNLOAD_HOSTS' } else { usage(2) } $user = shift or usage(2); $user .= '@'.$mdomain if $mdomain and $user !~ /@/; die "$0: no user $user\n" unless -d "$spooldir/$user"; my $rf = "$spooldir/$user/\@$opt_r"; unless (-s $rf) { open $rf,'>',$rf or die "$0: cannot open $rf - $!"; if ($opt_r eq 'ALLOWED_RECIPIENTS') { print {$rf}<$fph" or die "$0: cannot write to $fph - $!\n"; print {$fph} $_; close $fph; cpa("$FEXLIB/fup.pl","$vhd/lib"); foreach $i (qw'dop fex.pp fup.pl lf.pl reactivation.txt') { # symlink "$FEXLIB/$i","$vhd/lib/$i"; symlink "../../lib/$i","$vhd/lib/$i"; } foreach $i (qw( index.html tools.html SEX.html robots.txt logo.jpg small_logo.jpg action-fex-camel.gif favicon.ico FAQ )) { cpa("$docdir/$i","$vhd/htdocs"); } symlink "$docdir/version","../../htdocs/version"; symlink "$docdir/download","../../htdocs/download"; cpa("$FEXHOME/locale",$vhd); foreach $ld (glob "$vhd/locale/*") { if (not -l $ld and -d "$ld/cgi-bin") { $locale = basename($ld); rmrf("$ld/cgi-bin"); # symlink "../../../locale/$locale/cgi-bin","$ld/cgi-bin"; symlink "../../../locale/$locale/htdocs","$vhd/htdocs/locale/$locale"; unlink "$ld/lib/fex.ph"; symlink "../../../lib/fex.ph","$ld/lib/fex.ph"; symlink "../../../../locale/$locale/lib","$ld/lib/master"; foreach $f (qw'dop fex.pp lf.pl reactivation.txt') { unlink "$ld/lib/$f"; symlink "master/$f","$ld/lib/$f"; } } } $fph = "$FEXLIB/fex.ph"; open $fph,">>$fph" or die "$0: cannot write to $fph = $!\n"; print {$fph} "\n\$vhost{'$hhost'} = '$vhd';\n"; close $fph; print "You must now edit and configure $vhd/lib/fex.ph\n"; print "or execute: $0 -V $vhost -c\n"; exit; } # show config if ($opt_v and not @ARGV) { print "config from $FEXLIB/fex.ph :\n"; print " spooldir = $spooldir\n"; print " logdir = @logdir\n"; print " docdir = $docdir\n"; print " durl = @durl\n"; print " admin = $admin\n"; print " mdomain = $mdomain\n"; print " mailmode = $mailmode\n"; print " autodelete = $autodelete\n"; print " keep_default = $keep_default\n"; printf " keep_max = %s\n",$keep_max||'unlimited'; printf " recipient_quota = %d GB\n",int($recipient_quota/1024); printf " sender_quota = %d GB\n",int($sender_quota/1024); while (($hh,$vh) = each %vhost) { printf " virtual server %s : %s\n",basename($vh),$hh; } # unless (@ARGV) { # foreach $ph (glob "$ENV{HOME}/*/lib/fex.ph") { # $ENV{FEXLIB} = dirname($ph); # print "\n"; # system $0,'-v',$ph; # } # } if ($m = readlink '@MAINTENANCE') { print "server is in maintenance mode ($m)!\n" ; } exit; } # add user or show user config if ($opt_u) { chdir $spooldir or die "$0: cannot chdir $spooldir = $!\n"; if ($opt_u = shift @ARGV) { $user = lc $opt_u; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; $id = shift @ARGV; $idf = "$user/@"; if (open $idf,$idf) { chomp($ido = <$idf>||''); close $idf; } unless ($id) { die "$0: $user is not a regular FEX user\n" unless -f "$user/@"; showuser($user,$ido); exit; } unless ($user =~ /\w@[\w.-]+\.[a-z]+$/) { die "$0: $user is not a valid email-address!\n"; } unless (-d $user) { mkdir $user,0755 or die "$0: cannot mkdir $user - $!\n"; } open F,">$idf" or die "$0: cannot write $idf - $!\n"; print F $id,"\n"; close F or die "$0: cannot write $idf - $!\n"; showuser($user,$id); } else { print "Users in $spooldir:\n"; foreach $user (glob "*/@") { $user =~ s:.*/(.+)/@:$1:; print "$user\n"; } } exit; } # set user autodelete default if ($opt_a) { $user = lc $opt_a; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; $_ = shift @ARGV || ''; if (/^n/i) { $autodelete = 'no' } elsif (/^y/i) { $autodelete = 'yes' } elsif (/^d/i) { $autodelete = 'delay' } else { die "usage: $0 -a user yes\n". "usage: $0 -a user no\n". "usage: $0 -a user delay\n". "example: $0 -a framstag\@rus.uni-stuttgart.de no\n"; } mkdir "$spooldir/$user",0755; my $adf = "$spooldir/$user/\@AUTODELETE"; unlink $adf; symlink $autodelete,$adf or die "$0: cannot create symlink $adf - $!\n"; exit; } # set user notification default if ($opt_n) { $user = lc $opt_n; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; $_ = shift @ARGV || ''; if (/^n/i) { $notification = 'no' } elsif (/^[sb]/i) { $notification = 'short' } elsif (/^[fd]/i) { $notification = '' } else { die "usage: $0 -n user no\n". "usage: $0 -n user brief\n". "usage: $0 -n user detailed\n". "example: $0 -n framstag\@rus.uni-stuttgart.de brief\n"; } mkdir "$spooldir/$user",0755; my $ndf = "$spooldir/$user/\@NOTIFICATION"; unlink $ndf; if ($notification) { symlink $notification,$ndf or die "$0: cannot create symlink $ndf - $!\n"; } exit; } # set user keep default if ($opt_k) { $user = lc $opt_k; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; my $keep = shift @ARGV || ''; if ($keep !~ /^\d+$/) { die "usage: $0 -k user keep_days\n". "example: $0 -k framstag\@rus.uni-stuttgart.de 30\n"; } mkdir "$spooldir/$user",0755; my $kf = "$spooldir/$user/\@KEEP"; unlink $kf; symlink $keep,$kf or die "$0: cannot create symlink $kf - $!\n"; exit; } # quota if ($opt_q) { $user = lc $opt_q; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; unless (-d "$spooldir/$user") { die "$0: $user is not a FEX user\n"; } quota($user,@ARGV); exit; } if ($opt_C) { $user = lc $opt_C; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; unless (-f "$spooldir/$user/@") { die "$0: $user is not a regular FEX user\n"; } $_ = shift @ARGV || ''; if (/^y/i) { open $user,">>$spooldir/$user/\@CAPTIVE"; close $user; print "$user is now captive\n"; } elsif (/^n/i) { unlink "$spooldir/$user/\@CAPTIVE"; print "$user is no more captive\n"; } else { die "usage: $0 -C user yes\n". "usage: $0 -C user no\n". "example: $0 -C framstag\@rus.uni-stuttgart.de no\n"; } exit; } # FEXYOURSELF = user can only fex to himself via web interface if ($opt_y) { $user = lc $opt_y; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; unless (-f "$spooldir/$user/@") { die "$0: $user is not a regular FEX user\n"; } $_ = shift @ARGV || ''; if (/^y/i) { open $user,">>$spooldir/$user/\@FEXYOURSELF"; close $user; print "$user has now \"fex yourself\" web default\n"; } elsif (/^n/i) { unlink "$spooldir/$user/\@FEXYOURSELF"; print "$user has no \"fex yourself\" web default\n"; } else { die "usage: $0 -y user yes\n". "usage: $0 -y user no\n". "example: $0 -y framstag\@rus.uni-stuttgart.de no\n"; } exit; } if ($opt_D) { $user = lc $opt_D; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; $_ = $ARGV[0] || ''; if (/^no?$/i) { unlink "$spooldir/$user/\@DISABLED"; print "$user is now enabled\n"; } else { open $user,">>$spooldir/$user/\@DISABLED"; print {$user} "@ARGV\n"; close $user; print "$user is now disabled\n"; } exit; } if ($opt_P) { $user = lc $opt_P; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; $_ = shift @ARGV || ''; if (/^y/i) { open $user,">>$spooldir/$user/\@PERSISTENT"; close $user; print "$user is now persistent\n"; } elsif (/^n/i) { unlink "$spooldir/$user/\@PERSISTENT"; print "$user is no more persistent\n"; } else { die "usage: $0 -P user yes\n". "usage: $0 -P user no\n". "example: $0 -P framstag\@rus.uni-stuttgart.de yes\n"; } exit; } if ($opt_S eq 'fup') { &fupstat; exit; } if ($opt_S eq 'fop') { &fopstat; exit; } usage(3); sub showuser { my $user = shift; my $id = shift; my ($keep,$autodelete,$notification,$login); $user .= '@'.$mdomain if $mdomain and $user !~ /@/; print "[using config $FEXLIB/fex.ph]\n"; print "$fup?from=$user&id=$id\n"; printf "%s/%s\n",$fup,b64("from=$user&id=$id"); # printf "%s/%s\n",$fup,b64("from=$user&to=$user&id=$id&submit=."); print "spool: $spooldir/$user/\n"; if ($login_check and $login = readlink "$user/.login") { my $lc = &$login_check($login); if ($lc) { print "login: $login\n"; } else { print "login: DELETED\n"; } } my $disabled = 'no'; if (-e "$spooldir/$user/\@DISABLED") { $disabled = slurp("$spooldir/$user/\@DISABLED"); chomp $disabled; $disabled ||= 'yes'; } printf "fex yourself web default: %s\n", -e "$spooldir/$user/\@FEXYOURSELF" ? 'yes' : 'no'; printf "persistent: %s\n", -e "$spooldir/$user/\@PERSISTENT" ? 'yes' : 'no'; printf "captive: %s\n", -e "$spooldir/$user/\@CAPTIVE" ? 'yes' : 'no'; printf "disabled: %s\n",$disabled; printf "recipients restrictions: %s\n", -e "$spooldir/$user/\@ALLOWED_RECIPIENTS" ? 'yes' : 'no'; printf "upload restrictions: %s\n", -e "$spooldir/$user/\@UPLOAD_HOSTS" ? 'yes' : 'no'; printf "download restrictions: %s\n", -e "$spooldir/$user/\@DOWNLOAD_HOSTS" ? 'yes' : 'no'; $autodelete = lc(readlink "$spooldir/$user/\@AUTODELETE" || $::autodelete); print "autodelete default: $autodelete\n"; $notification = lc(readlink "$spooldir/$user/\@NOTIFICATION" || $::notification); print "notification default: $notification\n"; $keep = readlink "$spooldir/$user/\@KEEP" || $keep_default; print "keep default: $keep\n"; quota($user); printf "account creation: %s\n",slurp("$spooldir/$user/.auto")||'manual'; } # set or show disk quota sub quota { my $user = shift; my $rquota = ''; my $squota = ''; my $qf = "$spooldir/$user/\@QUOTA"; local $_; if (open $qf,$qf) { while (<$qf>) { s/#.*//; $rquota = $1 if /recipient.*?(\d+)/i; $squota = $1 if /sender.*?(\d+)/i; } close $qf; } if (@_) { for (@_) { $rquota = $1 if /^r.*:(\d*)/i; $squota = $1 if /^s.*:(\d*)/i; } open $qf,'>',$qf or die "$0: cannot write $qf - $!\n"; print {$qf} "recipient:$rquota\n" if $rquota; print {$qf} "sender:$squota\n" if $squota; close $qf; } printf "recpient quota (used): %d (%d) MB\n",check_recipient_quota($user); printf "sender quota (used): %d (%d) MB\n",check_sender_quota($user); } sub fupstat { my (%user,%domain,%du); my ($log,$u,$d,$z); my $Z = 0; if (-t) { $log = "$logdir/fup.log" } else { $log = '>&=STDIN' } open $log,$log or die "$0: cannot open $log - $!\n"; while (<$log>) { if (/^([\d: -]+) (\[[\d_]+\] )?(\w\S*) .* (\d+)$/) { $z = $4; $u = $3; $u .= '@'.$mdomain if $mdomain and $u !~ /@/; $user{$u} += $z; $d = $u; $d =~ s/.*@//; $d =~ s/.*\.(.+\.\w+)/$1/; $domain{$d} += $z; $du{$d}{$u}++; $Z += $z; } } foreach $u (sort {$user{$a} <=> $user{$b}} keys %user) { printf "%s : %d\n",$u,$user{$u}/M; } print "========================================================\n"; foreach $d (sort {$domain{$a} <=> $domain{$b}} keys %domain) { printf "%s : %d MB, %d user\n",$d,$domain{$d}/M,scalar(keys %{$du{$d}}); } printf "Total: %d GB\n",$Z/M/1024; exit; } sub fopstat { my $Z = 0; my ($log,$u,$d,$z); my (%user,%domain,%du); if (-t) { $log = "$logdir/fop.log" } else { $log = '>&=STDIN' } open $log,$log or die "$0: cannot open $log - $!\n"; while (<$log>) { if (/^([\d: -]+) (\[[\d_]+\] )?[\d.]+ (.+?)\/.* (\d+)\/\d+/) { $z = $4; $u = $3; $u .= '@'.$mdomain if $mdomain and $u !~ /@/; $user{$u} += $z; $d = $u; $d =~ s/.*@//; $d =~ s/.*\.(.+\.\w+)/$1/; $domain{$d} += $z; $du{$d}{$u}++; $Z += $z; } } foreach $u (sort {$user{$a} <=> $user{$b}} keys %user) { printf "%s : %d\n",$u,$user{$u}/M; } print "========================================================\n"; foreach $d (sort {$domain{$a} <=> $domain{$b}} keys %domain) { printf "%s : %d MB, %d user\n",$d,$domain{$d}/M,scalar(keys %{$du{$d}}); } printf "Total: %d GB\n",$Z/M/1024; exit; } sub cpa { my $dd = pop @_; die "(cpa): $dd is not a directory" unless -d $dd; system "rsync -a @_ $dd/" ; } sub check_admin { my $admin_id = slurp("$spooldir/$admin/@") or die "$0: no admin account - you have to create it with:\n". "$0 -/ $admin ".randstring(8)."\n"; chomp $admin_id; my $fid = "$ENV{HOME}/.fex/id"; if (open $fid,$fid) { $_ = <$fid>; chomp($_ = <$fid>||''); if ($_ ne $admin) { warn "WARNING: user $admin not in $fid\n"; $mismatch++; } chomp($_ = <$fid>||''); if ($_ ne $admin_id) { warn "WARNING: $admin auth-ID mismatch in $fid\n"; $mismatch++; } close $fid; if ($mismatch) { warn "$0: moving $fid to ${fid}_save\n"; rename $fid,$fid.'_save'; } } unless (-f $fid) { mkdir dirname($fid); open $fid,'>',$fid or die "$0: cannot create $fid - $!\n"; if ($durl =~ m{(https?://.+?)/}) { print {$fid} "$1\n"; } else { print {$fid} "$hostname\n"; } print {$fid} "$admin\n"; print {$fid} "$admin_id\n"; close $fid; warn "$0: new $fid created\n"; } } sub d3 { local $_ = shift; while (s/(\d)(\d\d\d\b)/$1,$2/) {}; return $_; } sub usage { my $port = ''; my $proto = 'http'; if ($durl =~ /:(\d+)/) { $port = ":$1" } if ($durl =~ /^(https?)/) { $proto = $1 } $0 =~ s:.*/::; print <) { next if /(^|\n)($ignore)/i; s/[\x00-\x08\x0B-\x1F\x1F\x80-\x9F]/_/g; s/^\n//; foreach $weed (@weed) { while (s/\n$weed.*\n/\n/i) {} } $post = /\nPOST\s/; if (/^\n*(CONNECT|CONTINUE).*\s\[([\d_]+)\]/i) { $pid = $2 } if (/\n(POST|GET)\s+(\S+)/i) { $cgi = $2; $cgi =~ s:.*/::; $cgi =~ s:\?.*::; } if (/Content-Length: (\d+)/i) { $d = $1; while ($d =~ s/(\d)(\d\d\d\b)/$1,$2/) {}; s/Content-Length: \d+/Content-Length: $d/i; } s/[\s\n]*$/\n\n/; print or exit; $from = ''; if (m:\nGET /fup/(\w{40,}):) { $_ = decode_b64($1); printf " FROM=\"%s\"\n\n",$1 if /from=([\w\@.-]+)/; } elsif (m:\nGET /fop/(\w+)/:) { $dkey = $1; my $ddir = "$spooldir/.dkeys/$dkey"; $_ = readlink $ddir or next; (undef,$to,$from) = split('/'); printf " FROM=\"%s\"\n",$from; printf " TO=\"%s\"\n",$to; $cgi = ''; if ($comment = slurp("$ddir/comment")) { printf " COMMENT=\"%s\"\n",utf8decode($comment)||''; } if (not -f "$ddir/data" and $_ = slurp("$ddir/error")) { s/\n.*//s; print " ERROR=\"$_\"\n"; } elsif ($size = -s "$ddir/data") { printf " SIZE=%s MB\n",int($size/1024/1024); } print "\n"; } elsif (m:\nGET /fup.*skey=(\w+):) { read_skey($1); print "\n"; } if ($debug and $pid and $post) { &read_debug_log; }; $pid = $cgi = ''; } sleep 1; } sub read_debug_log { my (@log,$log); local $/ = "\n"; local $_; # https://rt.cpan.org/Public/Bug/Display.html?id=88592 # local $^W; # no warnings "all"; no warnings 'utf8'; for (1..2) { sleep 1; @log = `ls -rt $logdir[0]/.debug/*_${pid}.$cgi 2>/dev/null`; if ($log = $log[-1] and open $log,$log) { binmode($log,":utf8"); while (<$log>) { s/\r//; s/[^\x09\x20-\xFF]/_/g; if (/^Content-Disposition:.*name="FILE".*filename="(.+)"/i) { print " FILE=\"$1\"\n"; } elsif (/^Content-Disposition:.*name="(\w+)"/i) { my $p = uc($1); $_ = <$log>; my $v = <$log>||''; $v =~ s/[\r\n]+//; if ($v) { my $vv = utf8decode($v)||$v; $vv =~ s/[\x00-\x1F]/_/g; $vv =~ s/[\x80-\x9F]/_/g; printf " %s=\"%s\"\n",$p,$vv; read_akey($v) if $p eq 'AKEY'; read_skey($v) if $p eq 'SKEY'; } } elsif (/^(Param|Exp): (\w+=".+")/) { print " $2\n"; } } close $log; print "\n"; return; } } } sub read_akey { my $akey = "$spooldir/.akeys/" . shift; if (my $user = readlink($akey)) { $user =~ s:../::; printf " USER=\"%s\"\n",$user; } } sub read_skey { my $skey = "$spooldir/.skeys/" . shift; if (open $skey,$skey) { while (<$skey>) { printf " FROM=\"%s\"\n",$1 if /from=(.+)/; printf " TO=\"%s\"\n",$1 if /to=(.+)/; } close $skey; } } sub utf8decode { local $_ = shift; s/([\xC0-\xDF])([\x80-\xBF])/chr(ord($1)<<6&0xC0|ord($2)&0x3F)/eg; return $_; } fex-20160919/bin/mksgkeys0000755000174700017470000000276112022437376013262 0ustar fexfex#!/usr/bin/perl -w # helper script to regenerate missing SKEYs and GKEYs use Digest::MD5 qw(md5_hex); @pw = getpwnam('fex'); $spool = $pw[7].'/spool'; chdir $spool or die "$spool - $!"; foreach $suf (glob "*/\@SUBUSER") { if (-f $suf and open $suf,$suf) { $to = $user = $suf; $to =~ s:/.*::; $user =~ s:/.*::; while (<$suf>) { chomp; s/#.*//; if (/(.+):(.+)/) { $from = $1; $id = $2; $skey = md5_hex("$user:$from:$id"); unless (-f ".skeys/$skey") { if (open $skey,">.skeys/$skey") { warn "creating $spool/.skeys/$skey\n"; print {$skey} "from=$from\n"; print {$skey} "to=$to\n"; print {$skey} "id=$id\n"; close $skey; } } } } close $suf; } } foreach $guf (glob "*/\@GROUP/*") { if (-f $guf and not -l $guf and open $guf,$guf) { $group = $user = $guf; $group =~ s:.*/::; $user =~ s:/.*::; while (<$guf>) { chomp; s/#.*//; if (/(.+):(.+)/) { $from = $1; $id = $2; $gkey = md5_hex("$user:$group:$from:$id"); unless (-f ".gkeys/$gkey") { if (open $gkey,">.gkeys/$gkey") { warn "creating $spool/.gkeys/$gkey\n"; print {$gkey} "from=$from\n"; print {$gkey} "to=\@$group\n"; print {$gkey} "user=$user\n"; print {$gkey} "id=$id\n"; close $gkey; } } } } close $guf; } } fex-20160919/bin/xx0000777000174700017470000000000012770010176013422 2fexsendustar fexfexfex-20160919/bin/sexget0000777000174700017470000000000012770010176014277 2sexsendustar fexfexfex-20160919/bin/sexxx0000777000174700017470000000000012770010176014157 2sexsendustar fexfexfex-20160919/bin/asex0000777000174700017470000000000012770010176013212 2afexustar fexfexfex-20160919/bin/ll0000777000174700017470000000000012770010176012171 2lustar fexfexfex-20160919/bin/lf0000777000174700017470000000000012770010176012163 2lustar fexfexfex-20160919/cgi-bin/0000755000174700017470000000000012770010176012224 5ustar fexfexfex-20160919/cgi-bin/fup0000711000174700017470000026200512770010174012737 0ustar fexfex#!/usr/bin/perl -wT # F*EX CGI for upload # # Author: Ulli Horlacher # # Contribs: # Sebastian Zaiser (upload status) # BEGIN { ($ENV{PERLINIT}||'') =~ /(.+)/s and eval $1 } use utf8; use Encode; use Fcntl qw':flock :seek :mode'; use IO::Handle; use Digest::MD5 qw'md5_hex'; use Cwd qw'abs_path'; # add fex lib (our $FEXLIB) = $ENV{FEXLIB} =~ /(.+)/; $| = 1; our $debug; our $ndata = 0; our $error = 'F*EX upload ERROR'; our $head = "$ENV{SERVER_NAME} F*EX upload"; our $autodelete = 'YES'; our $locale; # import from fex.ph our (@locales,@throttle,$bcc,$keep_max,$nomail,$nostore,$overwrite); our (@local_domains,@local_rdomains,@local_hosts,@local_rhosts,); our (@registration_hosts,@demo,@file_link_dirs); # import from fex.pp our ($FEXHOME); 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,$amdl); our ($dkeydir,$ukeydir,$akeydir,$skeydir,$gkeydir,$xkeydir); our ($MB,$DS); our $RB; # read POST bytes (total) our $akey = ''; our $dkey = ''; our $skey = ''; our $gkey = ''; our $seek = 0; # already sent bytes (from previous upload) our $filesize = 0; # total file size our $fpsize = 0; # file part size (MIME-part) my $data; my $boundary; my $rid = ''; # real ID 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"; # load fup local config our ($info_1,$info_2,$info_login); $locale = $ENV{LOCALE} || 'english'; foreach ( "/var/lib/fex/locale/$locale/lib/fup.pl", "$FEXLIB/fup.pl", ) { if (-f) { require; last; } } &check_camel unless $sid; chdir $spooldir or http_die("$spooldir - $!\n"); my $log = 'fup.log'; my $http_client = $ENV{HTTP_USER_AGENT} || ''; my $cl = $ENV{X_CONTENT_LENGTH} || $ENV{CONTENT_LENGTH} || 0; $fra .= '/'.$ENV{HTTP_X_FORWARDED_FOR} if $ENV{HTTP_X_FORWARDED_FOR}; $from = $to = $id = $file = $fkey = $comment = $command = $bwlimit = ''; $filename = $okey = $addto = $replyto = $submit = ''; @to = (); $data = ''; $locale = untaint($ENV{LOCALE}||''); my $ra = $ENV{REMOTE_ADDR}||0; if (@upload_hosts and not ipin($ra,@upload_hosts)) { http_die( "Uploads from your host ($ra) are not allowed.", "Contact $ENV{SERVER_ADMIN} for details." ); } &check_maint; &parse_request; # showstatus will not come back! if ($addto) { my %to; foreach $to (@to) { $to{$to} = 1 } push @to,$addto unless $to{$addto}; # user has submitted with [select from your address book] ? # if ($submit and @to == 1) { $addto = '' } } $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 $id_forgotten = $id if $id =~ /^"?\?"?$/; if ($from and $id_forgotten and $mail_authid and not ($fop_auth or $nomail)) { &check_status($from); &id_forgotten; exit; } # public recipients? (needs no auth-ID for sender) if ($to and $id and $id eq 'PUBLIC' and @public_recipients) { unless ($from) { http_die("missing sender e-mail address"); } # must use $param{FROM} for checking because $from is expanded with $mdomain unless (checkaddress(despace($param{FROM}))) { http_die("$param{FROM} is not a valid e-mail address"); } foreach my $to (@to) { unless (grep /^\Q$to\E$/i,@public_recipients) { http_die("$to is not a valid recipient"); } } $restricted = $public = $rid = $id; } # anonymous upload from enabled IP? if ($from =~ /^anonymous@/ and @anonymous_upload and ipin($ra,@anonymous_upload)) { $id = $rid = $anonymous = 'anonymous'; if ($to =~ /^anonymous/) { @to = ($to); $autodelete{$to} = $autodelete = $specific{'autodelete'}||'NO'; } $nomail = $anonymous; } $comment = 'NOMAIL' if $nomail and not $comment; # one time token if ($okey) { $to = "@to" or http_die("no recipient specified"); $from = readlink "$to/\@OKEY/$okey" or http_die("no upload key \"$okey\" - ". "request another one from $to"); $from = untaint($from); } &check_status($from) if $from; # look for regular sender ID if ($id and $from and not ($public or $anonymous or $okey)) { if (open $from,'<',"$from/\@") { # chomp($rid = <$from> || ''); $rid = getline($from); close $from; $rid = sidhash($rid,$id); # set time mark for successfull access if ($id eq $rid) { my $time = untaint(time); utime $time,$time,$from; } } else { my $error = $!; # if recipient (to) is specified, we have to look for subusers later, too unless (@to) { fuplog("ERROR: $spooldir/$from/\@ $error"); debuglog("cannot open $spooldir/$from/\@ : $error"); faillog("user $from, id $id"); http_die("wrong user or auth-ID"); } } } # check regular ID if ($from and $id and not ($gkey or $skey or $public or $okey)) { if ($rid and $rid eq $id) { # 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 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"); } } $captive = -e "$from/\@CAPTIVE"; } else { fuplog("ERROR: wrong auth-ID for $from"); debuglog("id sent by user $from=$id, real id=$rid"); faillog("user $from, id $id"); http_die("Wrong user or auth-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"||''); http_die("unknown dkey $dkey>") unless $file; $file =~ s:^\.\./::; forward($file); exit; } # modify file parameter if ($akey and $dkey and $command eq 'MODIFY') { my $file = untaint(readlink "$dkeydir/$dkey"||''); http_die("unknown dkey $dkey") unless $file; $file =~ s:^\.\./::; modify($file); exit; } # copy file from incoming to outgoing spool if ($akey and $dkey and $command eq 'COPY') { unless ($file = readlink "$dkeydir/$dkey") { http_die("No such file with DKEY=$dkey"); } if ($file =~ m:../(.+)/(.+)/(.+):) { ($to,$from,$file) = ($1,$2,$3); } else { http_die("Bad DKEY $dkey -> $file"); } unless (-f "$to/$from/$file/data") { http_die("File not found"); } if (-e "$to/$to/$file/data") { http_die("File $file already exists in your outgoing spool") if (readlink("$to/$to/$file/id")||$to) ne (readlink("$to/$from/$file/id")||$from); } else { mkdirp("$to/$to/$file"); link "$to/$from/$file/data","$to/$to/$file/data" or http_die("cannot link to $to/$to/$file/data - $!\n"); copy("$to/$from/$file/filename","$to/$to/$file/filename"); copy("$to/$from/$file/id","$to/$to/$file/id"); open $file,'>',"$to/$to/$file/notify"; close $file; open $file,'>',"$to/$to/$file/download"; print {$file} "$to\n"; close $file; $dkey = randstring(8); unlink "$to/$to/$file/dkey","$to/$to/$file/keep","$dkeydir/$dkey"; symlink "../$to/$to/$file","$dkeydir/$dkey"; symlink $dkey,"$to/$to/$file/dkey"; } nvt_print( "HTTP/1.1 302 Found", "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/rup?akey=$akey&oto=$to&file=$file", 'Content-Length: 0', '' ); &reexec; } # delete file without download if ($akey and $dkey and $command eq 'DELETE') { $del = untaint(readlink "$dkeydir/$dkey"||''); http_die("unknown dkey $dkey") unless $del; $del =~ s:^\.\./::; $filename = filename($del); if (unlink("$del/data") or unlink("$del/upload")) { if (open F,'>',"$del/error") { printf F "%s has been deleted by %s at %s\n", $filename,$ENV{REMOTE_ADDR},isodate(time); close F; } # http_header('200 OK'); # print html_header($head); # print "

$filename deleted

\n"; nvt_print( "HTTP/1.1 302 Found", "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/fup?akey=$akey&command=LISTRECEIVED", 'Content-Length: 0', "" ); &reexec; } else { my $s = $!; http_header('404 Not Found'); print html_header($head); print "

$filename not deleted ($s)

\n"; print "continue\n" if $akey; print "\n"; } exit; } # special commands if (($from and $id and $rid eq $id or $gkey or $skey) and $command) { if ($command eq 'CHECKQUOTA') { http_die("illegal command \"$command\"") if $public or $anonymous; nvt_print('HTTP/1.1 204 OK'); # nvt_print("X-SID: $ENV{SID}") if $ENV{SID}; ($quota,$du) = check_sender_quota($muser||$from); nvt_print("X-Sender-Quota: $quota $du") if $quota; ($quota,$du) = check_recipient_quota($muser||$from); nvt_print("X-Recipient-Quota: $quota $du") if $quota; nvt_print(''); exit; } if ($command eq 'LISTSETTINGS') { http_die("illegal command \"$command\"") if $public or $anonymous; nvt_print('HTTP/1.1 204 OK'); # nvt_print("X-SID: $ENV{SID}") if $ENV{SID}; ($quota,$du) = check_sender_quota($muser||$from); nvt_print("X-Sender-Quota: $quota $du") if $quota; ($quota,$du) = check_recipient_quota($muser||$from); nvt_print("X-Recipient-Quota: $quota $du") if $quota; $autodelete = lc(readlink "$from/\@AUTODELETE" || $autodelete); nvt_print("X-Autodelete: $autodelete"); $keep = readlink "$from/\@KEEP" || $keep; nvt_print("X-Default-Keep: $keep"); $locale = readlink "$from/\@LOCALE" || $default_locale || 'english'; nvt_print("X-Default-Locale: $locale"); $mime = -e "$from/\@MIME" ? 'yes' : 'no'; nvt_print("X-MIME: $mime"); nvt_print(''); exit; } if ($command eq 'RENOTIFY') { http_die("illegal command \"$command\"") if $public or $anonymous; my $nfile = ''; if ($dkey) { # resend notification e-mail $file = readlink("$dkeydir/$dkey") or html_error($error,"illegal DKEY $dkey"); $file =~ s:^../::; $file = untaint($file); unlink "$file/download"; # re-allow download from any ip address notify_locale($dkey,'new'); http_header( '200 OK', "X-Notify: $file", ); $nfile = $file; } else { http_header('200 OK'); } print html_header($head); # list sent files print "

Files from $from, ", "click on the file name to resend a notification e-mail:

\n", "
\n";
    foreach $file (glob "*/$from/*") {
      next if $file =~ m:/STDFEX$:;
      next if $file =~ m:(.+?)/: and -l $1;
      $size = -s "$file/data";
      next unless $size;
      $size = int($size/$MB+0.5);
      $filename = $comment = '';
      my $rto = $file;
      $rto =~ s:/.*::;
      if ($dkey = readlink "$file/dkey") {
        if ($rto ne $to) {
          $to = $rto;
          print "\nto $to :\n";
        }
        if (open $file,'<',"$file/filename") {
          $filename = <$file>;
          close $file;
        }
        if ($filename and length $filename) {
          $filename = html_quote($filename);
        } else {
          $filename = '???';
        }
        if (open $file,'<',"$file/comment") {
          $comment = untaint(html_quote(getline($file)));
          close $file;
        }
        my $rkeep = untaint(readlink "$file/keep"||$keep_default)
                    - int((time-mtime("$file/filename"))/$DS);
        if ($comment =~ /NOMAIL/ or
           (readlink "$to/\@NOTIFICATION"||'') =~ /^no/i) {
          printf "%8s MB (%2s d) %s/%s/%s\n",
                 $size,
                 $rkeep,
                 $durl,
                 $dkey,
                 urlencode(basename($file));
        } else {
          printf "%8s MB (%2s d) %s%s %s\n",
                 $size,
                 $rkeep,
                 untaint("/fup?akey=$akey&dkey=$dkey&command=RENOTIFY"),
                 $filename,
                 $comment ? qq' "$comment"' : '',
                 $file eq $nfile ?
                   " → notification e-mail has been resent" :
                   "";
        }
      }
    }
    pq(qq(
      '
' '

back to F*EX operation control' '' )); exit; } if ($command =~ /^LIST(RECEIVED)?$/) { http_die("illegal command \"$command\"") if $public or $anonymous; # list sent files if ($to and $param{'TO'} eq '*') { http_header('200 OK'); print html_header($head); # "(Format: [size] [rest keep time] [filename] [comment])

\n", print "

Files from $from:

\n", "
\n";
      foreach $file (glob "*/$from/*") {
        next if $file =~ m:/STDFEX$:;
        next if $file =~ m:(.+?)/: and -l $1;
        $size = -s "$file/data";
        next unless $size;
        $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";
          }
          if (open $file,'<',"$file/filename") {
            $filename = <$file>;
            close $file;
          }
          if ($filename and length $filename) {
            $filename = html_quote($filename);
          } else {
            $filename = '???';
          }
          if (open $file,'<',"$file/comment") {
            $comment = untaint(html_quote(getline($file)));
            close $file;
          }
          my $rkeep = untaint(readlink "$file/keep"||$keep_default)
                      - int((time-mtime("$file/filename"))/$DS);
          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"):'';
        }
      }
      pq(qq(
        '
' '

back to F*EX operation control' '' )); } # list received files else { $to = $from; http_header('200 OK'); print html_header($head); # "(Format: [size] [rest keep time] [URL] [comment])

\n", print "

Files for $to (*):

\n", "
\n";
      foreach $from (glob "$to/*") {
        next if $from =~ /[A-Z]/;
        $from =~ s:.*/::;
        $url = '';
        foreach $file (glob "$to/$from/*") {
          next if $file =~ /\/STDFEX$/;
          $filename = $comment = '';
          $size = -s "$file/data";
          next unless $size;
          $size = int($size/$MB+0.5);
          if ($dkey = readlink "$file/dkey") {
            print "\nfrom $from :\n" unless $url;
            $file =~ m:.*/(.+):;
            $url = "$durl/$dkey/$1";
            unless (-l "$dkeydir/$dkey") {
              symlink untaint("../$file"),untaint("$dkeydir/$dkey");
            }
            if (open $file,'<',"$file/filename") {
              $filename = <$file>;
              close $file;
            }
            if ($filename and length $filename) {
              $filename = html_quote($filename);
            } else {
              $filename = '???';
            }
            if (open $file,'<',"$file/comment") {
              $comment = untaint(html_quote(getline($file)));
              $comment = ' "'.$comment.'"';
              close $file;
            }
            my $rkeep = untaint(readlink "$file/keep"||$keep_default)
                        - int((time-mtime("$file/filename"))/$DS);
            printf "[delete] ",
                   $akey,$dkey;
            printf "[forward] ",
                   $akey,$dkey;
            printf "%8s MB (%2s d) %s%s\n",
                   $size,$rkeep,$url,$filename,$comment;
          }
        }
      }
      pq(qq(
        '
' '(*) Files for other e-mail addresses you own will not be listed here!

' 'back to F*EX operation control' '' )); } exit; } if ($command eq 'LISTSENT') { http_die("illegal command \"$command\"") if $public or $anonymous; # show download URLs http_header('200 OK'); print html_header($head); print "

Download URLs of files you have sent\n"; foreach $to (glob "*/$from") { if (@files = glob "$to/*/data") { $to =~ s:/.*::; print "

to $to :

\n"; print "
\n";
        foreach $file (@files) {
          $file =~ s:/data::;
          next if $file =~ /\/STDFEX$/;
          $dkey = readlink "$file/dkey" or next;
          $file =~ s:.*/::;
          print "$ENV{PROTO}://$ENV{HTTP_HOST}/fop/$dkey/$file\n";
        }
        print "
\n"; } } pq(qq( '

' '

back to F*EX operation control' '' )); exit; } if ($command eq 'FOPLOG') { http_die("illegal command \"$command\"") if $public or $anonymous; if (open my $log,"$logdir/fop.log") { http_header('200 OK'); while (<$log>) { next if /\/STDFEX\s/; if (s:^([^/]+)/$from/:$1 :) { if (s:(\d+)/(\d+)$:$1: and $1 and $1 == $2) { s/ \[[\d_]+\]//; print; } } } } exit; } if ($command eq 'RECEIVEDLOG') { http_die("illegal command \"$command\"") if $public or $anonymous; if (open my $log,"$logdir/fup.log") { http_header('200 OK'); while (<$log>) { next if /\sSTDFEX\s/; if (/\d+$/) { my @F = split; if ($F[5] eq $to) { s/ \[[\d_]+\]//; print; } } } } exit; } if ($command eq 'SENDLOG') { http_die("illegal command \"$command\"") if $public or $anonymous; if (open my $log,"$logdir/fup.log") { http_header('200 OK'); while (<$log>) { next if /\sSTDFEX\s/; if (/(\S+\@\S+)/ and $1 eq $from) { s/ \[[\d_]+\]//; print; } } } exit; } if (@to and $command eq 'CHECKRECIPIENT') { http_die("illegal command \"$command\"") if $public or $anonymous; check_rr($from,@to); nvt_print('HTTP/1.1 204 OK'); nvt_print("X-SID: $sid") if $sid; 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)", $autodelete{$to}||$autodelete, $keep{$to}||$keep_default, readlink("$to/\@LOCALE")||$locale{$to}||$default_locale; # readlink("$to/\@NOTIFICATION")||'full'; nvt_print("X-Recipient: $to $options"); } nvt_print(''); # control back to fexsrv for further HTTP handling &reexec; } if ($file and @to and $command eq 'DELETE') { http_die("illegal command \"$command\"") if $public or $anonymous; foreach (@group?@group:@to) { my $to = $_; $to =~ s/:\w+=.*//; # remove options from address $del = "$to/$from/$fkey"; # swap to and from for special senders, see fup storage swap! $del = "$from/$to/$fkey" if $from =~ /^(fexmail|anonymous)/; $del =~ s:^/+::; if ($del =~ /\/\./) { http_die("illegal parameter $del"); } $del = untaint($del); if (unlink("$del/data") or unlink("$del/upload")) { if (open F,'>',"$del/error") { print F "$file has been deleted by $from\n"; close F; } http_header('200 OK',"X-File: $del"); print html_header($head); print "

$file deleted

\n"; } else { http_header("404 Not Found"); print html_header($head); print "

$file not deleted

\n"; } if ($akey) { printf "continue\n", $akey,$to; } print "\n"; } exit; } } # ip restrictions if ($from and $id and $rid eq $id and open my $ipr,"$from/\@UPLOAD_HOSTS") { my @hosts; while (<$ipr>) { chomp; s/#.*//; push @hosts,$_ if /\w/; } close $ipr; unless (@hosts and ipin($ra,@hosts)) { http_die("$from is not allowed to upload from IP $ra"); } } # quotas if ($from and $id and $rid eq $id and @to and not $flink and not $seek) { my ($quota,$du); # check sender quota ($quota,$du) = check_sender_quota($muser||$from); 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/$MB > $quota) { http_die("$to cannot receive files: is overquota"); } } } # check recipients restriction if ($id and $id eq $rid and $from and @to and not $public) { check_rr($from,@to); } # on secure mode "fop authorization" also check if recipient(s) exists # (= 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 my $to (my @loop = @to) { $to =~ s/:\w+=.*//; # remove options from address $to_reg = 0; # full user? if (open $idf,'<',"$to/@") { $to_reg = getline($idf); close $idf; } # sub user? elsif (open $idf,'<',"$from/\@SUBUSER") { while (<$idf>) { s/#.*//; next unless /:/; chomp; ($subuser) = split ':'; if ($subuser eq $to or $subuser eq '*@*' or $subuser =~ /^\*\@(.+)/ and $to =~ /\@\Q$1\E$/i or $subuser =~ /(.+)\@\*$/ and $to =~ /^\Q$1\E\@/i) { $to_reg = $_; last; } } close $idf; } unless ($to_reg) { http_die("recipient $to is not a registered F*EX full or sub user"); } } } $to = join(',',@to); if ($to =~ /^@(.+)/) { if ($nomail) { http_die("server runs in NOMAIL mode - groups ($to) are not allowed"); } my $gf = "$from/\@GROUP/$1"; if (open $gf,'<',$gf) { while (<$gf>) { s/#.*//; push @group,$1 if /(.+@.+):/; } } close $gf; $group = $to; } if ($redirect) { nvt_print( "HTTP/1.1 302 Found", "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/$redirect?akey=$akey", 'Content-Length: 0', "" ); &reexec; } if ($from and $id and $id eq $rid and $faillog) { unlink $faillog; } # display HTML form and request user data unless ($file) { if ($test) { $cgi = $test } else { $cgi = $ENV{SCRIPT_NAME} } $cgi = 'fup'; # delete old cookies on logout referer my @cookies; if ($logout and my $cookie = $ENV{HTTP_COOKIE}) { while ($cookie =~ s/(\w+key)=\w+//) { push @cookies,"Set-Cookie: $1=x; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"; } } 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; } mksymlink("$from/\@LOCALE",$locale) if $locale; } http_header('200 OK',@cookies); # print html_header($head,''); print html_header($head); if ($http_client =~ /(Konqueror|w3m)/) { pq(qq( '


' '

' '

Your client seems to be "$1" which is incompatible with F*EX and will probably not work!

' 'We recommend firefox.' '
' '


' )); } # default "fex yourself" setting? if ($from and $id and $id eq $rid and not $addto and not ($gkey or $skey or $okey or $public or $anonymous) and (not @to or "@to" eq $from) and -f "$from/\@FEXYOURSELF") { @to = ($from); $nomail = 'fexyourself'; } # ask for recipient address(es) elsif ($from and $id and $id eq $rid and ($addto or not $submit or not @to) and not ($gkey or $skey or $okey or $public or $anonymous)) { present_locales('/fup'); # print "[$addto] [$submit] [@to]

\n"; @ab = (""); # select menu from server address book if (open my $AB,'<',"$from/\@ADDRESS_BOOK") { while (<$AB>) { s/#.*//g; if (/(\S+)[=\s]+(\S+@[\w.-]+\S*)/) { $_ = "$1 <$2>"; s/,.*/,.../g; s/:.*/>/; push @ab,""; } } close $AB; } unless (@to) { unless ($nomail) { foreach (glob "$from/\@GROUP/*") { if (-f and not -l) { s:.*/::; push @ab,"" unless /~$/; } } } } my $ab64 = b64("from=$from&id=$id"); # '

' ' ' ' ' ' ' ' ' ' ' '
sender: $from
recipient(s):' '
' )); if (grep /@/,@ab) { pq(qq( ' or select from your address book:' ' ' ' and' ' ' )); } pq(qq( '
' '

' )); my $rr = "$from/\@ALLOWED_RECIPIENTS"; if (-s $rr and open $rr,'<',$rr) { pq(qq( 'You are a restricted user and may only fex to these recipients:

' '

'
      ));
      while (<$rr>) {
        chomp;
        s/#.*//;
        s/\s//g;
        next unless $_;
        if (/^\@LOCAL_RDOMAINS/) {
          foreach my $rd (@local_rdomains) {
            print "*\@$rd\n";
          }
        } elsif (/^\@LOCAL_USERS/) {
          foreach (glob "*/@") {
            s:/.::;
            print "$_\n";
          }
        } else {
          print "$_\n";
        }
      }
      print "

\n"; close $rr; } print qq' '; if ($fex_yourself =~ /^yes|1/i) { print qq' or ' } print "\n

\n

\n"; if ($akey and -f "$from/\@" and not $captive ) { pq(qq( 'user config & operation control' )); } if ($from eq $admin ) { pq(qq( '

' 'server config & admin control' )); } if (0 and -f "$docdir/FIX.jar") { print "

\n"; if ($public) { print "" } elsif ($skey) { print "" } elsif ($gkey) { print "" } else { print "" } print "Alternate Java client (for files > 2 GB or sending of more than one file)\n"; } print &logout; pq(qq( '


' '' '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,' '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; } # ask for filename 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( '' )); pq(qq( '

' ' ' ' ' ' ' )); if ($public) { my $toh = join('
',@to); pq(qq( ' ' ' ' ' ' ' ' ' ' )); } elsif ($okey) { pq(qq( ' ' ' ' '
sender: $from
recipient:$toh
' ' ' ' ' )); } elsif ($skey) { pq(qq( ' ' '
sender: $from
recipient:$to
' ' ' ' ' )); } elsif (@group) { if ($gkey) { pq(qq( ' ' )); } my $toh = "group $group:
    "; my $toc = join(',',@group); foreach my $gm (@group) { $toh .= "
  • $gm" } $toh .= "
"; pq(qq( ' ' '
sender: $from
recipient:$to
' ' ' ' ' )); } else { my $toc = join(',',@to); my $toh = join('
',@to); pq(qq( ' ' '
sender:$from
recipient(s):' ' $toh
' ' ' )); if ($anonymous) { pq(qq( ' ' )); } else { pq(qq( ' ' )); } } $autodelete = lc $autodelete; $keep = $keep_default unless $keep; my ($quota,$du) = check_sender_quota($muser||$from); $quota = $quota ? "" : ''; $bwl = qq' kB/s'; if (@throttle) { foreach (@throttle) { if (/\[?(.+?)\]?:(\d+)$/) { my $throttle = $1; my $limit = $2; # throttle ip address? if ($throttle =~ /^[\w:.-]+$/) { if (ipin($ra,$throttle)) { $bwl = qq' $limit kB/s'; last; } } # throttle e-mail address? else { # allow wildcard *, but not regexps $throttle =~ quotemeta $throttle; $throttle =~ s/\*/.*/g; if ($from =~ /^$throttle$/i) { $bwl = qq' $limit kB/s'; last; } } } } } $autodelete = $autodelete{$to} if $autodelete{$to}; my $adt = ''; for ($autodelete) { if (/yes/i) { $adt = 'delete file after download' } elsif (/no/i) { $adt = 'do not delete file after download' } elsif (/delay/i) { $adt = 'delete file after download with delay' } elsif (/^\d+$/) { $adt = "delete file $autodelete days after download" } } $adt .= qq''; my $ctr = my $ktr = ''; if ($nomail) { $ctr = qq'no notification e-mail will be send'; } else { $ctr = qq''; } if ($captive) { $ktr = qq'$keep days'; } else { $ktr = qq'$keep days'; } pq(qq( ' ' ' ' ' $quota' ' ' ' ' ' ' ' ' '
sender:$from
recipient:' ' $toh
recipient(s):' ' $toh
sender quota (used):$quota ($du) MB
autodelete:' ' $adt' '
keep:' ' $ktr' '
bandwith limit:' ' $bwl' '
comment:' ' $ctr' '
file:' ' ' '
file size:
' '

' ' '

' '

' )); if ($akey and -f "$from/\@" and not $captive) { print "

\n", "user config & operation control\n"; } if ($from eq $admin ) { pq(qq( '

' 'server config & admin control' )); } if (0 and -f "$docdir/FIX.jar" and not $okey) { print "

\n"; if ($public) { print "" } elsif ($skey) { print "" } elsif ($gkey) { print "" } else { print "" } print "Alternate Java client (for files > 2 GB or sending of more than one file)\n"; } print &logout; print $info_2; # printf "


%s
\n",$ENV{HTTP_HEADER}; print "\n"; exit; } present_locales('/fup'); if ($ENV{REQUEST_METHOD} eq 'POST') { pq(qq( '

' ' You have to fill out this form completely to continue.' '

' )); } pq(qq( '
' ' ' ' ' ' ' '
sender:' '
auth-ID:' '
' )); if ($mail_authid and not ($fop_auth or $nomail)) { # pq(qq( # 'If you enter "?" as your auth-ID then it will be sent by e-mail to you.' # '

' # )); pq(qq( ' ' ' I have lost my auth-ID! Send it to me by e-mail! ' ' (you must fill out sender field above)' )); } pq(qq( '

' )); if (not $nomail and ( @local_domains and @local_hosts or @local_rdomains and @local_rhosts or @demo )) { pq(qq( 'You can register yourself ' 'if you do not have a F*EX account yet.

' )); } if (@anonymous_upload and ipin($ra,@anonymous_upload)) { my $a = 'anonymous_'.int(rand(999999)); pq(qq( 'You may also use anonymous upload' )); } # if (-f "$docdir/sup.html") { # pq(qq( # '
' # 'You may also use simple upload' # )); # } print "

\n"; print $info_login||$info_1; if ($debug and $debug>1) { print "
\n
\n";
    foreach $v (sort keys %ENV) {
      print "$v = $ENV{$v}\n";
    }
    print "
\n"; } print "\n"; exit; } # from sup.html if ($from and $file and not @to) { check_rr($from,$from); @to = ($from); $sup = 'fexyourself'; $keep{$from} = readlink("$from/\@KEEP")||$keep_default; } # all these variables should be defined here, but just to be sure... http_die("no file specified") unless $file; http_die("no sender specified") unless $from; http_die("no recipient specified") unless @to; unless ($okey and -l "$to/\@OKEY/$okey") { http_die("no auth-ID specified") unless $id; unless ($rid eq $id or $gkey or $skey) { faillog("user $from, id $id"); http_die("wrong auth-ID specified"); } } &check_status($from); if (@throttle) { foreach (@throttle) { if (/(.+):(\d+)$/) { my $throttle = $1; my $limit = $2; if (not $bwlimit or $limit < $bwlimit) { # throttle ip address? if ($throttle =~ /^[\d.-]+$/) { if (ipin($ra,$throttle)) { $bwlimit = $limit; last; } } # throttle e-mail address? else { # allow wildcard *, but not regexps $throttle =~ quotemeta $throttle; $throttle =~ s/\*/.*/g; if ($from =~ /^$throttle$/i) { $bwlimit = $limit; last; } } } } } } # address rewriting for storage (swap sender and recipient), see also fop! if (not ($skey or $gkey) and $from =~ /^(anonymous|fexmail)/) { ($from,@to) = ("@to",$from); } if (not $anonymous and $overwrite =~ /^n/i) { foreach $to (@to) { if (-f "$to/$from/$fkey/data") { http_die("$file already exists for $to"); } } } # additional last check unless (@group or $gkey or $skey or $public or $okey) { foreach $to (@to) { checkaddress($to) or http_die("$to is not a valid e-mail address"); } } $to = join(',',@to); # file overwriting for anonymous is only possible if his client has the # download cookie - else request purging if ($anonymous and not $seek and my $dkey = readlink "$to/$from/$fkey/dkey") { if ($overwrite =~ /^n/i) { http_die("$file already exists for $to"); } if ($ENV{HTTP_COOKIE} !~ /$dkey/) { my $purge = "/fop/$dkey/$dkey?purge"; # http_die("$file already exists $dkey:$ENV{HTTP_COOKIE}:"); http_die("$file already exists - purge it?!"); } } if (@group) { @to = @group; $comment = "[$group] $comment"; } elsif ($public) { $comment .= ' (public upload)'; } # file data still waits on STDIN ... get it now! &get_file; if ($to eq $from and $file eq 'ADDRESS_BOOK') { unlink "$from/\@ADDRESS_BOOK"; rename "$from/$from/ADDRESS_BOOK/upload","$from/\@ADDRESS_BOOK" or http_die("cannot save $from/\@ADDRESS_BOOK - $!\n"); http_header('200 OK'); print html_header($head); print "address book updated", "\n"; exit; } # finalize upload unless ($nostore) { foreach (@group?@group:@to) { my $to = $_; $to =~ s/:\w+=.*//; # remove options from address $filed = "$to/$from/$fkey"; $save = "$filed/data"; $upload = "$filed/upload"; $download = "$filed/download"; $dkey{$to} = readlink "$filed/dkey"; $overwrite{$to}++ if -f $save and not -f $download; unlink $save,$download; rename $upload,$save or http_die("cannot rename $upload to $save - $!\n"); # log dkey 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 and ($comment or not $overwrite{$to})) { notify_locale($dkey{$to},'new'); debuglog("notify $filed [$filename] '$comment'"); } } } # send HTTP status $HTTP_HEADER = 'HTTP/1.1 200 OK'; if ($nostore) { nvt_print($HTTP_HEADER,'Content-Type: text/html',''); exit if $http_client =~ /^fexsend/; } elsif ($file eq 'STDFEX') { nvt_print($HTTP_HEADER,''); exit; } else { nvt_print($HTTP_HEADER); if ($xkey and not $restricted) { my $x = "$durl//$xkey"; $x =~ s:/fop::; nvt_print("X-Location: $x"); } if ($anonymous) { my $dkey = $dkey{$to}; my $cookie = $dkey; $cookie = $1 if $ENV{HTTP_COOKIE} =~ /anonymous=([\w:]+)/; $cookie .= ':'.$dkey if $cookie !~ /$dkey/; nvt_print("Set-Cookie: anonymous=$cookie"); $keep{$to} = readlink("$to/\@KEEP")||$keep_default; } foreach (@group?@group:@to) { 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)", readlink("$file/autodelete")||$autodelete, readlink("$file/keep")||readlink("$to/\@KEEP")||$keep_default, 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; } if ($http_client =~ /^(fexsend|schwuppdiwupp)/) { nvt_print(''); exit; } else { nvt_print('Content-Type: text/html',''); } } # send HTML report print html_header($head); if ($nostore) { 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*$MB ? sprintf "%s kB",int($ndata/1024): sprintf "%s MB",int($ndata/$MB); pq(qq( '$file ($size) received and saved

' 'Download URL for copy & paste:' '

$durl/$dkey{$to}/$fkey

' 'Link is valid for $keep{$to} days!

' )); } else { if ($ndata<2*1024) { print "$file ($ndata B) received and saved

\n"; if (not $boring and not $seek) { print "Ehh... $ndata BYTES?! You are kidding?

\n"; } } elsif ($ndata<2*$MB) { $ndata = int($ndata/1024); print "$file ($ndata kB) received and saved

\n"; if ($ndata<1024 and not ($boring or $seek)) { print "Using F*EX for less than 1 MB: ", "ever heard of MIME e-mail? ☺

\n"; } } else { $ndata = int($ndata/$MB); print "$file ($ndata MB) received and saved

\n"; } print "

    \n"; foreach $to (@to) { print "
  • "; if ($nomail or $nomail{$to}) { if ($restricted) { rmrf("$to/$from/$fkey"); print "$file removed because you are a restricted user ". "and recipient $to cannot receive e-mail

    \n"; } else { pq(qq( '$to cannot receive e-mail →' '

    ' ' No notification e-mail has been sent to $to!' '

    ' 'Download URL for copy & paste:' )); if ($xkey) { my $x = "$durl{$to}//$xkey"; $x =~ s:/fop::; print "

    $x

    \n"; } else { print "

    $durl/$dkey{$to}/$fkey

    \n"; print "Link is valid for $keep{$to} days!

    \n"; } } } elsif ($overwrite{$to} and not $comment) { print "(old $file for $to overwritten)

    \n" } else { print "$to notified

    \n" } } print "

\n"; } if ($okey) { unlink "$to/\@OKEY/$okey"; } elsif (not $anonymous and not $sup) { print ""; print "send another file\n"; if ($http_client !~ /fexsend/ and $http_client =~ /Linux/i) { 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; } print "\n"; exit; # parse GET and POST requests sub parse_request { my %to; my ($to,$dkey); my ($x,$k,$v); my $qs = $ENV{QUERY_STRING}; local $_; # get JUP parameters from environment (HTTP headers) while (($k,$v) = each %ENV) { if ($k =~ s/^FEX_//) { setparam($k,$v); } } # decode base64 PATH_INFO to QUERY_STRING if ($ENV{PATH_INFO} =~ m:^/(\w+=*)$:) { if ($qs) { $qs = sprintf("%s&%s",decode_b64($1),$qs); } else { $qs = decode_b64($1); } } # parse HTTP QUERY_STRING (parameter=value pairs) if ($qs) { foreach (split '&',$qs) { if (s/^(\w+)=(.*)//) { my $p = uc($1); my $v = $2; # decode URL-encoding $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; # } } } } # HTTP redirect does not work correctly with opera! # ==> locale handling is now done by fexsrv if (0 and $locale) { nvt_print( "HTTP/1.1 302 Found", "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/fup", "Set-Cookie: locale=$locale", 'Expires: 0', 'Content-Length: 0', '' ); &reexec; } if ($showstatus) { &showstatus; exit; } # check for akey, gkey and skey (from HTTP GET) &check_keys; if ($ENV{REQUEST_METHOD} eq 'POST' and $cl) { foreach $sig (keys %SIG) { if ($sig !~ /^(CHLD|CLD)$/) { $SIG{$sig} = \&sigexit; } } $SIG{PIPE} = 'IGNORE' if $ENV{PROTO} eq 'https'; # stunnel workaround $SIG{__DIE__} = \&sigdie; http_die("invalid Content-Length header \"$cl\"") if $cl !~ /^-?\d+$/; debuglog($0); debuglog(sprintf("awaiting %d bytes from %s %s", $cl,$ENV{REMOTE_ADDR}||'',$ENV{REMOTE_HOST}||''),"\n"); &check_space($cl) if $cl > 0; $SIG{ALRM} = sub { $SIG{__DIE__} = 'DEFAULT'; die "TIMEOUT\n"; }; alarm($timeout); binmode(STDIN,':raw'); if (defined($ENV{FEX_FILENAME})) { # JUP via HTTP header $file = $param{'FILE'} = $ENV{FEX_FILENAME}; $fileid = $ENV{FEX_FILEID} || 0; $fpsize = $ENV{X_CONTENT_LENGTH} || 0; $boundary = ''; } elsif ($contentlength) { # JUP via URL parameter $fpsize = $contentlength; $boundary = ''; } else { # FUP if ($ENV{CONTENT_TYPE} =~ /boundary=\"?([\w\-\+\/_]+)/) { $boundary = $1; } else { http_die("malformed HTTP POST (no boundary found)"); } READPOST: while (&nvt_read) { # the file itself - *must* be last part of POST! if (/^Content-Disposition:\s*form-data;\s*name="file";\s*filename="(.+)"/i) { push @header,$_; $file = $param{'FILE'} = $1; while (&nvt_read) { last if /^\s*$/; $fileid = $1 if /^X-File-ID:\s*(.+)/; $fpsize = $1 if /^Content-Length:\s*(\d+)/; $flink = $1 if /^Content-Location:\s*(\/.+)/; push @header,$_; } # STDIN is now at begin of file, will be read later with get_file() last; } # all other parameters if (/^Content-Disposition:\s*form-data;\s*name="([a-z]\w*)"/i) { my $x = $1; nvt_skip_to('^\s*$'); &nvt_read; setparam($x,$_); NEXTPART: while (&nvt_read) { last READPOST if /^--\Q$boundary--/; last NEXTPART if /^--\Q$boundary/; } } } } if (length($file)) { $file =~ s/%(\d+)/chr($1)/ge; $file = untaint(strip_path(normalize($file))); $file =~ s/[\\\/<>]/_/g; # filter out dangerous chars $file =~ s/^\|//; # filter out dangerous chars $file =~ s/\|$//; # filter out dangerous chars $filename = $file; $fkey = urlencode($file); } # check for akey, gkey and skey (from HTTP POST) &check_keys; } if ($from) { unless ($skey or $gkey or $okey) { $from .= '@'.$mdomain if $mdomain and $from !~ /@/; if ($from ne 'anonymous' and not checkaddress($from)) { http_die("$from is not a valid e-mail address"); } } $from = untaint($from); } # collect multiple addresses and check for aliases (not group) if (@to and "@to" !~ /^@[\w-]+$/ and not ($gkey or $addto or $command =~ /^LIST(RECEIVED)?$/)) { # read address book if ($from and open my $AB,'<',"$from/\@ADDRESS_BOOK") { my ($alias,$addresses,$autodelete,$locale,$keep); while (<$AB>) { s/#.*//; $_ = lc $_; if (s/^\s*(\S+)[=\s]+(\S+)//) { ($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(",",$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 if $autodelete; $keep{$alias} = $keep if $keep; $locale{$alias} = $locale if $locale; } } } close $AB; } # look for recipient's options and eliminate dupes %to = (); foreach my $to (my @loop = @to) { # 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 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} } } 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}) { 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'; } } } 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} = 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} = 'NO' if $to =~ /$amdl/; # mailing lists, etc if (-e "$to/\@CAPTIVE") { my $v; $v = readlink "$to/\@AUTODELETE" and $autodelete{$to} = $v; $v = readlink "$to/\@KEEP" and $keep{$to} = $v; } } @to = keys %to; if (scalar(@to) == 1) { $to = "@to"; $keep = $keep{$to} if $keep{$to}; $autodelete = $autodelete{$to} if $autodelete{$to}; } # check recipients and eliminate dupes %to = (); foreach $to (@to) { if ($to eq 'anonymous') { $to{$to} = $to; } else { if ($to =~ /^@(.+)/) { http_die("You cannot send to more than one group") if @to > 1; http_die("Group $to does not exist") unless -f "$from/\@GROUP/$1"; } else { if ($skey or $gkey or $okey or checkaddress($to)) { $to .= '@'.$mdomain if $mdomain and $to !~ /@/; $to{$to} = untaint($to); } else { http_die("$to is not a valid e-mail address"); } } } } @to = values %to; } foreach $to (@to) { unless (checkforbidden($to)) { http_die("$to is not allowed"); } } } # show the status progress bar sub showstatus { my $wclose; my ($upload,$data,$sfile,$ukey,$file); my ($nsize,$tsize); my ($t0,$t1,$t2,$tt,$ts,$tm); my ($osize,$percent,$npercent); local $_; $wclose = '

close'."\n". ''."\n"; $ukey = "$ukeydir/$uid"; $upload = "$ukey/upload"; $data = "$ukey/data"; $sfile = "$ukey/size"; for (1..$timeout) { sleep 1; $tsize = readlink $sfile and last; # upload error? # remark: stupid Internet Explorer *needs* the error represented in this # asynchronous popup window, because it cannot display the error in the # main window on HTTP POST! if (-f $ukey and open $ukey,'<',$ukey or -f "$ukey/error" and open $ukey,'<',"$ukey/error") { undef $/; unlink $ukey; html_error($error,<$ukey> || 'unknown'); } } # unlink $sfile; if (defined $tsize and $tsize == 0) { print "\n"; exit; } unless ($tsize) { html_error($error, "no file data received - does your file exist or is it >2GB?") } html_error($error,"file size unknown") unless $tsize =~ /^\d+$/; http_header('200 OK'); if (open $ukey,'<',"$ukey/filename") { local $/; $file = <$ukey>; close $ukey; } http_die("no filename?!") unless $file; my $ssize = $tsize; if ($ssize<2097152) { $ssize = sprintf "%d kB",int($ssize/1024); } else { $ssize = sprintf "%d MB",int($ssize/1048576); } pq(qq( "" "

" "

Upload Status for
$file ($ssize)

" '' "
" "" "
" "
" "
" )); # wait for upload file for (1..9) { last if -f $upload or -f $data; sleep 1; } unless (-f $upload or -f $data) { print "

ERROR: no upload received

\n"; print $wclose; exit; } $SIG{ALRM} = sub { $SIG{__DIE__} = 'DEFAULT'; die "TIMEOUT in showstatus: no (more) data received\n"; }; alarm($timeout*2); $t0 = $t1 = time; $osize = $percent = $npercent = 0; for ($percent = 0; $percent<100; sleep(1)) { $t2 = time; $nsize = -s $upload; if (defined $nsize) { if ($nsize<$osize) { print "

ABORTED

\n"; print $wclose; exit; } if ($nsize>$osize) { alarm($timeout*2); $osize = $nsize; } $npercent = int($nsize*100/$tsize); $showsize = calcsize($tsize,$nsize); } else { $npercent = 100; $showsize = calcsize($tsize,$tsize); } # hint: for ISDN (or even slower) links, 5 s tcp delay is minimum # so, updating more often is contra-productive if ($t2>$t1+5 or $npercent>$percent) { $percent = $npercent; $t1 = $t2; $tm = int(($t2-$t0)/60); $ts = $t2-$t0-$tm*60; $tt = sprintf("%d:%02d",$tm,$ts); pq(qq( "" )) or last; } } alarm(0); if ($npercent == 100) { print "

file successfully transferred

\n"; } else { print "

file transfer aborted

\n"; } pq(qq( "" )); print $wclose; unlink $ukey; exit; } # get file from post request sub get_file { my ($to,$filed,$upload,$nupload,$speed,$download); my ($b,$n,$uss); my $dkey; my ($fh,$filesize); my ($t0,$tt); my $fb = 0; # file bytes my $ebl = 0; # end boundary length # FUP, not JUP if ($boundary) { $ebl = length($boundary)+8; # 8: 2 * CRLF + 2 * "--" } unless ($nostore) { # download already in progress? foreach $to (@to) { $to =~ s/:\w+=.*//; # remove options from address $filed = "$to/$from/$fkey"; $download = "$filed/download"; if (-f $download and open $download,'>>',$download) { flock($download,LOCK_EX|LOCK_NB) or http_die("$filed locked: a download is currently in progress"); } } # prepare upload foreach $to (@to) { $to =~ s/:\w+=.*//; # remove options from address $filed = "$to/$from/$fkey"; $nupload = "$filed/upload"; # upload for next recipient mkdirp($filed); # upload already prepared (for first recipient)? if ($upload) { # link upload for next recipient unless ($upload eq $nupload or -r $upload and -r $nupload and (stat $upload)[1] == (stat $nupload)[1]) { unlink $nupload; link $upload,$nupload; } } # first recipient => create upload else { $upload = $nupload; unlink "$ukeydir/$uid"; if ($flink) { if ($seek) { http_die("cannot resume on link upload"); } &nvt_read and $flink = $_; if ($flink !~ /^\//) { http_die("no file link name ($flink)"); } $flink = abs_path($flink); my $fok; foreach (@file_link_dirs) { my $dir = abs_path($_); $fok = $flink if $flink =~ /^\Q$dir\//; } unless ($fok) { http_die("$flink not allowed for linking"); } my @s = stat($flink); unless (@s and ($s[2] & S_IROTH) and -r $flink) { http_die("cannot read $flink"); } unless (-f $flink and not -l $flink) { http_die("$flink is not a regular file"); } # http_die("DEBUG: flink = $flink"); &nvt_read; &nvt_read if /^$/; unless (/^--\Q$boundary--/) { http_die("found no MIME end boundary in upload ($_)"); } unlink $upload; symlink untaint($flink),$upload; } else { unlink $upload if -l $upload; open $upload,'>>',$upload or http_die("cannot write $upload - $!"); flock($upload,LOCK_EX|LOCK_NB) or http_die("$file locked: a transfer is already in progress"); unless ($seek) { seek $upload,0,0; truncate $upload,0; } # already uploaded file data size $uss = -s $upload; # provide upload ID symlink for showstatus symlink "../$filed","$ukeydir/$uid"; } } unlink "$filed/autodelete", "$filed/error", "$filed/restrictions", "$filed/locale", "$filed/keep", "$filed/header", "$filed/id", "$filed/ip", "$filed/speed", "$filed/replyto", "$filed/useragent", "$filed/uurl", "$filed/comment", "$filed/notify"; unlink "$filed/size" unless $seek; # showstatus needs file name and size # fexsend needs full file size (+$seek) $fh = "$filed/filename"; open $fh,'>',$fh or die "cannot write $fh - $!\n"; print {$fh} $filename; close $fh; if ($::filesize > 0 or $cl > 0) { if ($::filesize > 0) { $filesize = $fpsize || $::filesize } else { $filesize = $cl-$RB-$ebl+$seek } # new file unless ($seek) { if ($::filesize > 0) { # total file size as reported by POST mksymlink("$filed/size",$::filesize) or die "cannot write $filed/size - $!\n"; } else { # file size as counted mksymlink("$filed/size",$filesize) or die "cannot write $filed/size - $!\n"; } } } if ($from eq "@to") { # special "fex yourself" mksymlink("$filed/autodelete",$specific{'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/keep",$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 ($_ = readlink "$to/\@LOCALE") { # mksymlink("$filed/locale",$_); } elsif ($locale{$to}) { mksymlink("$filed/locale",$locale{$to}); } elsif ($locale and $locale ne $default_locale) { mksymlink("$filed/locale",$locale); } if ($replyto and $replyto =~ /.@./) { mksymlink("$filed/replyto",$replyto); } my $arh = "$from/\@ALLOWED_RHOSTS"; if (-s $arh) { copy($arh,"$filed/restrictions"); } if (@header and open $fh,'>',"$filed/header") { print {$fh} join("\n",@header),"\n"; close $fh; } if ((readlink "$to/\@NOTIFICATION"||'') =~ /^no/i) { $nomail{$to} = 'NOTIFICATION'; } if ($nomail) { open $fh,'>',"$filed/notify" and close $fh; } if ($comment) { if (open $fh,'>',"$filed/comment") { print {$fh} encode_utf8($comment); close $fh; } } # provide download ID key unless ($dkey = readlink("$filed/dkey") and -l "$dkeydir/$dkey") { $dkey = randstring(8); unlink "$dkeydir/$dkey"; symlink "../$filed","$dkeydir/$dkey" or http_die("cannot symlink $dkeydir/$dkey ($!)"); unlink "$filed/dkey"; symlink $dkey,"$filed/dkey"; } } # extra download (XKEY)? if ($anonymous and $fkey =~ /^afex_\d/ or $from eq "@to" and $comment =~ s:^//(.*)$:NOMAIL:) { $xkey = $1||$fkey; $nomail = $comment; my $x = "$xkeydir/$xkey"; unless (-l $x and readlink($x) eq "../$from/$from/$fkey") { if (-e $x) { http_die("extra download key $xkey already exists"); } symlink "../$from/$from/$fkey",$x or http_die("cannot symlink $x - $!\n"); unlink "$x/xkey"; symlink $xkey,"$x/xkey"; } } } # file link? if ($flink) { # upload link has been already created, no data to read any more $to = join(',',@to); fuplog($to,$fkey,0); debuglog("upload link successfull, dkey=$dkey"); } # regular file else { # at last, read (real) file data $t0 = time(); # streaming data? 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; $fb += $n; syswrite $upload,$_ unless $nostore; alarm($timeout*2); } # size of transferred file, without end boundary $ndata = untaint($fb-$ebl); } # normal file with known file size else { if ($fpsize) { debuglog(sprintf("still awaiting %d+%d = %d bytes", $fpsize,$ebl,$fpsize+$ebl)); $cl = $RB+$fpsize+$ebl; # recalculate CONTENT_LENGTH } else { if ($::filesize) { $cl = $RB+$::filesize+$ebl; # recalculate CONTENT_LENGTH } debuglog(sprintf("still awaiting %d-%d = %d bytes", $cl,$RB,$cl-$RB)); } # read until end boundary, not EOF 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; $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) { sleep 1; $tt = time-$t0; } } # debuglog($_); } else { last; } } # read end boundary - F*IX is broken! if ($ebl and $http_client !~ /F\*IX/) { $_ = ; $_ = ||''; unless (/^--\Q$boundary--/) { http_die("found no MIME end boundary in upload ($_)"); } } $RB += $ebl; $ndata = untaint($fb); } alarm(0); unless ($nostore) { close $upload; # or die "cannot close $upload - $!\n";; # throuput in kB/s $tt = (time-$t0) || 1; mksymlink("$filed/speed",int($fb/1024/$tt)); unless ($ndata) { http_die( "No file data received!". " File name correct?". " File too big (browser-limit: 2 GB!)?" ); } $to = join(',',@to); # streaming upload? if ($cl == -1) { open $upload,'<',$upload or http_die("internal error - cannot read upload"); seek $upload,$ndata+2,0; $_ = <$upload>||''; unless (/^--\Q$boundary--/) { http_die("found no MIME end boundary in upload ($_)"); } close $upload; truncate $upload,$ndata; } else { # truncate boundary string # truncate $upload,$ndata+$uss if -s $upload > $ndata+$uss; # incomplete? if ($cl != $RB) { fuplog($to,$fkey,$ndata,'(aborted)'); if ($fpsize) { http_die("read $RB bytes, but Content-Length announces $fpsize bytes"); } else { http_die("read $RB bytes, but CONTENT_LENGTH announces $cl bytes"); } } # multipost, not complete if ($::filesize > -s $upload) { http_header('206 Partial OK'); exit; } # save error? if (-s $upload > ($::filesize||$filesize)) { fuplog($to,$fkey,$ndata,'(write error: upload > filesize)'); http_die("internal server error while writing file data"); } } fuplog($to,$fkey,$ndata); debuglog("upload successfull, dkey=$dkey"); } } } # check recipients restriction sub check_rr { my $from = shift; my @to = @_; my $rr = "$from/\@ALLOWED_RECIPIENTS"; my ($allowed,$to,$ar,$rd); if (-s $rr and open $rr,'<',$rr) { $restricted = $rr; foreach (@to) { my $to = $_; $allowed = 0; seek $rr,0,0; while (<$rr>) { chomp; s/#.*//; s/\s//g; if (/^\@LOCAL_RDOMAINS/) { $ar = '(@'; foreach (@local_rdomains) { my $rd = $_; # allow wildcard *, but not regexps $rd =~ s/\./\\./g; $rd =~ s/\*/[\\w.-]+/g; $ar .= '|[^\@]+\@' . $rd; } $ar .= ')'; } elsif (/^\@LOCAL_USERS/ and -s "$to/@") { $allowed = 1; last; } else { # allow wildcard *, but not regexps $ar = quotemeta $_; $ar =~ s/\\\*/[^@]*/g; } if ($to =~ /^$ar$/i) { $allowed = 1; last; } } unless ($allowed) { fuplog("ERROR: $from not allowed to fex to $to"); debuglog("$to not in $spooldir/$from/\@ALLOWED_RECIPIENTS"); http_die("You ($from) are not allowed to fex to $to"); } } close $rr; } } # add domain to user if necessary sub expand { my @users = @_; my @ua; foreach my $u (my @loop = @users) { if ($u =~ /^anonymous(_\d+)?$/) { $u = "$u\@$hostname"; } if ($u eq 'nettest') { if ($mdomain and -d "$u\@$mdomain") { $u .= "\@$mdomain" } elsif (-d "$u\@$hostname") { $u .= "\@$hostname" } } if ($u =~ /@/) { push @ua,$u } elsif ($mdomain) { push @ua,"$u\@$mdomain" } elsif (-d "$u\@$hostname") { push @ua,"$u\@$hostname" } else { push @ua,$u } } return wantarray ? @ua : join(',',@ua); } # forward-copy (bounce) an already uploaded file sub forward { my $file = shift; my ($nfile,$to,$AB); 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 check_rr($from,@to); # read aliases from address book if (open $AB,'<',"$from/\@ADDRESS_BOOK") { while (<$AB>) { s/#.*//; $_ = lc $_; if (s/^\s*(\S+)[=\s]+(\S+)//) { my ($alias,$address) = ($1,$2); foreach my $address (split(",",$address)) { $address .= '@'.$mdomain if $mdomain and $address !~ /@/; push @{$ab{$alias}},$address; } } } close $AB; } # collect addresses foreach my $to (my @loop = @to) { if ($ab{$to}) { foreach my $address (@{$ab{$to}}) { $to{$address} = $address; } } else { $to .= '@'.$mdomain if $mdomain and $to !~ /@/; $to{$to} = $to; } } @to = keys %to; http_header('200 OK'); print html_header($head); foreach my $to (my @loop = @to) { $to =~ s/:\w+=.*//; # remove options from address $nfile = $file; $nfile =~ s:.*?/:$to/:; next if $nfile eq $file; mkdirp($nfile); http_die("cannot create directory $nfile") unless -d $nfile; unlink "$nfile/data", "$nfile/upload", "$nfile/download", "$nfile/autodelete", "$nfile/error", "$nfile/restrictions", "$nfile/keep", "$nfile/header", "$nfile/id", "$nfile/speed", "$nfile/comment", "$nfile/replyto", "$nfile/notify"; if ($comment) { open $comment,'>',"$nfile/comment"; print {$comment} $comment; close $comment; } if ($autodelete =~ /^(DELAY|NO|\d+)$/i) { 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); unlink "$dkeydir/$dkey"; symlink "../$nfile","$dkeydir/$dkey" or http_die("cannot symlink $dkeydir/$dkey"); unlink "$nfile/dkey"; symlink $dkey,"$nfile/dkey" or http_die("cannot create $nfile/dkey - $!"); } if ($nomail or $nomail{$to}) { if ($filename) { my $url = "$durl/$dkey/".normalize_filename($filename); pq(qq( 'Download-URL for $to:
' '$url' '

' )); } } else { notify_locale($dkey,'new'); fuplog($to,urlencode($filename),"(forwarded)"); if ($filename) { pq(qq( 'File "$filename" copy-forwarded to $to and notified.' '

' )); } } } pq(qq( 'back to F*EX operation control' '' )); } else { $filename = filename($file); http_header('200 OK'); print html_header($head); pq(qq( '

' ' ' ' ' ' ' ' forward a copy of "$filename" to:
' ' ' '
' '' )); } } # modify file parameter sub modify { my $file = shift; my $filename = filename($file); my $dkey = readlink "$file/$dkey"; my $to; my @parameter; http_die("no file data for $file") unless -f "$file/data"; $to = $file; $to =~ s:/.*::; if ($specific{'keep'}) { mksymlink("$file/keep",$keep); utime time,time,"$file/filename"; push @parameter,'KEEP'; } if ($specific{'autodelete'}) { mksymlink("$file/autodelete",$autodelete); push @parameter,'AUTODELETE'; } if ($comment) { if (open $comment,'>',"$file/comment") { print {$comment} $comment; close $comment; } notify_locale($dkey,'new'); push @parameter,'COMMENT'; } http_header('200 OK'); print "Parameter ".join(',',@parameter)." modified for $filename for $to\n"; } sub calcsize { my ($tsize,$nsize) = @_; if ($tsize<2097152) { return sprintf "%d kB",int($nsize/1024); } else { return sprintf "%d MB",int($nsize/1048576); } } # set parameter variables sub setparam { my ($v,$vv) = @_; my ($idf,$to); $v = uc(despace($v)); # if ($vv =~ /([<>])/) { # http_die(sprintf("\"&#%s;\" is not allowed in parameter $v",ord($1))); # } $param{$v} = $vv; if ($v eq 'LOGOUT') { $logout = $v; # skey and gkey are persistant! $akey = $1 if $ENV{QUERY_STRING} =~ /AKEY:(\w+)/i; unlink "$akeydir/$akey"; $login = $FEXHOME.'/cgi-bin/login'; if (-x $login) { $login = readlink $login || 'login'; nvt_print( "HTTP/1.1 302 Found", "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/$login", 'Content-Length: 0', "" ); } else { nvt_print( "HTTP/1.1 302 Found", "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/fup", 'Content-Length: 0', "" ); } &reexec; } elsif ($v eq 'LOCALE' and $vv =~ /^(\w+)$/) { $locale = $1; } elsif ($v eq 'REDIRECT' and $vv =~ /^([\w?=]+)$/) { $redirect = $1; } elsif ($v eq 'SKEY' and $vv =~ /^([\w:]+)/) { $skey = $1; $restricted = $v; } elsif ($v eq 'GKEY' and $vv =~ /^([\w:]+)/) { $gkey = $1 unless $nomail; $restricted = $v; } elsif ($v eq 'DKEY' and $vv =~ /^(\w+)/) { $dkey = $1; } elsif ($v eq 'AKEY' and $vv =~ /^(\w+)/) { $akey = $1; } elsif ($v eq 'FROM' or $v eq 'USER') { $from = normalize_email($vv); $from = untaint(expand($from)); checkchars('from address',$from); # 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); checkaddress($replyto) or http_die("REPLYTO $replyto is no legal e-mail address"); } elsif ($v eq 'ADDTO') { $vv =~ s/\s.*//; $addto = normalize_email($vv); } elsif ($v eq 'SUBMIT') { $submit = decode_utf8(normalize($vv)); } 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) { $specific{'autodelete'} = $autodelete = uc($1); } if ($vv =~ s/[\s,]+KEEP=(\d+)//i) { $keep = $1; $keep = $keep_max if $keep_max and $keep > $keep_max; $specific{'keep'} = $keep; } $to = normalize(lc($vv)); $to =~ s/[\n\s;,]+/,/g; 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 = '//'; } } checkchars('to address',$to); push @to,split(',',$to); } elsif ($v eq 'ID') { $id = despace($vv); checkchars('auth-ID',$id); } elsif ($v eq 'TCE') { $test = despace($vv); } elsif ($v eq 'OKEY' and $vv =~ /^(\w+)$/) { $okey = $1; $restricted = $v; } elsif ($v eq 'FILEID' and $vv =~ /^(\w+)$/) { $fileid = $1; } elsif ($v eq 'CONTENTLENGTH' and $vv =~ /^(\d+)$/) { $contentlength = $1; } elsif ($v eq 'FILE' or $v eq 'FILENAME') { $file = strip_path(normalize($vv)); } elsif ($v eq 'UID' and $vv =~ /^(\w+)$/) { $uid = $1; } elsif ($v eq 'ID_FORGOTTEN') { $id_forgotten = $vv; } elsif ($v eq 'SHOWSTATUS' and $vv =~ /^(\w+)$/) { $showstatus = $uid = $1; } elsif ($v eq 'COMMENT') { $comment = decode_utf8(normalize($vv)); $comment =~ s/^\s*!\.!/!SHORTMAIL!/; $comment =~ s/^!#!/!NOMAIL!/; $comment =~ s/^!-!/!NOSTORE!/; $nomail = $comment if $comment =~ /NOMAIL/; $nostore = $nomail = $comment if $comment =~ /NOSTORE/; $bcc .= " $from" if $comment =~ s/\s*!bcc!?\s*//i; # backward compatibility foreach my $cmd (qw( DELETE LIST CHECKQUOTA CHECKRECIPIENT RECEIVEDLOG SENDLOG FOPLOG FORWARD )) { $command = $comment if $comment eq $cmd } } elsif ($v eq 'COMMAND') { $command = normalize($vv); } elsif ($v eq 'BWLIMIT' and $vv =~ /^(\d+)$/) { $bwlimit = $1; } elsif ($v eq 'SEEK' and $vv =~ /^(\d+)$/) { $seek = $1; } elsif ($v eq 'FILESIZE' and $vv =~ /^(\d+)$/) { $filesize = $1; # complete filesize! &check_space($filesize-$seek); } elsif ($v eq 'AUTODELETE' and $vv =~ /^(\w+)$/) { $specific{'autodelete'} = $autodelete = uc($1); } elsif ($v eq 'KEEP' and $vv =~ /^(\d+)$/) { $keep = $1; $keep = $keep_max if $keep_max and $keep > $keep_max; $specific{'keep'} = $keep; } elsif ($v eq 'TIMEOUT' and $vv =~ /^(\d+)$/) { $specific{'timeout'} = $timeout = $1; } } sub id_forgotten { my ($id,$to,$subuser,$gm,$skey,$gkey,$url,$fup); return if $nomail; $fup = $durl; $fup =~ s:/fop:/fup:; # full user if (open $from,'<',"$from/\@") { $id = getline($from); close $from; } if ($id) { $url = "$fup/".b64("from=$from&id=$id"); mail_forgotten($from,qqq(qq( 'Your reqested F*EX auth-ID for $fup?from=$from is:' '$id' '' 'Or use:' '$url' ))); exit; } # sub user foreach my $skey (glob("$skeydir/*")) { if (-f $skey and open $skey,'<',$skey) { while (<$skey>) { $_ = lc; if (/^(\w+)=(.+)/) { $subuser = $2 if $1 eq 'from'; $to = $2 if $1 eq 'to'; } } close $skey; } if ($from and $to and $from eq $subuser) { $skey =~ s:.*/::; mail_forgotten($subuser,qqq(qq( 'Your reqested F*EX login is:' '' '$fup?skey=$skey' ))); exit; } } # group user foreach my $gkey (glob("$gkeydir/*")) { if (-f $gkey and open $gkey,'<',$gkey) { while (<$gkey>) { $_ = lc; if (/^(\w+)=(.+)/) { $gm = $2 if $1 eq 'from'; $to = $2 if $1 eq 'to'; } } close $gkey; } if ($gm and $to and $from eq $gm) { $gkey =~ s:.*/::; mail_forgotten($gm,qqq(qq( 'Your reqested F*EX login is:' '' '$fup?gkey=$gkey' ))); exit; } } http_die("$from is not a F*EX user on this server"); } sub mail_forgotten { my $user = shift; my @msg = @_; local *P; return if $nomail; open P,'|-',$sendmail,$user,$bcc or http_die("cannot start sendmail - $!\n"); pq(P,qq( 'From: $admin' 'To: $user' 'Subject: F*EX service $hostname' 'X-Mailer: F*EX' '' )); print P @msg; close P or http_die("cannot send mail - $!\n"); http_header('200 OK'); print html_header($head); print "

Mail has been sent to you ($from)

\n"; print "\n"; } # 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; if ($skey) { # encrypted SKEY? if ($skey =~ s/^MD5H:(.+)/$1/) { # search real SKEY foreach my $s (glob "$skeydir/*") { $s =~ s:.*/::; if ($skey eq md5_hex($s.$sid)) { $skey = $s; last; } } } if (open $skey,'<',"$skeydir/$skey") { $akey = $gkey = ''; while (<$skey>) { if (/^(\w+)=(.+)/) { $from = $2 if lc($1) eq 'from'; @to = ($muser = $2) if lc($1) eq 'to'; $rid = $id = $2 if lc($1) eq 'id'; } } close $skey; } else { # $skey = ''; http_die("invalid SKEY $skey"); } } if ($gkey) { # encrypted GKEY? if ($gkey =~ s/^MD5H:(.+)/$1/) { # search real GKEY foreach my $g (glob "$gkeydir/*") { $g =~ s:.*/::; if ($gkey eq md5_hex($g.$sid)) { $gkey = $g; last; } } } if (open $gkey,'<',"$gkeydir/$gkey") { $akey = $skey = ''; while (<$gkey>) { if (/^(\w+)=(.+)/) { $from = $2 if lc($1) eq 'from'; $to = $muser = $2 if lc($1) eq 'to'; $rid = $id = $2 if lc($1) eq 'id'; # $user = $2 if lc($1) eq 'user'; } } close $gkey; @to = ($to); } else { # $gkey = ''; http_die("invalid GKEY $gkey"); } } if ($akey and not $id) { my $idf; # sid is not set with web browser # akey with sid is set with schwuppdiwupp & co $idf = "$akeydir/$akey/@"; if (open $idf,'<',$idf and $id = getline($idf)) { close $idf; $from = readlink "$akeydir/$akey" or http_die("internal server error: no $akey symlink"); $from =~ s:.*/::; $from = untaint($from); if ($akey ne md5_hex("$from:$id")) { $from = $id = ''; } } else { $akey = ''; } } } # check if there is enough space on spool sub check_space { my $req = shift; my ($df,$free,$uprq); local *P; if (open $df,"df -k $spooldir|") { while (<$df>) { if (/^.+?\s+\d+\s+\d+\s+(\d+)/ and $req/1024 > $1) { $free = int($1/1024); $uprq = int($req/$MB); if (not $nomail and open P,"|$sendmail -t") { pq(P,qq( 'From: $admin' 'To: $admin' 'Subject: F*EX spool out of space' '' 'F*EX spool $spooldir on $ENV{SERVER_NAME} is out of space.' '' 'Current free space: $free MB' 'Upload request: $uprq MB' )); close P; } debuglog("aborting because not enough free space in spool ($free MB)"); http_die("not enough free space for this upload"); } } close $df; } } # global substitution as a function like in gawk sub gsub { local $_ = shift; my ($p,$r) = @_; s/$p/$r/g; return $_; } # standard log sub fuplog { my $msg = "@_"; $msg =~ s/\n/ /g; $msg =~ s/\s+$//; $msg = sprintf "%s [%s_%s] %s (%s) %s\n", isodate(time),$$,$ENV{REQUESTCOUNT},$from,$fra,$msg; writelog($log,$msg); } sub sigdie { local $_ = shift; chomp; sigexit('DIE',$_); } sub sigexit { my ($sig) = @_; my $msg; my $to = join(',',@to); $SIG{__DIE__} = 'DEFAULT'; foreach (keys %SIG) { $SIG{$_} = 'DEFAULT' } $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 ($sig eq 'DIE') { shift; die "$msg\n"; } else { die "SIGNAL $msg\n"; } } sub present_locales { my $url = shift; my @locales = @::locales; # from fex.ph my ($locale,$lang); if ($url =~ /\?/) { $url .= "&"; $url =~ s/locale=\w+&//g; } else { $url .= "?"; } if (@locales) { map { $_ = "$FEXHOME/locale/$_" } @locales; } else { @locales = glob "$FEXHOME/locale/*"; } if (@locales > 1) { print "

"; foreach my $locale (my @loop = @locales) { if (-x "$locale/cgi-bin/fup") { $lang = "$locale/lang.html"; $locale =~ s:.*/::; if (open $lang,'<',$lang and $lang = getline($lang)) { close $lang; } else { $lang = $locale; } print "$lang "; } } print "

\n"; } } sub check_camel { my ($logo,$camel); local $/; if (open $logo,"$docdir/logo.jpg") { $camel = md5_hex(<$logo>) eq 'ad8a95bba8dd1a61d70bd38611bc2059'; } if ($camel and open $logo,"$docdir/action-fex-camel.gif") { $camel = md5_hex(<$logo>) eq '1f3d7acc70377496f95c5adddaf4ca7b'; } http_die("Missing camel") unless $camel; } fex-20160919/cgi-bin/fop0000711000174700017470000007132212656114574012745 0ustar fexfex#!/usr/bin/perl -wT # F*EX CGI for download # # Author: Ulli Horlacher # BEGIN { ($ENV{PERLINIT}||'') =~ /(.+)/s and eval $1 } use utf8; use Fcntl qw':flock :seek'; use Cwd qw'abs_path'; use File::Basename; use IO::Handle; use Encode; # add fex lib ($FEXLIB) = $ENV{FEXLIB} =~ /(.+)/; die "$0: no $FEXLIB\n" unless -d $FEXLIB; our $error = 'F*EX download ERROR'; our $head = "$ENV{SERVER_NAME} F*EX download"; # import from fex.pp our ($spooldir,$tmpdir,@logdir,$skeydir,$dkeydir,$durl); our ($bs,$fop_auth,$timeout,$keep_default,$nowarning); our ($limited_download,$admin,$akey,$adlm,$amdl); our (@file_link_dirs); # load common code, local config : $HOME/lib/fex.ph require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n"; my $ra = $ENV{REMOTE_ADDR}||0; if (@download_hosts and not ipin($ra,@download_hosts)) { http_die( "Downloads from your host ($ra) are not allowed.", "Contact $ENV{SERVER_ADMIN} for details." ); } &check_maint; # call localized fop if available if ($0 !~ m{/locale/.*/fop} and my $lang = $ENV{HTTP_ACCEPT_LANGUAGE}) { if ($lang =~ /^de/ and $0 =~ m{(.*)/cgi-bin/fop}) { my $fop = "$1/locale/deutsch/cgi-bin/fop"; exec $fop if -x $fop; } } my $log = 'fop.log'; chdir $spooldir or die "$spooldir - $!\n"; my $http_client = $ENV{HTTP_USER_AGENT} || ''; $file = $ENV{PATH_INFO} || ''; http_die('no file name') unless $file; $file =~ s:%3F:/?/:g; # escape '?' for URL-decoding $file =~ s/%([\dA-F]{2})/unpack("a",pack("H2",$1))/ge; $file =~ s:/\?/:%3F:g; # deescape '?' $file =~ s:/\.\.:/__:g; $file =~ s:^/+::; $file = untaint($file); # secure mode with HTTP authorization? if ($fop_auth) { @http_auth = (); if ($ENV{HTTP_AUTHORIZATION} and $ENV{HTTP_AUTHORIZATION} =~ /Basic\s+(.+)/) { @http_auth = split(':',decode_b64($1)); } if (@http_auth != 2) { &require_auth; } &check_auth($file,@http_auth); } # download-URL-scheme /$dkey/$file ? if ($file =~ m:^([^/]+)/[^/]+$:) { $dkey = $1; if ($link = readlink("$dkeydir/$dkey")) { if ($link !~ s:^\.\./::) { http_die("internal error on dkey for $link"); } $file = untaint($link); } else { http_die("no such file $file"); } } else { # download-URL-scheme /$to/$from/$file $file =~ s/\?.*//; if ($ENV{REQUEST_METHOD} eq 'GET' and $file =~ m:.+/(.+)/.+:) { $from = lc $1; if (-s "$from/\@ALLOWED_RECIPIENTS") { http_die("$from is a restricted user"); } } # add mail-domain to addresses if necessary if ($mdomain and $file =~ s:(.+)/(.+)/(.+):$3:) { $to = lc $1; $from = lc $2; $to =~ s/[:,].*//; $to .= '@'.$hostname if $to eq 'anonymous'; $from .= '@'.$hostname if $from eq 'anonymous'; $to .= '@'.$mdomain if -d "$to\@$mdomain"; $from .= '@'.$mdomain if -d "$from\@$mdomain"; if ($ENV{REQUEST_METHOD} eq 'GET' and -s "$from/\@ALLOWED_RECIPIENTS") { http_die("$from is a restricted user"); } $file = "$to/$from/$file"; } } if ($file and $file =~ m:(.+)/(.+)/.+:) { $to = $1; $from = $2; # afex! if ($from =~ s/^(anonymous).*/$1/) { if (@anonymous_upload and ipin($ra,@anonymous_upload) or $dkey) { $anonymous = $from; } else { http_header('403 Forbidden'); print html_header($head), "You have no permission to request the URI $ENV{REQUEST_URI}\n", "\n"; exit; } } } else { http_die("unknown query format"); } $data = "$file/data"; # open $file,$file; print Digest::MD5->new->addfile($file)->hexdigest; # request with ?query-parameter ? if ($qs = $ENV{QUERY_STRING}) { http_die("\"$1\" is not allowed in URL") if $qs =~ /([<>\%\'\"])/; # workaround for broken F*IX $qs =~ s/&ID=skey:\w+//; # subuser with skey? if ($qs =~ s/&*SKEY=([\w:]+)//i) { $skey = $1; # encrypted skey? if ($skey =~ s/^MD5H:(.+)/$1/) { # lookup real skey foreach my $s (glob "$skeydir/*") { $s =~ s:.*/::; if ($skey eq md5_hex($s.$ENV{SID})) { $skey = $s; last; } } } if (open $skey,'<',"$skeydir/$skey") { $from = $to = ''; while (<$skey>) { $from = lc($1) if /^from=(.+)/; $to = lc($1) if /^to=(.+)/; } close $skey; if ($from and $to) { $file =~ s:.*/:$to/$from/:; } else { http_die("INTERNAL ERROR: missing data in $skeydir/$skey"); } } else { debuglog("SKEY=$skey"); http_die("wrong SKEY authentification"); } } # group member with gkey? if ($qs =~ s/&*GKEY=([\w:]+)//i) { $gkey = $1; # encrypted gkey? if ($gkey =~ s/^MD5H:(.+)/$1/) { # lookup real gkey foreach my $g (glob "$gkeydir/*") { $g =~ s:.*/::; if ($gkey eq md5_hex($g.$ENV{SID})) { $gkey = $g; last; } } } if (open $gkey,'<',"$gkeydir/$gkey") { $from = $to = ''; while (<$gkey>) { $from = lc($1) if /^from=(.+)/; $group = lc($1) if /^to=\@(.+)/; } close $gkey; if ($from and $group and open $group,'<',"$from/\@GROUP/$group") { while (<$group>) { s/#.*//; s/\s//g; if (/(.+):/) { my $to = $1; $file =~ s:.*/:$to/$from/:; last; } } close $group; } else { http_die("INTERNAL ERROR: missing data in $gkeydir/$gkey"); } } else { debuglog("GKEY=$gkey"); http_die("wrong GKEY authentification"); } } # check for ID in query elsif ($qs =~ s/\&*\bID=([^&]+)//i) { $id = $1; $fop_auth = 0; if ($id eq 'PUBLIC') { http_header('403 Forbidden'); exit; } if ($file =~ m:^(.+)/(.+)/(.+):) { $to = $1; $from = $2; $to =~ s/,+/,/g; $to =~ s/\s//g; $from =~ s/\s//g; if ($mdomain and $from ne 'anonymous') { $to .= '@'.$mdomain if $to !~ /@/; $from .= '@'.$mdomain if $from !~ /@/; } $to = lc $to; $from = lc $from; } else { http_die("unknown file query format"); } # public or anonymous recipient? (needs no auth-ID for sender) if ($anonymous or $id eq 'PUBLIC' and @public_recipients and grep /^\Q$to\E$/i,@public_recipients) { $rid = $id; } else { open my $idf,'<',"$from/@" or http_die("unknown user $from"); $rid = getline($idf); close $idf; $rid = sidhash($rid,$id); } unless ($id eq $rid) { debuglog("real id=$rid, id sent by user=$id"); http_die("wrong auth-ID"); } # 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")); unlink "$akeydir/$akey"; symlink "../$from","$akeydir/$akey"; } my %to; COLLECTTO: foreach my $to (split(',',$to)) { if ($to !~ /.@./ and open my $AB,'<',"$from/\@ADDRESS_BOOK") { while (<$AB>) { s/\s*#.*//; s/^\s+//; next unless $_; if (/^\s*([\S]+)\s+([\S]+)/) { my ($alias,$address) = ($1,$2); if ($to =~ /^\Q$alias\E$/i) { foreach my $to (split(",",$address)) { $to .= '@'.$mdomain if $mdomain and $to !~ /@/; $to{$to} = lc $to; # ignore dupes } next COLLECTTO; } } } } elsif ($to =~ /^\@(.+)/) { my $group = "$from/\@GROUP/$1"; if (not -l $group and open $group) { while (<$group>) { s/#.*//; s/\s//g; if (/(.+\@[w.-]+):.+/) { $to{$1} = lc $1; # ignore dupes } } close $group; } } else { $to .= '@'.$mdomain if $mdomain and $to !~ /.@./; $to{$to} = lc $to; # ignore dupes } } foreach $to (keys %to) { # if (-e "$to/\@CAPTIVE") { http_die("$to is CAPTIVE") } unless (-d $to or checkaddress($to)) { http_die("$to is not a legal e-mail address"); } } } if ($qs =~ /\&?KEEP=(\d+)/i) { $keep = $1; $filename = filename($file); check_captive($file); if (-f $data) { unlink "$file/keep"; if (symlink $keep,"$file/keep") { http_header('200 OK'); print html_header($head), "

set keep=$keep for $filename

\n", "\n"; } else { http_header('599 internal error'); print html_header($head), "

$filename - $!

\n", "\n"; } } else { http_header('404 File not found'); print html_header($head), "

$filename not found

\n", "\n"; } exit; } elsif ($qs =~ s/\&?KEEP//i) { check_captive($file); $autodelete = 'NO'; } if ($qs =~ s/\&?FILEID=(\w+)//i) { $fileid = $1 } if ($qs =~ s/\&?IGNOREWARNING//i) { $ignorewarning = 1 } if ($qs eq 'LIST') { http_header('200 OK','Content-Type: text/plain'); print "$file :\n"; chdir $file and exec '/client/bin/l'; exit; } # copy file to yourself if ($qs eq 'COPY') { unless (-f "$file/data") { http_die("File not found."); } ($to,$from,$file) = split('/',$file); unless ("$to/@") { # http_header('403 Forbidden'); # print html_header($head), # "You have no permission to copy a file.\n", # "\n"; http_die("You have no permission to copy a file."); } if (-s "$to/\@ALLOWED_RECIPIENTS") { http_die("You are a restricted user."); } if (-e "$to/$to/$file/data") { # http_header('409 File Exists'); # print html_header($head), # "File $file already exists in your outgoing spool.\n", # "\n"; http_die("File $file already exists in your outgoing spool."); } mkdirp("$to/$to/$file"); link "$to/$from/$file/data","$to/$to/$file/data" or http_die("cannot link to $to/$to/$file/data - $!\n"); my $fkey = copy("$to/$from/$file/filename","$to/$to/$file/filename"); open my $notify,'>',"$to/$to/$file/notify"; close $notify; my $dkey = randstring(8); unlink "$to/$to/$file/dkey","$dkeydir/$dkey"; symlink "../$to/$to/$file","$dkeydir/$dkey"; symlink $dkey,"$to/$to/$file/dkey"; http_header('200 OK',"Location: $durl/$dkey/$fkey"); print html_header($head), "File $file copied to yourself.\n", "\n"; exit; } # ex and hopp? if ($qs =~ s/(^|&)DELETE//i) { if (unlink $data) { $filename = filename($file); if (open my $log,'>',"$file/error") { printf {$log} "%s has been deleted by %s at %s\n", $filename,$ENV{REMOTE_ADDR},isodate(time); close $log; } foreach my $logdir (@logdir) { my $msg = sprintf "%s [%s_%s] %s %s deleted\n", isodate(time),$$,$ENV{REQUESTCOUNT},$ra,encode_Q($file); if (open $log,'>>',"$logdir/$log") { print {$log} $msg; close $log; } } http_header('200 OK',"X-File: $file"); print html_header($head), "

$filename deleted

\n", "\n"; exit; } else { http_die("no such file"); } exit; } # wipe out!? (for anonymous upload) if ($qs =~ s/(^|&)PURGE//i) { $filename = filename($file); if (@anonymous_upload and ipin($ra,@anonymous_upload)) { unlink "$dkeydir/$dkey" if $dkey; if (rmrf($file)) { foreach my $logdir (@logdir) { my $msg = sprintf "%s [%s_%s] %s %s purged\n", isodate(time),$$,$ENV{REQUESTCOUNT},$ra,encode_Q($file); if (open $log,'>>',"$logdir/$log") { print {$log} $msg; close $log; } } http_header('200 OK',"X-File: $file"); print html_header($head), "

$filename purged

\n", "\n"; } else { http_die("no such file"); } } else { http_die("you are not allowed to purge $filename"); } exit; } # request for file size? if ($qs eq '?') { sendsize($file); # control back to fexsrv for further HTTP handling &reexec; } # fallback if ($qs) { http_die("unknown query format $qs"); } } unless ($id and $rid and $id eq $rid or $dkey or $anonymous) { http_die("wrong parameter $file"); } unless ($to) { http_die("internal error: unknown recipient"); } unless ($from) { http_die("internal error: unknown sender"); } &check_status($from); # server based ip restrictions if (@download_hosts and not ipin($ra,@download_hosts)) { http_die( "Downloads from your host ($ra) are not allowed.", "Contact $ENV{SERVER_ADMIN} for details." ); } # user based ip restrictions unless (check_rhosts("$to/\@DOWNLOAD_HOSTS")) { http_die("You are not allowed to download from IP $ra"); } # file based ip restrictions unless (check_rhosts("$file/restrictions")) { http_die("Download of files from external user $from is restricted " ."to internal hosts. Your IP $ra is not allowed."); } # set time mark for this access if ($file =~ m:(.+?)/:) { my $user = $1; my $time = untaint(time); utime $time,$time,$user; } # reget or range? if ($range = $ENV{HTTP_RANGE}) { $seek = $1 if $range =~ /^bytes=(\d+)-/i; $stop = $1 if $range =~ /^bytes=\d*-(\d+)/i; } else { $seek = 0; $stop = 0; } if (not $autodelete or $autodelete ne 'NO') { $autodelete = readlink "$file/autodelete" || 'YES'; } if ($from and $file eq "$from/$from/ADDRESS_BOOK") { if (open my $AB,'<',"$from/\@ADDRESS_BOOK") { my $ab = ''; while (<$AB>) { s/^\s+//; s/\s+$//; s/[\r\n]//g; $ab .= $_."\r\n"; } close $AB; nvt_print( 'HTTP/1.1 200 OK', 'Content-Length: ' . length($ab), 'Content-Type: text/plain', '' ); print $ab; } else { nvt_print( 'HTTP/1.1 404 No address book found', 'Content-Length: 0', '' ); } # control back to fexsrv for further HTTP handling &reexec; } if (-f $data) { # already downloaded? if ($limited_download and $limited_download !~ /^n/i and $from ne $to # fex to yourself is ok! and $from !~ /^_?fexmail/ # fexmail is ok! and $to !~ /^_?fexmail/ # fexmail is ok! and $to !~ /^anonymous/ # anonymous fex is ok! and $to !~ /$amdl/ # allowed multi download recipients and $http_client !~ /$adlm/ # allowed download managers and $file !~ /\/STDFEX$/ # xx is ok! and (slurp("$file/comment")||'') !~ /^!\*!/ # multi download allow flag and not($dkey and ($ENV{HTTP_COOKIE}||'') =~ /dkey=$dkey/) and open $file,'<',"$file/download") { my $d1 = <$file> || ''; # first download chomp $d1; close $file; if ($ra) { # allow downloads from same ip $d1 = '' if $d1 =~ /\Q$ra/; # allow downloads from sender ip $d1 = '' if (readlink("$file/ip")||'') eq $ra; } if ($d1 and $d1 =~ s/(.+) ([\w.:]+)$/$2 at $1/) { $file = filename($file); http_die("$file has already been downloaded by $d1"); } } $sb = sendfile($file,$seek,$stop); shutdown(STDOUT,2); } elsif (-l $data) { # $file =~ s:.*/::; http_die("$file has been withdrawn"); } elsif (open $errf,'<',"$file/error" and $err = getline($errf)) { fdlog($log,$file,0,0); http_die($err); } else { fdlog($log,$file,0,0); if ($file =~ /^anonymous.*afex_\d+\.tar$/) { # should be extra handled... } http_die("no such file $file"); } debuglog(sprintf("%s %s %d %d %d", isodate(time),$file,$sb||0,$seek,-s $data||0)); if ($sb+$seek == -s $data) { # note successfull download $download = "$file/download"; if (open $download,'>>',$download) { printf {$download} "%s %s\n",isodate(time),$ENV{REMOTE_ADDR}; close $download; } # delete file after grace period if ($autodelete eq 'YES') { $grace_time = 60 unless defined $grace_time; for (;;) { my $utime = (stat $data)[8] || 0; my $dtime = (stat $download)[8] || 0; exit if $utime > $dtime; last if time > $dtime+$grace_time; sleep 10; } unlink $data; my $error = "$file/error"; if (open $error,'>',$error) { printf {$error} "%s has been autodeleted after download from %s at %s\n", filename($file),$ENV{REMOTE_ADDR},isodate(time); close $error; } } } exit; sub sendfile { my ($file,$seek,$stop) = @_; my ($filename,$size,$total_size,$fileid,$filetype); my ($data,$download,$header,$buf,$range,$s,$b,$t0); my $type = ''; # swap to and from for special senders, see fup storage swap! $file =~ s:^(_?anonymous_.*)/(anonymous.*)/:$2/$1/:; $file =~ s:^(_?fexmail_.*)/(fexmail.*)/:$2/$1/:; $data = $file.'/data'; $download = $file.'/download'; $header = $file.'/header'; # fallback defaults, should be set later with better values $filename = filename($file); $total_size = -s $data || 0; # file link? if (-l $data) { unless (-f $data and -r $data) { http_die("$file has been withdrawn"); } $data = abs_path($data); my $fok; foreach (@file_link_dirs) { my $dir = abs_path($_); $fok = $data if $data =~ /^\Q$dir\//; } unless ($fok) { http_die("no permission to download $file"); } } else { unless (-f $data and -r $data) { http_die("$file has gone"); } } if ($ENV{REQUEST_METHOD} eq 'GET') { debuglog("Exp: FROM=\"$from\"","Exp: TO=\"$to\""); open $data,$data and flock($data,LOCK_EX|LOCK_NB); # security check: must be regular file after abs_path() if (-l $data) { http_die("no permission to download $file"); } # HTTP Range download suckers are already rejected by fexsrv unless ($range = $ENV{HTTP_RANGE}) { # download lock open $download,'>>',$download or die "$download - $!\n"; if ($file =~ m:(.+?)/(.+?)/: and $1 ne $2) { # only one concurrent download is allowed if sender <> recipient flock($download,LOCK_EX|LOCK_NB) or http_die("$file locked: a download is already in progress"); } } $size = $total_size - $seek - ($stop ? $total_size-$stop-1 : 0); } elsif ($ENV{REQUEST_METHOD} eq 'HEAD') { $size = -s $data || 0; } else { http_die("unknown HTTP request method $ENV{REQUEST_METHOD}"); } # read MIME entity header (what the client said) if (open $header,'<',$header) { while (<$header>) { if (/^Content-Type: (.+)/i) { $type = $1; last; } } close $header; $type =~ s/\s//g; } $fileid = readlink "$file/id" || ''; # determine own MIME entity header for download my $mime = $file; $mime =~ s:/.*:/\@MIME:; my $mt = $ENV{FEXHOME}.'/etc/mime.types'; if (($type =~ /x-mime/i or -e $mime) and open $mt,'<',$mt) { $type = 'application/octet-stream'; MIMETYPES: while (<$mt>) { chomp; s/#.*//; s/^\s+//; my ($mt,@ft) = split; foreach my $ft (@ft) { if ($filename =~ /\.\Q$ft\E$/i) { $type = $mt; last MIMETYPES; } } } close $mt; } # reset to default MIME type else { $type = 'application/octet-stream' } # HTML is not allowed for security reasons! (embedded javascript, etc) $type =~ s/html/plain/i; debuglog("download with $http_client"); if ($seek or $stop) { if ($size < 0) { http_header('416 Requested Range Not Satisfiable'); exit; } if ($stop) { $range = sprintf("bytes %s-%s/%s",$seek,$stop,$total_size); } else { $range = sprintf("bytes %s-%s/%s",$seek,$total_size-1,$total_size); } # RFC 7233 "Responses to a Range Request" nvt_print( 'HTTP/1.1 206 Partial Content', "Content-Length: $size", "Content-Range: $range", "Content-Type: $type", ); if ($http_client !~ /MSIE/) { nvt_print("Cache-Control: no-cache"); if ($type eq 'application/octet-stream') { nvt_print("Content-Disposition: attachment; filename=\"$filename\""); } } nvt_print(''); } else { # another stupid IE bug-workaround # http://drupal.org/node/163445 # http://support.microsoft.com/kb/323308 if ($http_client =~ /MSIE/ and not $nowarning) { # $type = 'application/x-msdownload'; if ($ignorewarning) { $type .= "; filename=$filename"; nvt_print( 'HTTP/1.1 200 OK', "Content-Length: $size", "Content-Type: $type", # "Pragma: no-cache", # "Cache-Control: no-store", "Content-Disposition: attachment; filename=\"$filename\"", "Connection: close", ); # nvt_print('','HTTP/1.1 200 OK',"Content-Length: $size","Content-Type: $type"); exit; nvt_print($_) foreach(@extra_header); } else { http_header('200 OK'); print html_header($head); pq(qq( '

Internet Explorer warning

' 'Using Microsoft Internet Explorer for download will probably' 'lead to problems, because it is not Internet compatible (RFC 2616).' '

' 'We recommend Firefox' '

' 'If you really want to continue with Internet Explorer, then' '' 'click here with your right mouse button and select "save as"' '' '

' 'See also F*EX user FAQ.' '' )); &reexec; } } else { nvt_print( 'HTTP/1.1 200 OK', "Content-Length: $size", "Content-Type: $type", "Cache-Control: no-cache", "Connection: close", ); if ($type eq 'application/octet-stream') { nvt_print(qq'Content-Disposition: attachment; filename="$filename"'); } nvt_print($_) foreach(@extra_header); } nvt_print("X-Size: $total_size"); nvt_print("X-File-ID: $fileid") if $fileid; # if ((`file "$file/data" 2>/dev/null` || '') =~ m{.*/data:\s(.+)}) { # nvt_print("X-File-Type: $1"); # } if ($dkey = $dkey||readlink "$file/dkey") { my $ma = (readlink "$file/keep"||$keep_default)*60*60*24; nvt_print("Set-Cookie: dkey=$dkey; Max-Age=$ma; Path=$ENV{REQUEST_URI}"); } nvt_print(''); } if ($ENV{REQUEST_METHOD} eq 'HEAD') { # control back to fexsrv for further HTTP handling &reexec; } if ($ENV{REQUEST_METHOD} eq 'GET') { if (@throttle) { my $to = $file; $to =~ s:/.*::; foreach (@throttle) { if (/(.+):(\d+)$/) { my $throttle = $1; my $limit = $2; # throttle ip address? if ($throttle =~ /^[\d.-]+$/) { if (ipin($ra,$throttle)) { $bwl = $limit; last; } } # throttle e-mail address? else { # allow wildcard *, but not regexps $throttle =~ quotemeta $throttle; $throttle =~ s/\*/.*/g; if ($to =~ /$throttle$/) { $bwl = $limit; last; } } } } } foreach my $sig (keys %SIG) { local $SIG{$sig} = \&sigexit } local $SIG{ALRM} = sub { die "TIMEOUT\n" }; seek $data,$seek,0; $t0 = time; $s = $b = 0; # sysread/syswrite because of speed while ($s < $size and $b = sysread($data,$buf,$bs)) { # last chunk for HTTP Range? if ($stop and $s+$b > $size) { $b = $size-$s; $buf = substr($buf,0,$b) } $s += $b; alarm($timeout*10); syswrite STDOUT,$buf or last; # client still alive? if ($bwl) { alarm(0); sleep 1 while $s/(time-$t0||1)/1024 > $bwl; } } close $data; alarm(0); fdlog($log,$file,$s,$size); } close $download; return $s; } sub sendsize { my ($path) = @_; my ($file,$upload,$to,$from,$dkey); my $size = 0; local $_; $path =~ s:^/::; ($to,$from,$file) = split('/',$path); $to =~ s/,.*//; $to = lc $to; $from = lc $from; # swap to and from for special senders, see fup storage swap! ($from,$to) = ($to,$from) if $from =~ /^(fexmail|anonymous)/; $to .= '@'.$hostname if $to eq 'anonymous'; $from .= '@'.$hostname if $from eq 'anonymous'; $to .= '@'.$mdomain if -d "$to\@$mdomain"; $from .= '@'.$mdomain if -d "$from\@$mdomain"; $file =~ s/%([A-F0-9]{2})/chr(hex($1))/ge; $file = urlencode($file); if ($to eq '*' and $fileid) { foreach my $fd (glob "*/$from/$file") { if (-f "$fd/data" and -l "$fd/id" and readlink "$fd/id" eq $fileid and $dkey = readlink "$fd/dkey") { $to = $fd; $to =~ s:/.*::; last; } } } elsif ($to !~ /@/ and open my $AB,'<',"$from/\@ADDRESS_BOOK") { while (<$AB>) { s/\s*#.*//; $_ = lc $_; my ($alias,$address) = split; if ($address) { $address =~ s/,.*//; $address .= '@'.$mdomain if $mdomain and $address !~ /@/; if ($to eq $alias) { $to = $address; last; } } } close $AB; } if (-f "$to/$from/$file/data") { $dkey = readlink "$to/$from/$file/dkey"; $fkey = slurp("$to/$from/$file/filename")||$file; } $upload = -s "$to/$from/$file/upload" || -s "$to/$from/$file/data" || 0; $size = readlink "$to/$from/$file/size" || 0; $fileid = readlink "$to/$from/$file/id" || ''; nvt_print('HTTP/1.1 200 OK'); nvt_print("Server: fexsrv"); nvt_print("Content-Length: $upload"); nvt_print("X-Original-Recipient: $to"); if ($dkey and not -s "$from/\@ALLOWED_RECIPIENTS") { nvt_print("X-DKEY: $dkey"); nvt_print("X-Location: $durl/$dkey/$fkey") if $fkey; } nvt_print("X-Size: $size"); nvt_print("X-File-ID: $fileid") if $fileid; nvt_print("X-Features: $ENV{FEATURES}"); nvt_print(''); } sub check_rhosts { my $ipr = shift; my @hosts; local $_; if (open $ipr,$ipr) { while (<$ipr>) { chomp; s/#.*//; s/\s//g; if ($_ eq '@LOCAL_RHOSTS') { push @hosts,@local_rhosts if @local_rhosts; } elsif (/\w/) { push @hosts,$_; } } close $ipr; if (@hosts and not ipin($ra,@hosts)) { return 0; } } return 1; } sub require_auth { http_header( '401 Authorization Required', 'WWW-Authenticate: Basic realm="'.$ENV{SERVER_NAME}.' F*EX download"', 'Content-Length: 0', ); # control back to fexsrv for further HTTP handling &reexec; } sub check_auth { my ($path,$user,$auth) = @_; my ($to,$from,$file,$dkey); my ($id,$idf); my ($subuser,$subid); my $auth_ok = 0; local $_; if ($path =~ m:(.+)/(.+)/(.+):) { ($to,$from,$file) = ($1,$2,$3); } elsif ($path =~ m:(.+)/(.+):) { ($dkey,$file) = ($1,$2); $path = readlink "$dkeydir/$dkey" or http_die('no such file'); (undef,$to,$from,$file) = split('/',$path); } else { http_die("wrong URL format for download"); } $to .= '@'.$mdomain if $mdomain and $to !~ /@/; $from .= '@'.$mdomain if $mdomain and $from !~ /@/; $to = lc $to; $from = lc $from; # auth user match to in download URL? if ($to ne $user and "$to\@$mdomain" ne $user and $to ne "$user@$mdomain") { debuglog("mismatch: to=$to, auth user=$user"); &require_auth; } # check for real user if (open $idf,'<',"$to/@") { $id = getline($idf); close $idf; unless ($id and $id eq $auth) { debuglog("$user mismatch: id=$id, auth=$auth"); &require_auth; } } # check for sub user elsif (open $idf,'<',"$from/\@SUBUSER") { while (<$idf>) { chomp; s/#.*//; ($subuser,$subid) = split ':'; if ($subid and $subid eq $auth and ($user eq $subuser or $subuser eq '*@*' or $subuser =~ /^\*\@(.+)/ and $user =~ /\@\Q$1\E$/i or $subuser =~ /(.+)\@\*$/ and $user =~ /^\Q$1\E\@/i)) { $auth_ok = 1; last; } } close $idf; unless ($auth_ok) { debuglog("no matching $user in $from/\@SUBUSER"); &require_auth; } } else { debuglog("no $to/@ and no $from/@"); &require_auth; } } sub check_captive { my $to = shift; $to =~ s:/.*::; $to .= '@'.$mdomain if $mdomain and -d "$to\@$mdomain"; if (-e "$to/\@CAPTIVE") { http_die("$to is CAPTIVE - no URL parameters allowed"); } } sub sigexit { my ($sig) = @_; my $msg; $msg = @_ ? "@_" : '???'; $msg =~ s/\n/ /g; $msg =~ s/\s+$//; errorlog("$file caught SIGNAL $msg"); # sigpipe means: client has terminated # this event will be handled further by sendfile(), do not terminate here if ($sig ne 'PIPE') { $SIG{__DIE__} = ''; if ($sig eq 'DIE') { shift; die "$msg\n"; } else { die "SIGNAL $msg\n"; } } } fex-20160919/cgi-bin/fuc0000755000174700017470000007666312670476252012763 0ustar fexfex#!/usr/bin/perl -wT # FEX CGI for user control # (subuser, groups, address book, one time upload key, auth-ID, etc) # # Author: Ulli Horlacher # BEGIN { ($ENV{PERLINIT}||'') =~ /(.+)/s and eval $1 } use utf8; use Fcntl qw(:flock); use Digest::MD5 qw(md5_hex); # add fex lib ($FEXLIB) = $ENV{FEXLIB} =~ /(.+)/; die "$0: no $FEXLIB\n" unless -d $FEXLIB; # import from fex.pp our ($FEXHOME); our ($mdomain,$admin,$hostname,$sendmail,$akeydir,$skeydir,$docdir,$durl,$bcc); our ($nomail,$faillog); our $akey = ''; # load common code, local config : $HOME/lib/fex.ph require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n"; my ($CASE,$ESAC); my $error = 'F*EX user config ERROR'; my $head = "$ENV{SERVER_NAME} F*EX user config"; my $fup = $durl; $fup =~ s:/fop:/fup:; chdir $spooldir or die "$spooldir - $!\n"; my $user = my $id = my $nid = my $ssid = my $comment = ''; my $notification = my $reminder = my $disclaimer = ''; my $encryption = my $pubkey = my $mime = ''; $akey = ''; # delete akey cookie my $qs = $ENV{QUERY_STRING}; if ($qs) { if ($qs =~ /akey=(\w+)/i) { $akey = $1 } if ($qs =~ /ab=load/) { $ab = 'load' } } # look for CGI parameters our %PARAM; &parse_parameters; foreach my $v (keys %PARAM) { my $vv = $PARAM{$v}; # debuglog("Param: $v=\"$vv\""); if ($v =~ /^akey$/i) { $akey = $1 if $vv =~ /^(\w+)$/; next; } $CASE = $v =~ /^user$/i ? $user = normalize_email($vv): $v =~ /^subuser$/i ? $subuser = normalize_email($vv): $v =~ /^otuser$/i ? $otuser = normalize_email($vv): $v =~ /^notify$/i ? $notify = normalize_email($vv): $v =~ /^notification$/i ? $notification = checkchars('parameter',$vv): $v =~ /^disclaimer$/i ? $disclaimer = $vv: $v =~ /^encryption$/i ? $encryption = checkchars('parameter',$vv): $v =~ /^pubkey$/i ? $pubkey = $PARAM{$v}{data}: $v =~ /^reminder$/i ? $reminder = checkchars('parameter',$vv): $v =~ /^mime$/i ? $mime = checkchars('parameter',$vv): $v =~ /^comment$/i ? $comment = decode_utf8(normalize($vv)): $v =~ /^id$/i ? $id = checkchars('auth-ID',$vv): $v =~ /^nid$/i ? $nid = checkchars('auth-ID',$vv): $v =~ /^ssid$/i ? $ssid = $vv: $v =~ /^group$/i ? $group = checkchars('group',$vv): $v =~ /^ab$/i ? $ab = $vv: $v =~ /^gm$/i ? $gm = $vv: $v =~ /^show$/i ? $show = checkchars('parameter',$vv): $ESAC; } if ($group and $group ne 'NEW') { $group = lc $group; $group =~ s/[^\w\*%^+=:,.!-]/_/g; } $group = '' if $nomail; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; $nomail = $comment if $comment =~ /NOMAIL|!#!/; if ($show and $show eq 'tools') { nvt_print( "HTTP/1.1 302 Found", "Location: /tools.html", 'Expires: 0', 'Content-Length: 0', '' ); &reexec; if (open $tools,"$docdir/tools.html") { while (<$tools>) { while (/\$([\w_]+)\$/) { my $var = $1; my $env = $ENV{$var} || ''; s/\$$var\$/$env/g; }; print; } } exit; } if ($akey) { # sid is not set with web browser my $idf = "$akeydir/$akey/@"; if (open $akey,'<',$idf and $id = getline($akey)) { close $akey; $idf =~ /(.*)\/\@/; $user = readlink $1 or http_die("internal server error: no $akey symlink $1"); $user =~ s:.*/::; $user = untaint($user); if ($akey ne md5_hex("$user:$id")) { $user = $id = ''; } } } &check_status($user) if $user; if ($user and $akey and $qs and $qs =~ /info=(.+?)&skey=(.+)/) { $subuser = $1; $skey = $2; notify_subuser($user,$subuser,"$fup?skey=$skey#$user",$comment); http_header("200 OK"); print html_header($head); pq(qq( 'An information e-mail has been sent to your subuser $subuser' '

Go back' '' )); exit; } if ($user and $id) { if (-e "$user/\@CAPTIVE") { html_error($error,"captive user") } unless (open $idf,'<',"$user/@") { faillog("user $from, id $id"); html_error($error,"wrong user or auth-ID"); } $rid = getline($idf); close $idf; if ($id eq $rid) { unless ($akey) { $akey = untaint(md5_hex("$user:$id")); unlink "$akeydir/$akey"; symlink "../$user","$akeydir/$akey"; } } else { faillog("user $from, id $id"); html_error($error,"wrong user or auth-ID"); } } else { my $login = -x "$FEXHOME/login" ? 'login' : 'fup'; nvt_print( "HTTP/1.1 302 Found", "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/$login", 'Expires: 0', 'Content-Length: 0', '' ); &reexec; } # empty POST? ==> back to foc if ($ENV{REQUEST_METHOD} eq 'POST' and not ($subuser or $notify or $nid or $ssid or $group or $ab or $gm or $disclaimer or $encryption or $pubkey)) { nvt_print( "HTTP/1.1 302 Found", "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/foc", 'Expires: 0', 'Content-Length: 0', '' ); &reexec; } unlink $faillog if $faillog; http_header("200 OK"); print html_header($head); # foreach $v (keys %ENV) { print $v,' = "',$ENV{$v},"\"
\n" }; if ($gm and not $group) { pq(qq( '

ERROR: no group name specified

' '' )); exit; } if ($group) { &handle_group; } # create one time upload key if ($subuser and $otuser) { $otuser = $subuser; if ($otuser !~ /^[^@]+@[\w.-]+[a-z]$/) { pq(qq( '$otuser is not a valid e-mail address' '

Go back' '' )); exit; } my $okey = randstring(8); my $okeyd = "$user/\@OKEY"; mkdir $okeyd; symlink $otuser,"$okeyd/$okey" or http_die("cannot create OKEY $okeyd/$okey : $!\n"); my $url = "$fup?to=$user&okey=$okey"; pq(qq( 'A one time upload URL for $otuser has been created:' '

' '$url' )); unless ($nomail) { ¬ify_otuser($user,$otuser,$url,$comment); pq(qq( '

' 'and an information e-mail has been sent to this address.' '

' )); } pq(qq( 'back to F*EX operation control' '' )); exit; } # direct single subuser entry if ($subuser and not $otuser) { if (-f "$subuser/@") { pq(qq( '$subuser is already a registered F*EX full user' '

Go back' '' )); exit; } if ($subuser !~ /^[^@]+@[\w.-]+[a-z]$/) { pq(qq( '$subuser is not a valid e-mail address' '

Go back' '' )); exit; } $skey = ''; if (open $idf,'<',"$user/\@SUBUSER") { while (<$idf>) { chomp; if (/^\Q$subuser:/) { $skey = md5_hex("$user:$_"); last; } } close $idf; } if ($skey) { my $url = "$fup?skey=$skey"; if ($nomail) { pq(qq( '$subuser is already your subuser and has access URL:' '

' '$url' )); } else { pq(qq( '$subuser' 'is already your subuser and has access URL:' '

' '$url' '

' "Click on the subuser's e-mail address link to send him an" "information e-mail by the F*EX server.

" )); } } else { my $sid = randstring(8); my $skey = mkskey($user,$subuser,$sid); $url = "$fup?skey=$skey"; open $idf,'>>',"$user/\@SUBUSER" or die "$user/\@SUBUSER - $!\n"; print {$idf} "$subuser:$sid\n"; close $idf; pq(qq( 'Your subuser upload URL is:' '

' '$url' )); unless ($nomail) { ¬ify_subuser($user,$subuser,$url,$comment); pq(qq( '

' 'An information e-mail has been sent to $subuser' )); } } print "\n"; exit; } # modify addressbook if ($user and $akey and defined $ab) { if ($ab eq 'load') { $ab = ''; if (open $ab,'<',"$user/\@ADDRESS_BOOK") { undef $/; $_ = <$ab>; s/\s*$/\n/; close $ab; $ab = html_quote($_); } my $rows = ($ab =~ tr/\n//) + 5; pq(qq( '

Edit address book

' '' ' ' ' ' '
Entry:aliase-mail address# optional comment
Example:Framstagframstag\@rus.uni-stuttgart.de# Ulli Horlacher
' '
' ' ' '
' ' ' '
' '

' 'You may use these alias names as F*EX recipient addresses on ' 'fup' '

' 'Alternatively you can fex a file ADDRESS_BOOK to yourself ' '($user) containing your alias definitions.' '

' 'back to F*EX operation control' '' )); exit; } else { $ab =~ s/[\r<>]//g; $ab =~ s/\s*$/\n/; foreach (split(/\n/,$ab)) { s/^\s+//; s/\s+$//; if (s/\s*(#.*)//) { $comment = $1 } else { $comment = '' } next if /^\s*$/; @options = (); push @options,$1 if s/(autodelete=\w+)//i; push @options,$1 if s/(keep=\d+)//i; s/[,\s]+$//; if (s/([\S]+)\s+(\S+)//) { $alias = $1; $address = $2; $options = join(',',@options); push @abt,"$alias$address$options$comment\n"; } else { push @badalias,$_; } } if (@badalias) { print "

ERROR: bad aliases:

\n
    "; foreach my $ba (@badalias) { print "
  • $ba" } pq(qq( '
' '

' 'Not in format: alias e-mail-address' '

' 'Go back' '' )); exit; } open my $AB,'>',"$user/\@ADDRESS_BOOK" or http_die("cannot open $user/\@ADDRESS_BOOK - $!\n"); print {$AB} $ab; close $AB; pq(qq( '

address book

' '' '' '@abt' '
aliase-mail addressoptionscomment
' '

' 'back to F*EX operation control' '

' 'back to fup (F*EX upload)' '' )); } exit; } if ($user and $notification eq 'detailed') { unlink "$user/\@NOTIFICATION"; pq(qq( '

Notification e-mails now come in detailed format.

' '

' 'back to F*EX operation control' '' )); &reexec; } if ($user and $mime eq 'yes') { open $mime,'>',"$user/\@MIME" or http_die("cannot write $user/\@MIME - $!\n"); close $mime; pq(qq( '

Downloads will now be displayed (if possible).

' '

' 'back to F*EX operation control' '' )); &reexec; } if ($user and $mime eq 'no') { unlink "$user/\@MIME"; pq(qq( '

Downloads will now be saved.

' '

' 'back to F*EX operation control' '' )); &reexec; } if ($user and $notification eq 'short') { unlink "$user/\@NOTIFICATION"; symlink "short","$user/\@NOTIFICATION"; pq(qq( '

Notification e-mails now come in short format.

' '

' 'back to F*EX operation control' '' )); &reexec; } if ($user and $disclaimer) { my $df = "$user/\@DISCLAIMER"; if ($disclaimer =~ /^[\s\"]*DEFAULT[\s\"]*$/i) { unlink $df; pq(qq( '

E-mail disclaimer reset to default.

' '

' 'back to F*EX operation control' '' )); } elsif ($disclaimer eq 'CHANGE') { $disclaimer = slurp($df) || ''; $disclaimer =~ s/&/&/g; $disclaimer =~ s/' ' ' '


' ' Disclaimer to be sent with download notification e-mail:
' '
' ' ' ' or ' ' reset the disclaimer to default.' '' '' )); exit; } else { $disclaimer =~ s/^\s+//; $disclaimer =~ s/\s+$/\n/; open $df,'>',$df or http_die("cannot write $df - $!\n"); print {$df} $disclaimer; close $df; $disclaimer =~ s/&/&/g; $disclaimer =~ s/E-mail disclaimer changed to:' '

'
      '$disclaimer'
      '
' '

' 'back to F*EX operation control' '' )); } &reexec; } if ($user and $pubkey) { my $gf = "$user/\@GPG"; my $pk; local $/; local $_; open $pk,">$gf.pk" or http_die("cannot write $gf.pk - $!\n"); print {$pk} $pubkey; close $pk; unlink $gf; system "gpg --batch --no-default-keyring --keyring $gf --import". "< $gf.pk >/dev/null 2>&1"; if (`gpg --batch <$gf 2>/dev/null` =~ /^pub\s.*<\Q$user\E>/sm) { $pk = `gpg --batch <$gf 2>&1`; $pk =~ s/&/&/g; $pk =~ s/E-mails to you will be encrypted with the PGP/GPG key:' '

'
      '$pk'
      '
' '

' 'back to F*EX operation control' '' )); unlink "$gf.pk","$gf~"; } else { $pk = `gpg --batch <$gf.pk 2>&1`; $pk =~ s/&/&/g; $pk =~ s/Your uploaded file does not contain a PGP/GPG public key for' ' $user' '

'
      '$pk'
      '
' '

' 'back' '' )); } &reexec; } if ($user and $encryption) { my $gf = "$user/\@GPG"; unless(-s "$ENV{HOME}/.gnupg/pubring.gpg") { html_error($error,"no GPG support activated"); } if ($encryption eq 'DELETE') { unlink $gf; pq(qq( '

PGP/GPG key deleted.

' '

E-mails to you will be sent not encrypted.

' '

' 'back to F*EX operation control' )); } elsif ($encryption eq 'CHANGE') { pq(qq( '

' ' ' ' Select your PGP/GPG public key file(*):
' ' ' '

' ' and ' '

' )); if (-f $gf) { my $g = `gpg < $gf`; $g =~ s/' 'delete your already uploaded public key:' '
'
        '$g'
        '
' )); } pq(qq( '


' '(*) To extract and verify your GPG public key use:' '

'
      'gpg -a --export $user > pubkey.gpg'
      'gpg < pubkey.gpg'
      '
' )); } print "\n"; exit; } if ($user and $reminder eq 'yes') { unlink "$user/\@REMINDER"; pq(qq( '

You will now get reminder notification e-mails.

' '

' 'back to F*EX operation control' '' )); &reexec; } if ($user and $reminder eq 'no') { unlink "$user/\@REMINDER"; symlink "no","$user/\@REMINDER"; pq(qq( '

You will now get no reminder notification e-mails.

' '

' 'back to F*EX operation control' '' )); &reexec; } if ($nid) { $nid =~ s/^\s+//; $nid =~ s/\s+$//; $nid = randstring(6) if $nid eq '?'; open $idf,'>',"$user/@" or die "$user/@ - $!\n"; print {$idf} $nid,"\n"; close $idf; $akey = untaint(md5_hex("$user:$nid")); unlink "$akeydir/$akey"; symlink "../$user","$akeydir/$akey"; pq(qq( '

new auth-ID "$nid" for $user saved

' 'back to F*EX operation control' '' )); &reexec; } # empty subuser list POST if (defined($PARAM{'ssid'}) and $ssid =~ /^\s*$/) { unlink "$user/\@SUBUSER"; pq(qq( '

All subusers deleted

\n
    ' 'back to F*EX operation control' '' )); &reexec; } # update sub-users if ($ssid) { my ($subuser,$subid,$skey); # delete old skeys if (open $idf,'<',"$user/\@SUBUSER") { while (<$idf>) { s/#.*//; if (/(.+\@.+):(.+)/) { ($subuser,$subid) = ($1,$2); $skey = md5_hex("$user:$subuser:$subid"); unlink "$skeydir/$skey"; unlink "$subuser/\@MAINUSER/$user"; } } close $idf; } $ssid = strip($ssid); # collect (new) subusers foreach (split("\n",$ssid)) { s/#.*//; s/\s//g; if (/(.+\@[\w.-]+)/) { $subuser = lc $1; push @badaddress,$subuser unless checkaddress($subuser); } } if (@badaddress) { print "

    ERROR: bad addresses:

    \n
      "; foreach my $ba (@badaddress) { print "
    • $ba" } pq(qq( '
    ' 'Go back' '' )); exit; } if ($ssid =~ /\S\@\w/) { open $idf,'>',"$user/\@SUBUSER" or die "$user/\@SUBUSER - $!\n"; print "Your subusers upload URLs are:

    \n"; print "\n"; foreach (split("\n",$ssid)) { s/#.*//; s/\s//g; if (/(\S+\@[\w.-]+)/) { $subuser = lc $1; if (/:(.+)/) { $subid = $1 } else { $subid = randstring(8) } print {$idf} "$subuser:$subid\n"; $skey = mkskey($user,$subuser,$subid); print " \n"; } } pq(qq( "
    $subuser :", "$fup?skey=$skey
    \n

    " "You have to give these URLs to your subusers for fexing files to you." "
    " "Or click on the subuser's e-mail address link to send him an" "information e-mail by the F*EX server.

    " )); } print "back to F*EX operation control\n"; print "\n"; close $idf; exit; } if (open my $subuser,'<',"$user/\@SUBUSER") { local $/; $ssid = <$subuser> || ''; close $subuser; } # display HTML form and request user data pq(qq( '

    ' ' ' )); # pq(qq( # ' ' # ' ' # ' Your F*EX account: $user:$id

    ' # ' New auth-ID: ' # ' (Remember your auth-ID when you change it!)' # )); if (-s "$user/\@ALLOWED_RECIPIENTS") { pq(qq( '

    ' ' ' '

    ' '' )); exit; } if ($ssid) { $ssid = html_quote(strip($ssid)); } pq(qq( '


    ' ' Allow special senders (= subusers) to fex files to you:
    ' '
    ' ' ' '' '

    ' '' ' ' ' ' '
    This list has entries in format:<e-mail address>:<encryption-ID>
    Example:framstag\@rus.uni-stuttgart.de:schwuppdiwupp
    ' '

    ' 'These special senders may fex files only to you!
    ' 'It is not necessary to add regular fex users to your list,' 'because they already can fex.' '

    ' 'The encryption-ID is necessary to generate a unique upload URL for this subuser.
    ' 'If you omit the encryption-ID a random one will be used.' )); unless ($nomail) { pq(qq( '


    ' '

    ' 'Edit your F*EX groups:

    ' '
      ' )); foreach $group (glob "$user/\@GROUP/*") { if (-f $group and not -l $group and $group !~ /~$/) { $group =~ s:.*/::; print "
    • \@$group\n"; } } pq(qq( '
    • new group' '
    ' )); } pq(qq( '


    ' 'back to F*EX operation control' '' )); exit; sub strip { local $_ = shift; s/[ \t]+//g; s/\s*[\r\n]+\s*/\n/g; return $_; } sub notify_otuser { my ($user,$otuser,$url,$comment) = @_; my $server = $hostname || $mdomain; my $sf; return if $nomail; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; $sf = $sender_from ? $sender_from : $user; open my $mail,'|-',$sendmail,'-f',$sf,$otuser,$bcc or http_die("cannot start sendmail - $!\n"); pq($mail,qq( 'From: $sf ($user via F*EX service $server)' 'To: $otuser' 'Subject: Your upload URL' 'X-Mailer: F*EX' 'Content-Type: text/plain; charset=utf-8' 'Content-Transfer-Encoding: 8bit' '' 'This is an automatically generated e-mail.' '' 'Use' '' '$url' '' 'to upload one file to $user' '' '$comment' '' 'Questions? ==> F*EX admin: $admin' )); close $mail or http_die("cannot send notification e-mail (sendmail error $!)\n"); } sub notify_subuser { my ($user,$subuser,$url,$comment) = @_; my $server = $hostname || $mdomain; my $sf; return if $nomail; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; $sf = $sender_from ? $sender_from : $user; open my $mail,'|-',$sendmail,'-f',$sf,$subuser,$user,$bcc or http_die("cannot start sendmail - $!\n"); pq($mail,qq( 'From: $sf ($user via F*EX service $server)' 'To: $subuser' 'Cc: $user' 'Subject: Your F*EX account on $server' 'X-Mailer: F*EX' 'Content-Type: text/plain; charset=utf-8' 'Content-Transfer-Encoding: 8bit' '' 'This is an automatically generated e-mail.' '' 'A F*EX (File EXchange) account has been created for you on $server' 'Use' '' '$url' '' 'to upload files to $user' '' 'See http://$ENV{HTTP_HOST}/index.html for more information about F*EX.' '' '$comment' '' 'Questions? ==> F*EX admin: $admin' )); close $mail or http_die("cannot send notification e-mail (sendmail error $!)\n"); } sub notify_groupmember { my ($user,$gm,$group,$id,$url) = @_; my $server = $hostname || $mdomain; my $sf; $user .= '@'.$mdomain if $mdomain and $user !~ /@/; $sf = $sender_from ? $sender_from : $user; open my $mail,'|-',$sendmail,'-f',$sf,$gm,$user,$bcc or http_die("cannot start sendmail - $!\n"); pq($mail,qq( 'From: $sf ($user via F*EX service $hostname)' 'To: $gm' 'Cc: $user' 'Subject: Your F*EX account on $server' 'X-Mailer: F*EX' '' 'A F*EX (File EXchange) account has been created for you on $server' 'Use' '' '$url' '' 'to upload files to F*EX group "$group"' '' 'See http://$ENV{HTTP_HOST}/index.html for more information about F*EX.' '' 'Questions? ==> F*EX admin: $admin' )); close $mail or http_die("cannot send notification e-mail (sendmail error $!)\n"); } sub mkskey { my ($user,$subuser,$id) = @_; my $skey = md5_hex("$user:$subuser:$id"); open my $skf,'>',"$skeydir/$skey" or die "$skeydir/$skey - $!\n"; print {$skf} "from=$subuser\n", "to=$user\n", "id=$id\n"; close $skf or die "$skeydir/$skey - $!\n"; mkdirp("$subuser/\@MAINUSER"); symlink $skey,"$subuser/\@MAINUSER/$user"; return $skey; } sub mkgkey { my ($user,$group,$gm,$id) = @_; my $gkey = untaint(md5_hex("$user:$group:$gm:$id")); open my $gkf,'>',"$gkeydir/$gkey" or die "$gkeydir/$gkey - $!\n"; print {$gkf} "from=$gm\n", "to=\@$group\n", "user=$user\n", "id=$id\n"; close $gkf or die "$gkeydir/$gkey - $!\n"; return $gkey; } sub handle_group { my ($gf,$gd,$gl,$gid,$gkey); $group =~ s/^@+//; $group =~ s:[/&<>]::g; # $notify is group member if ($notify) { $gf = untaint("$notify/\@GROUP/$group"); unless ($_ = readlink $gf) { pq(qq( '

    ERROR: cannot read $gf - $!

    ' '' )); exit; } if (m{([^/]+\@[\w.-]+)/}) { $user = lc $1; } else { pq(qq( '

    INTERNAL ERROR: groupfile = $gf

    ' '' )); exit; } if (open $gf,'<',$gf) { while (<$gf>) { if (/\Q$notify\E:(\S+)/i) { $gid = $1; last; } } close $gf; } else { pq(qq( '

    ERROR: cannot open $gf - $!

    ' '' )); exit; } unless ($gid) { pq(qq( '

    ERROR: $notify not found in $gf

    ' '' )); exit; } $gkey = untaint(md5_hex("$user:$group:$notify:$gid")); notify_groupmember( $user, $notify, $group, $gid, # "$ENV{PROTO}://$ENV{HTTP_HOST}/fup?from=$notify&to=\@$group" "$fup?gkey=$gkey" ); pq(qq( '

    Notification e-mail to $notify has been sent

    ' '

    Go back' '' )); exit; } $gf = untaint("$user/\@GROUP/$group"); if (defined $gm) { if ($gm =~ /\S/) { foreach (split /\n/,$gm) { s/#.*//; s/\s//g; next if /^\w+=./; next if /^$/; if (s/:.+//) { if (/(.+@[\w\.-]+)/ and checkaddress($_)) { push @gm,lc $1; } else { push @badaddress,$_; } } else { push @badformat,$_; } } if (@badformat) { print "

    ERROR: lines not in format <e-mail address>:<encryption-ID>

    \n
      "; foreach my $ba (@badformat) { print "
    • $ba" } print "
    \n"; } if (@badaddress) { print "

    ERROR: bad addresses:

    \n
      "; foreach my $ba (@badaddress) { print "
    • $ba" } print "
    \n"; } if (@badformat or @badaddress) { pq(qq( 'Go back' '' )); exit; } $gd = "$user/\@GROUP"; unless (-d $gd or mkdir $gd,0700) { print "

    ERROR: cannot create $gd - $!

    \n"; print "\n"; exit; } if (-l $gf) { if ($_ = readlink $gf and m{([^/]+\@[\w.-]+)/}) { $user = $1; pq(qq( '

    ERROR: you are already in group \@$group owned by $user

    ' 'Go back' 'and enter another group name' '' )); } else { print "

    INTERNAL ERROR: $gf is a symlink. but not readable

    \n"; print "\n"; } exit; } # delete old gkeys if (open $gf,'<',$gf) { # delete old group links and gkeys while (<$gf>) { s/#.*//; if (/(.+\@.+):(.+)/) { $gkey = untaint(md5_hex("$user:$group:$1:$2")); unlink "$gkeydir/$gkey"; unlink "$1/\@GROUP/$group" if -l "$1/\@GROUP/$group"; } } close $gf; } # write new group file and gkeys if (open $gf,'>',$gf) { $gm =~ s/[\r\n]+/\n/g; foreach (split /\n/,$gm) { print {$gf} "$_\n"; s/#.*//; s/\s//g; if (/^\s*([^\/]+):(.+)/) { mkgkey(lc $user,$group,lc $1,$2); } } close $gf; } else { print "

    ERROR: cannot write $gf - $!

    \n"; print "\n"; exit; } if (@gm) { foreach $gm (@gm) { next if $gm eq $user; unless (-d $gm or mkdir $gm,0700) { print "

    ERROR: cannot create $gm - $!

    \n"; print "\n"; exit; } $gd = "$gm/\@GROUP"; unless (-d $gd or mkdir $gd,0700) { print "

    ERROR: cannot create $gd - $!

    \n"; print "\n"; exit; } $gl = "$gm/\@GROUP/$group"; unless (-l $gl or symlink "../../$user/\@GROUP/$group",$gl) { print "

    ERROR: cannot create $gl - $!

    \n"; print "\n"; exit; } } pq(qq( '

    Group \@$group has members:

    ' '
      ' )); foreach $gm (@gm) { if ($gm ne $user) { print "
    • $gm\n"; } } pq(qq( '
    ' '(click address to send a notification e-mail to this user)' )); } else { print "

    Group \@$group has no members

    \n"; } pq(qq( '

    ' 'back to F*EX operation control' )); print "\n"; exit; } else { # no group members -> delete group file unlink $gf; } } else { $gm = ''; pq(qq( '

    Edit F*EX group

    ' 'A F*EX group is similar to a mailing list, but for files:
    ' 'When a member fexes a file to this list, ' 'then all other members will receive it.' '

    ' '

    ' ' ' )); if ($group eq 'NEW') { pq(qq( ' ' ' New group name: (You MUST fill out this field!)' ' ' )); $gm = $user.':'.randstring(8); } else { if (open $gf,'<',$gf) { local $/; $gm = <$gf>||''; } close $gf; pq(qq( ' ' ' F*EX group \@$group:' )); } my $rows = ($gm =~ tr/\n//) + 5; pq(qq( '

    ' ' ' '
    ' '

    ' '' ' ' ' ' '
    This list must have entries in format:<e-mail address>:<encryption-ID>
    Example:framstag\@rus.uni-stuttgart.de:schwuppdiwupp
    ' '

    ' 'The encryption-ID is necessary to generate a unique upload URL for this subuser.' 'You can name any existing e-mail address.' )); if (open my $ab,'<',"$user/\@ADDRESS_BOOK") { pq(qq( "


    " "

    Your address book:

    " "
    "
          ));
          while (<$ab>) {
            s/#.*//;
            print "$1\n" if /([\S]+\@[\S]+)/;
          }
          close $ab;
          print "
    \n"; } print "\n"; exit; } } fex-20160919/cgi-bin/foc0000755000174700017470000001650612624116560012733 0ustar fexfex#!/usr/bin/perl -wT # FEX CGI for (user) operation control # # Author: Ulli Horlacher # BEGIN { ($ENV{PERLINIT}||'') =~ /(.+)/s and eval $1 } use utf8; use Fcntl qw(:flock); use Digest::MD5 qw(md5_hex); # add fex lib ($FEXLIB) = $ENV{FEXLIB} =~ /(.+)/; die "$0: no $FEXLIB\n" unless -d $FEXLIB; our ($FEXHOME,$mdomain,$nomail,$faillog); our $akey = ''; # load common code, local config : $HOME/lib/fex.ph require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n"; my $error = 'F*EX operation control ERROR'; chdir $spooldir or die "$spooldir - $!\n"; $akeydir = "$spooldir/.akeys"; $user = $id = ''; # look for CGI parameters our %PARAM; &parse_parameters; foreach my $v (keys %PARAM) { my $vv = $PARAM{$v}; # debuglog("Param: $v=\"$vv\""); if ($v =~ /^akey$/i and $vv =~ /^(\w+)$/) { $akey = $1; } elsif ($v =~ /^(from|user)$/i) { $user = normalize_email($vv); $user .= '@'.$mdomain if $mdomain and $user !~ /@/; } elsif ($v =~ /^id$/i) { $id = checkchars($vv); } } if ($akey and not $user and not $id) { if (open $akey,'<',"$akeydir/$akey/@" and $id = getline($akey)) { close $akey; $user = readlink "$akeydir/$akey" or http_die("internal server error: no $akey symlink"); $user =~ s:.*/::; $user = untaint($user); if ($akey ne md5_hex("$user:$id")) { $user = $id = ''; } } } $head = "$ENV{SERVER_NAME} F*EX operation control"; # display HTML form and request user data if ($user and $id) { my $idf; unless (open $idf,'<',"$user/@") { faillog("user $from, id $id"); html_error($error,"wrong user or auth-ID"); } &check_status($user); if (-e "$user/\@CAPTIVE") { html_error($error,"captive user") } $rid = getline($idf); close $idf; if ($id eq $rid) { unless ($akey) { $akey = untaint(md5_hex("$user:$id")); unlink "$akeydir/$akey"; symlink "../$user","$akeydir/$akey"; } } else { faillog("user $from, id $id"); html_error($error,"wrong user or auth-ID"); } unlink $faillog if $faillog; http_header("200 OK"); print html_header($head); # authorized login URL my $url = "$ENV{PROTO}://$ENV{HTTP_HOST}/fup/".b64("from=$user&id=$id"); pq(qq( '' '

    for user $user

    ' '' )); ($quota,$du) = check_sender_quota($user); if ($quota) { pq(qq( )); } ($quota,$du) = check_recipient_quota($user); if ($quota) { pq(qq( )); } pq(qq( '
    sender quota (used):$quota ($du) MB
    recipient quota (used):$quota ($du) MB
    ' '


    ' '' 'Retrieve a list of all your received files in F*EX spool.' )); pq(qq( '


    ' '

    ' ' ' ' ' ' ' ' Change your auth-ID to' ' ' ' ' )); if (-s "$user/\@ALLOWED_RECIPIENTS") { # pq(qq( # ' (You are a restricted user)'; # '

    ' # )); # '


    ' # '' # 'Show download URLs of files you have sent.' unless ($nomail) { pq(qq( '


    ' '' 'Resend notification e-mails for files you have sent.' )); } } else { pq(qq( '


    ' '' 'Forward a copy of a file you already have uploaded to another recipient.' '


    ' '' 'Redirect files you have uploaded to a wrong or misspelled recipient.' )); unless ($nomail) { pq(qq( '


    ' '' 'Resend notification e-mails for files you have sent.' )); } pq(qq( '


    ' ' Create a subuser who can send you files. Enter his e-mail address:
    ' ' ' ' for only one upload
    ' )); if ($nomail) { pq(qq( ' ' )); } else { pq(qq( ' Comment to send with information e-mail:
    ' '
    ' ' ' )); } pq(qq( '


    ' ' Manage your subusers and groups' '


    ' ' Edit your address book' )); pq(qq( '


    ' ' ' ' Change the disclaimer to be sent with notification e-mail.' )); } pq(qq( '


    ' ' ' ' (De)activate e-mail encryption.' )) if -s "$ENV{HOME}/.gnupg/pubring.gpg"; if ((readlink "$user/\@NOTIFICATION"||'') =~ /short/i) { pq(qq( '


    ' ' Get detailed notification e-mails (current setting: brief).' )); } else { pq(qq( '


    ' ' Get brief notification e-mails (current setting: detailed).' )); } if ((readlink "$user/\@REMINDER"||'') =~ /no/i) { pq(qq( '


    ' ' Get reminder notification e-mails (current setting: no reminders).' )); } else { pq(qq( '


    ' ' Get no reminder notification e-mails (current setting: send reminders).' )); } if (-e "$user/\@MIME") { pq(qq( '


    ' ' Save files after download (current setting: display).' )); } else { pq(qq( '


    ' ' Display files when downloading with web browser (current setting: save).' )); } pq(qq( '


    ' ' Back to fup (upload page)' '

    ' )); print &logout; print "\n"; exit; } my $login = -x "$FEXHOME/login" ? 'login' : 'fup'; nvt_print( "HTTP/1.1 302 Found", "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/$login", 'Expires: 0', 'Content-Length: 0', '' ); &reexec; fex-20160919/cgi-bin/fac0000755000174700017470000006510712770010174012712 0ustar fexfex#!/usr/bin/perl -Tw # F*EX CGI for administration # # Original author: Andre Hafner # BEGIN { ($ENV{PERLINIT}||'') =~ /(.+)/s and eval $1 } $| = 1; $fac = $0; $fac =~ s:.*/::; # add fex lib (our $FEXLIB) = $ENV{FEXLIB} =~ /(.+)/ or die "no \$FEXLIB\n"; # import from fex.pp and fex.ph our ($FEXHOME,$spooldir,$logdir,$docdir,$akeydir,$durl,$mdomain,$bs,$hostname); our ($keep_default,$keep_max,$recipient_quota,$sender_quota,$autodelete); our ($admin,$admin_pw,$admin_hosts); our ($sendmail,$bcc); our $error = 'FAC error'; # load common code, local config : $HOME/lib/fex.ph require "$FEXLIB/fex.pp"; my @http_auth = (); my $ra = $ENV{REMOTE_ADDR}||0; if (not @admin_hosts or not ipin($ra,@admin_hosts)) { html_error($error,"Administration from your host ($ra) is not allowed."); } html_error($error,"\$admin not configured in $FEXLIB/fex.ph\n") unless $admin; chdir $spooldir or http_die("$spooldir - $!"); chomp($admin_pw = slurp("$admin/@")||''); html_error($error,"no F*EX account for admin $admin\n") unless $admin_pw; # redirect to https if configured (undef,$port) = split(':',$ENV{HTTP_HOST}||''); $port ||= $ENV{PROTO} eq 'https' ? 443 : 80; if ($port == 80 and open my $x,'/etc/xinetd.d/fexs') { while (<$x>) { if (/^\s*disable\s*=\s*no/) { nvt_print( "HTTP/1.1 301 Moved Permanently", "Location: https://$hostname$ENV{REQUEST_URI}", 'Content-Length: 0', '' ); exit; } } close $x; } our %PARAM; &parse_parameters; $action = $PARAM{"action"}||''; # authentication &require_akey; my $fup = $durl; $fup =~ s:/fop:/fup:; my $http_client = $ENV{HTTP_USER_AGENT} || ''; # files to save with backup function my @backup_files = qw( htdocs/index.html lib/fex.ph lib/fup.pl spool/*@*/@* spool/*@*/.auto ); # backup goes first if ($action eq "backup") { &backup; exit; } http_header('200 OK'); $_ = html_header("F*EX Admin Control for $hostname"); s:: (logout):; print; my $nav_user = "
  • Create new user\n". "
  • Change user auth-ID\n". "
  • Edit user restrictions file\n". "
  • Delete existing user\n". "
  • Manage disk quota\n"; my $nav_log = "
  • Get fup.log\n". "
  • Get fop.log\n". "
  • Get error.log\n"; if (-f "$logdir/fexsrv.log") { $nav_log = "
  • Watch logfile\n". "
  • Get fexsrv.log\n". $nav_log; } my $nav_backup = "
  • Download backup
    (config only)
    \n". "
  • Restore backup\n"; my $nav_show = "
  • List spooled files\n". "
  • Show quotas (sender/recipient)\n". "
  • Show server config\n". "
  • Show user config\n"; my $nav_edit = "
  • Edit config\n". "
  • Edit index.html\n"; pq(qq( '' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
    manage usershowlog fileseditbackup
      $nav_user
    ' '
      $nav_show
    ' '
      $nav_log
    ' '
      $nav_edit
    ' '
      $nav_backup
    ' '
    ' '
    ' )); my @user_items = &userList; if ($action eq "create") { &createUserForm } elsif ($action eq "change-auth") { &changeAuthForm } elsif ($action eq "edit") { &editRestrictionsForm } elsif ($action eq "delete") { &deleteUserForm } elsif ($action eq "quota") { &changeQuotaForm } elsif ($action eq "list") { &listFiles } elsif ($action eq "showquota") { &showQuota } elsif ($action eq "showconfig") { &showConfig } elsif ($action eq "userconfig") { &userConfigForm } elsif ($action eq "watch") { &watchLog } elsif ($action eq "fexsrv.log") { &getlog("fexsrv.log") } elsif ($action eq "fup.log") { &getlog("fup.log") } elsif ($action eq "fop.log") { &getlog("fop.log") } elsif ($action eq "error.log") { &getlog("error.log") } elsif ($action eq "editconfig") { &editFile("$FEXLIB/fex.ph") } elsif ($action eq "editindex") { &editFile("$docdir/index.html") } elsif ($action eq "backup") { &backup } elsif ($action eq "restore") { &restoreForm } if (defined $PARAM{"createUser"}) { createUser($PARAM{"createUser"}, $PARAM{"authID"}); } elsif (defined $PARAM{"changeAuthUser"}) { if ($PARAM{"changeAuthUser"} =~ /^#.*/) { &changeAuthForm; } else { changeUser($PARAM{"changeAuthUser"}, $PARAM{"authID"}); } } elsif (defined $PARAM{"showUserConfig"}) { if ($PARAM{"showUserConfig"} =~ /^#.*/) { &userConfigForm; } else { showUserConfig($PARAM{"showUserConfig"}); } } elsif (defined $PARAM{"deleteUser"}) { if ($PARAM{"deleteUser"} =~ /^#.*/) { &deleteUserForm; } else { deleteUser($PARAM{"deleteUser"}); } } elsif (defined $PARAM{"userQuota"}) { if ($PARAM{"userQuota"} =~ /^#.*/) { &changeQuotaForm; } else { if (defined $PARAM{"default quota"}) { $user = normalize_user($PARAM{"userQuota"}); unlink "$user/\@QUOTA"; print "$user has now default quota:

    \n"; print "recipient quota: $recipient_quota MB
    \n"; print "sender quota: $sender_quota MB
    \n"; &end_html; } else { alterQuota( $PARAM{"userQuota"}, $PARAM{"recipientQuota"}, $PARAM{"senderQuota"} ); } } } elsif (defined $PARAM{"editUser"}) { if ($PARAM{"editUser"} =~ /^#.*/) { &editRestrictionsForm; } else { $user = normalize_user($PARAM{"editUser"}); if (defined $PARAM{"delete file"}) { unlink "$user/\@ALLOWED_RECIPIENTS"; print "upload restrictions for $user have been deleted\n"; &end_html; } else { editUser($user); } } } elsif ($PARAM{"contentBox"} and $PARAM{"ar"}) { saveFile($PARAM{"contentBox"},$PARAM{"ar"}); } elsif ($PARAM{"upload_archive"}) { restore($PARAM{"upload_archive"}{data}); } &end_html; ####### # declaration of formular functions ####### # formular for creating new users # required arguments: - sub createUserForm { print h3("Create new user"); pq(qq( '

    ' '' '' '' '' '' '' '' '
    user
    auth-ID:
    ' '' '
    ' )); &end_html; } # formular for changing auth-id of an user # required arguments: - sub changeAuthForm { my @option = map { "\n" } @user_items; print h3("change auth-ID"); pq(qq( '
    ' '' '' '' '' '' '' '' '
    user:
    new auth-ID:
    ' '' '
    ' )); &end_html; } # formular choosing user, whose config files shall be shown # required arguments: - sub userConfigForm { my @option = map { "\n" } @user_items; print h3("Show user config files"); pq(qq( '
    ' '' '' '' '' '
    user:
    ' '' '
    ' )); &end_html; } # formular for choosing user, whose restriction file shall be edited # required arguments: - sub editRestrictionsForm { my @option = map { "\n" } @user_items; print h3("Edit user restriction file"); pq(qq( '
    ' '' '' '' '' '
    user:
    ' '' '' '
    ' )); &end_html; } # formular for choosing user, who shall be removed # required arguments: - sub deleteUserForm { my @option = map { "\n" } @user_items; print h3("Delete existing user"); pq(qq( '
    ' '' '' '' '' '
    user:
    ' '' '
    ' )); &end_html; } # formular for changing an user's quota file # required arguments: - sub changeQuotaForm { my $user; my @option; my $rquota = ''; my $squota = ''; if ($user = $PARAM{"user"}) { $user = normalize_user($user); $rquota = $1 if ($PARAM{"rquota"}||'') =~ /^(\d+)$/; $squota = $1 if ($PARAM{"squota"}||'') =~ /^(\d+)$/; } foreach (@user_items) { if ($user and $user eq $_) { push @option,"\n"; } else { push @option,"\n"; } } print h3("Manage disk quota"); pq(qq( '
    ' '' '' '' '' '' '' '' '' '' '' '' '' '
    user:
    new quota for recipient:' ' MB (optional)
    new quota for sender:' ' MB (optional)
    ' '' '' '
    ' )); &end_html; } # formular for choosing backup file to restore # required arguments: - sub restoreForm { print h2("restore config"); pq(qq( 'Specify the backup-archive you want to restore:
    ' '
    ' '
    ' '' '
    ' )); &end_html; } ####### # declaration user functions ####### # function for creating new users # required arguments: username, auth-id sub createUser { my ($user,$id) = @_; my $idf; http_die("not enough arguments in createUser") unless $id; $user = normalize_user($user); unless (-d "$user") { mkdir "$user",0755 or http_die("cannot mkdir $user - $!"); } $idf = "$user/@"; if (-f $idf) { html_error($error,"There is already an user $user!"); } open $idf,'>',$idf or http_die("cannot write $idf - $!"); print {$idf} $id,"\n"; close $idf or http_die("cannot write $idf - $!"); print "\n"; printf "%s?from=%s&ID=%s
    \n",$fup,$user,$id; printf "%s/%s

    \n",$fup,b64("from=$user&id=$id"); print "\n"; notifyUser($user,$id); print "An information e-mail to $user has been sent.\n"; &end_html; } # function for changing an user's auth-ID # required arguments: username, auth-id sub changeUser { my ($user,$id) = @_; http_die("not enough arguments in changeUser") unless $id; $id = despace($id); $user = normalize_user($user); my $idf = "$user/@"; print "\n"; print "$idf

    "; open $idf,'>',$idf or http_die("cannot write $idf - $!"); print {$idf} $id,"\n"; close $idf or http_die("cannot write $idf - $!"); printf "%s?from=%s&ID=%s
    \n",$fup,$user,$id; printf "%s/%s\n",$fup,b64("from=$user&id=$id"); print "

    \n"; notifyUser($user,$id,"change-auth"); print "An information e-mail to $user has been sent.\n"; &end_html; } # function for showing an user's config files # required arguments: username sub showUserConfig { my $user = shift; http_die("not enough arguments in showUserConfig!") unless $user; $user = normalize_user($user); chdir "$user" or http_die("could not change directory $user - $!"); print h2("Config files of $user"); foreach my $file (glob('.auto @* @GROUP/*')) { if (-f $file and not -l $file and $file !~ /.*~$/) { print h3($file), "\n"; open $file,'<',$file or http_die("cannot open $file - $!"); # print "
    \n"; dumpfile($file); # print "
    \n"; close $file; } } &end_html; } # function for editing an user's recipient/sender restrictions # required arguments: username sub editUser { my $user = shift; my $content; http_die("not enough arguments in editUser") unless $user; $user = normalize_user($user); http_die("no user $user") unless -d $user; my $ar = "$user/\@ALLOWED_RECIPIENTS"; unless (-f $ar) { open $ar,'>',$ar or http_die("cannot open $ar - $!"); print {$ar}<<'EOD'; # Restrict allowed recipients. Only those listed here are allowed. # Make this file COMPLETLY empty if you want to disable the restriction. # An allowed recipient is an e-mail address, you can use * as wildcard. # Example: *@flupp.org EOD close $ar; } $content = dehtml(slurp($ar)); pq(qq( 'Edit restrictions file for user $user :
    ' '

    ' '
    ' '' '' '
    ' )); &end_html; } # function for deleting files # required arguments: list of Files sub deleteFiles { http_die("not enough arguments in deleteFiles") unless (my @files = @_); foreach (@files) { if (-e) { if (unlink $_) { print "file has been deleted: $_
    \n"; } else { print "file could not be deleted: $_ - $!
    \n"; } } else { print "file does not exists: $_
    \n"; } } &end_html; } # function for saving a single file # required arguments: content, location sub saveFile { my ($rf,$ar) = @_; my $new; http_die("not enough arguments in saveFile") unless $ar; if ($ar eq 'index.html') { $ar = "$docdir/index.html" } elsif ($ar eq 'fex.ph') { $ar = "$FEXLIB/fex.ph" } elsif ($ar =~ m'^([^/]+/\@ALLOWED_RECIPIENTS)$') { $ar = $1; } else { http_die("unknown file $ar") } $new = $ar.'_new'; if ($ar =~ /fex.ph$/) { open $new,'>',$new or http_die("cannot open ${ar}_new - $!"); print {$new} $rf; close $new or http_die("cannot write $new - $!");; my $status = dehtml(`perl -c $FEXLIB/fex.ph_new 2>&1`); if ($status =~ /syntax OK/ ) { rename $ar,"$ar~"; rename $new,$ar; http_die("cannot write $ar~ - $!") if $?; } else { rename "$ar~",$ar; pq(qq( 'No valid syntax in configuration file:' '

    $status

    ' 'back' )); &end_html; } } else { system 'mv',$ar,"$ar~"; } $rf =~ s/^\s+$//; open $ar,'>',$ar or http_die("cannot write $ar - $!"); print {$ar} $rf; close $ar or http_die("cannot write $ar - $!");; print "$ar has been saved\n"; &end_html; } # function for deleting existing user # required arguments: username sub deleteUser { my $user = shift; http_die("not enough arguments in deleteUser") unless $user; $user = normalize_user($user); $idf = "$user/\@"; http_die("no such user $user") unless -f $idf; unlink $idf or http_die("cannot remove $idf - $!"); unlink "$user/\@ALLOWED_RECIPIENTS"; unlink "$user/\@SUBUSER"; rmrf("$user/\@GROUP"); print "$user deleted\n"; &end_html; } # function for saving quota information for one single user # required arguments: username, recipient-quota, sender-quota sub alterQuota { my ($user,$rq,$sq) = @_; my ($rquota,$squota); my $qf; $user = normalize_user($user); http_die("$user is not a F*EX user") unless -d $user; $rquota = $squota = ''; $qf = "$user/\@QUOTA"; if (open $qf,$qf) { while (<$qf>) { s/#.*//; $rquota = $1 if /recipient.*?(\d+)/i; $squota = $1 if /sender.*?(\d+)/i; } close $qf; } $rquota = $1 if $rq and $rq =~ /(\d+)/; $squota = $1 if $sq and $sq =~ /(\d+)/; open $qf,'>',$qf or http_die("cannot write $qf - $!"); print {$qf} "recipient:$rquota\n" if $rquota; print {$qf} "sender:$squota\n" if $squota; close $qf or http_die("cannot write $qf - $!"); $rquota = $recipient_quota unless $rquota; $squota = $sender_quota unless $squota; print h3("New quotas for $user"); print "recipient quota: $rquota MB
    \n"; print "sender quota: $squota MB
    \n"; &end_html; } # function for listing f*exed files # required arguments: - sub listFiles { print h3("List current files"); my ($file,$dkey); print "

    \n";
      foreach $recipient (glob "*@*") {
        next if -l $recipient;
        foreach $file (glob "$recipient/*/*") {
          if (-s "$file/data" and  $dkey = readlink("$file/dkey") and -l ".dkeys/$dkey") {
            ($to,$from,$file) = split "/",$file;
            $file = html_quote($file);
            print "$from → $to : $durl/$dkey/$file\n";
          }
        }
      }
      print "
    \n"; &end_html; } # function for watching the fex-logfile # required arguments: - sub watchLog { if (-f "$logdir/fexsrv.log") { print h2("polling fexsrv.log"),"\n"; open my $log,"$FEXHOME/bin/logwatch|" or http_die("cannot run $FEXHOME/bin/logwatch - $!"); dumpfile($log); } else { print h2("no fexsrv.log"); } &end_html; } # function for showing logfiles # required arguments: logfile-name sub getlog { my $log = shift or http_die("not enough arguments in getLog"); print h2("show $log"); if (open $log,"$logdir/$log") { dumpfile($log); close $log; } else { http_die("cannot open $logdir/$log - $!"); } &end_html; } # function for creating a new backup file # required arguments: - sub backup { my @d = localtime time; my $date = sprintf('%d%02d%02d',$d[5]+1900,$d[4]+1,$d[3]); my $backup = "backup/config-$date.tar"; my $http_client = $ENV{HTTP_USER_AGENT} || ''; my $size; my $home = $FEXHOME; $home = $1 if $ENV{VHOST} and $ENV{VHOST} =~ /:(.+)/; chdir $home or http_die("$home - $!"); unless (-d "backup") { mkdir "backup",0700 or http_die("cannot mkdir backup - $!"); } system "tar -cf $backup @backup_files 2>/dev/null"; $size = -s $backup or http_die("backup file empty"); open $backup,'<',$backup or http_die("cannot open $backup - $!"); nvt_print( 'HTTP/1.1 200 OK', "Content-Length: $size", "Content-Type: application/octet-stream; filename=fex-backup-$date.tar", "Content-Disposition: attachment; filename=\"fex-backup-$date.tar\"", "", ); while (read($backup,my $b,$bs)) { print $b or last; } exit; } # function for restoring an old configuration file # required arguments: uploaded archive sub restore { my $archive_file = shift or http_die("not enough arguments in restore!"); my $restore = "backup.tar"; my $home = $FEXHOME; $home = $1 if $ENV{VHOST} and $ENV{VHOST} =~ /:(.+)/; chdir $home or http_die("$home - $!"); mkdir 'backup'; open $restore,'>',$restore or http_die("cannot open $restore - $!"); print {$restore} $archive_file; close $restore or http_die("cannot write $restore - $!"); if (-s $restore) { print "file upload successful
    \n"; print "saving actual config in $home/backup/config.tar
    \n"; print "
    \n";
        system "tar -cf backup/config.tar @backup_files";
        print "
    \n"; print "starting restore:\n

    \n"; print "

    \n";
        system "tar -xvf $restore";
        unlink $restore;
        &end_html;
      } else {
        http_die("upload error - no file data received");
      }
    }
    
    # function for editing a text-file
    # required arguments: filepath, filename
    sub editFile {
      my $ar = shift;
      my $file;
    
      $file = dehtml(slurp($ar));
    
      $ar =~ s:.*/::;
    
      print h2("edit $ar");
    
      pq(qq(
        '
    ' '
    ' '' '' '
    ' )); &end_html; } # function for showing all users' quotas # required arguments: - sub showQuota { print h2("Show quotas (domain sorted, values in MB)"); print ""; foreach (@user_items) { if (/\#\#\#\s(\S+)/) { print ""; print ""; print ""; print ""; print ""; print ""; print "\n"; # $table = $_; } else { my $rquota = $recipient_quota; my $squota = $sender_quota; my $rquota_used = 0; my $squota_used = 0; my $user = $_; ($squota,$squota_used) = check_sender_quota($user); ($rquota,$rquota_used) = check_recipient_quota($user); my $action = "quota&user=$user&rquota=$rquota&squota=$squota"; s/\@.*//; print ""; print ""; print ""; print ""; print ""; print ""; print "\n"; } } print "
    \@$1sendersender (used)recipientrecipient (used)
    $_$squota$squota_used$rquota$rquota_used
    \n"; &end_html; } # function for showing fex-server configuration # required arguments: - sub showConfig { print h3("Show config"); print "\n"; printf "\n",$spooldir; printf "\n",$logdir; printf "\n",$docdir; printf "\n",$durl; printf "\n",$mdomain||''; printf "\n",$autodelete; printf "\n",$keep_default; printf "\n",$keep_max; printf "\n",$recipient_quota; printf "\n",$sender_quota; printf "\n",$admin; print "
    spooldir:%s
    logdir:%s
    docdir:%s
    durl:%s
    mdomain:%s
    autodelete:%s
    keep:%s
    keep_max:%s
    recipient_quota:%s
    sender_quota:%s
    admin:%s
    \n"; &end_html; } # require authentification sub require_akey { my $id; my $rid; if ($action eq 'logout') { if (($ENV{HTTP_COOKIE}||'') =~ /akey=(\w+)/) { unlink "$akeydir/$1"; } nvt_print( "HTTP/1.1 301 Moved Permanently", "Location: /$fac", 'Content-Length: 0', "Set-Cookie: akey=; Max-Age=0; Discard", '' ); &reexec; } $rid = slurp("$admin/@") or html_error($error,"no F*EX account for $admin"); chomp $rid; $id = $PARAM{"id"}; if ($id) { # correct auth-ID? if ($id eq $rid) { $akey = md5_hex("$admin:$rid"); return; } } elsif ($akey) { # correct akey? return if $akey eq md5_hex("$admin:$rid"); } http_header('200 OK'); print html_header("F*EX Admin Control for $hostname"); if ($akey) { pq(qq( '

    ' ' wrong akey for $admin' '

    ' )); } if ($id and $id ne $rid) { pq(qq( '

    ' ' wrong auth-ID for $admin' '

    ' )); } pq(qq( '
    ' ' auth-ID for $admin:' ' ' '
    ' )); &end_html; } # function for checking simple HTTP authentication # (not used any more, replaced with require_akey) sub require_auth { if ($ENV{HTTP_AUTHORIZATION} and $ENV{HTTP_AUTHORIZATION} =~ /Basic\s+(.+)/) { @http_auth = split(':',decode_b64($1)) } if ( @http_auth != 2 or $http_auth[0] !~ /^(fexmaster|admin|\Q$admin\E)$/ or $http_auth[1] ne $admin_pw ) { http_header( '401 Authorization Required', "WWW-Authenticate: Basic realm=$admin F*EX admin authentification", 'Content-Length: 0', ); # control back to fexsrv for further HTTP handling &reexec; } } # function for sending notification mails to an user # required arguments: username, auth-id, message-type sub notifyUser { my ($user,$id,$type) = @_; my $url = $durl; my $message = 'A F*EX account has been created for you. Use'; http_die("not enough arguments in createUser") unless $id; if ($type and $type eq "change-auth") { $message = 'New auth-ID for your F*EX account has been set. Use' } $user = normalize_user($user); open my $mail,'|-',$sendmail,'-f',$admin,$user,$bcc or http_die("cannot start sendmail - $!"); $url =~ s:/fop::; pq($mail,qq( 'From: $admin' 'To: $user' 'Subject: your F*EX account on $hostname' 'X-Mailer: F*EX' '' '$message' '' '$url/fup?from=$user' 'auth-ID: $id' '' 'See $url/index.html for more information about F*EX.' '' 'Questions? ==> F*EX admin: $admin' )); close $mail or http_die("cannot send notification e-mail (sendmail error $!)"); } # sort key is the (inverse) domain # required arguments: list of usernames (e-mail addresses) sub domainsort { # http_die("not enough arguments in domainsort") unless (my @d = @_); my @d = @_; local $_; foreach (@d) { s/\s//g; s/\./,/ while /\..*@/; s/@/@./; $_ = join('.',reverse(split /\./)); } @d = sort { lc $a cmp lc $b } @d; foreach (@d) { $_ = join('.',reverse(split /\./)); s/,/./g; s/@\./@/; } return @d; } # function for creating a sorted list of all users # required arguments: - sub userList { my (@u,@list); my $domain = ''; my $u; foreach $u (glob('*@*')) { next if -l $u; push @u,$u if -f "$u/@"; } foreach (domainsort(@u)) { if (/@(.+)/) { if ($1 ne $domain) { push @list,"### $1 ###"; } push @list,$_; $domain = $1; } } return @list; } sub dumpfile { my $file = shift; print "
    \n";
      while (<$file>) { print dehtml($_) }
      print "\n
    \n"; } sub h2 { local $_ = shift; chomp; return "

    $_

    \n"; } sub h3 { local $_ = shift; chomp; return "

    $_

    \n"; } sub end_html { print "\n"; exit; } sub dehtml { local $_ = shift; s/&/&/g; s/ # BEGIN { ($ENV{PERLINIT}||'') =~ /(.+)/s and eval $1 } use utf8; use Fcntl qw(:flock :seek :mode); use Digest::MD5 qw(md5_hex); # add fex lib (our $FEXLIB) = $ENV{FEXLIB} =~ /(.+)/; die "$0: no $FEXLIB\n" unless -d $FEXLIB; our ($keep_default,$dkeydir,$akeydir,$mdomain,@logdir,$fra); our $akey = ''; # load common code, local config : $HOME/lib/fex.ph require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n"; our $error = 'F*EX redirect ERROR'; chdir $spooldir or die "$spooldir - $!\n"; $from = $id = $oto = $nto = $file = ''; # look for CGI parameters our %PARAM; &parse_parameters; foreach my $v (keys %PARAM) { my $vv = $PARAM{$v}; $vv =~ s/[<>\'\`\"\000-\037]//g; if ($v =~ /^akey$/i and $vv =~ /^(\w+)$/) { $akey = $1; } elsif ($v =~ /^(from|user)$/i) { $from = normalize_address($vv); $from .= '@'.$mdomain if $mdomain and $from !~ /@/; } elsif ($v =~ /^id$/i) { $id = despace($vv); } elsif ($v =~ /^file$/i) { $vv =~ s:/:_:g; $file = untaint(normalize($vv)); } elsif ($v =~ /^oto$/i) { $oto = normalize_address($vv); $oto .= '@'.$mdomain if $mdomain and $oto !~ /@/; } elsif ($v =~ /^nto$/i) { $nto = normalize_address($vv); } } if ($akey and not $from) { if (open $akey,'<',"$akeydir/$akey/@" and $id = getline($akey)) { close $akey; $from = readlink "$akeydir/$akey"; $from =~ s:.*/::; $from = untaint($from); if ($akey ne md5_hex("$from:$id")) { $from = $id = ''; } } } if ($from and -s "$from/\@ALLOWED_RECIPIENTS") { http_die("You are a restricted user"); } if ($from and $id) { open F,'<',"$from/@" or http_die("wrong user or auth-ID"); chomp($rid = ); close F; http_die("wrong user or auth-ID") if $id ne $rid; unless ($akey) { $akey = untaint(md5_hex("$from:$id")); unlink "$akeydir/$akey"; symlink "../$from","$akeydir/$akey"; } } else { http_die("wrong user or auth-ID"); } if ($oto and not glob("$oto/$from/*")) { http_die("$oto has no no files in spool from you ($from)"); } # display HTML form and request user data unless ($from and $id and $file and $oto and $nto) { $head = "$ENV{SERVER_NAME} F*EX redirect"; http_header("200 OK"); print html_header($head); pq(qq( '
    ' ' ' )); if ($akey) { print "\n"; } else { pq(qq( ' ' ' ' )); } if ($oto) { pq(qq( ' ' ' ' )); } else { pq(qq( ' ' )); } if ($from and $oto) { pq(qq( ' ' ' \n"; } pq(qq( '
    sender:' '
    auth-ID:' '
    old (wrong) recipient:$oto
    old (wrong) recipient:' '
    new recipient:' '
    filename:
    ' '

    ' ' ' '

    '

    'back to F*EX operation control' '' )); exit; } if ($nto) { # read aliases from address book if (open my $AB,'<',"$from/\@ADDRESS_BOOK") { while (<$AB>) { s/#.*//; $_ = lc $_; if (s/^\s*(\S+)[=\s]+(\S+)//) { my ($alias,$address) = ($1,$2); if ($nto eq $alias) { $nto = $address; last; } } } close $AB; } $nto .= '@'.$mdomain if $mdomain and $nto !~ /@/ and $nto =~ /\w/; checkaddress($nto) or http_die("$nto is not a valid e-mail address"); } else { http_die("no new recipient given"); } if ($oto and $nto and $oto eq $nto) { http_die("new recipient must be other than old recipient"); } $fkey = urlencode($file); unless (-s "$oto/$from/$fkey/data") { http_die("no upload data found for $file for $oto"); } if (not -e "$oto/$from/$fkey/data") { if (my $download = slurp("$oto/$from/$fkey/download")) { chomp $download; http_die("$file already downloaded by $download"); } http_die("$file has gone"); } mkdirp("$nto/$from"); rmrf("$nto/$from/$fkey"); if (rename "$oto/$from/$fkey","$nto/$from/$fkey") { mkdirp("$oto/$from/$fkey"); if (open $fkey,'>',"$oto/$from/$fkey/error") { print {$fkey} "$from has removed $file\n"; close $fkey; } unlink "$nto/$from/$fkey/dkey"; unlink "$nto/$from/$fkey/notify"; unlink "$nto/$from/$fkey/error"; unlink "$nto/$from/$fkey/download"; if (slurp("$oto/$from/$fkey/comment")||'' =~ /NOMAIL/) { unlink "$nto/$from/$fkey/comment"; } $dkey = randstring(8); symlink $dkey,"$nto/$from/$fkey/dkey"; symlink "../$nto/$from/$fkey","$dkeydir/$dkey"; $filename = filename("$nto/$from/$fkey") || $fkey; notify_locale($dkey,'new'); ruplog("$oto/$from/$fkey ==> $nto"); http_header("200 OK"); print html_header('F*EX redirect'); pq(qq( '

    F*EX redirect

    ' 'notification of file upload \"$filename\" sent to $nto' '

    ' 'back to F*EX operation control' '' )); } else { http_die("redirect $nto/$from/$fkey failed : $!") } exit; sub normalize_address { local $_ = shift; s/[<>;,\s\|\/\'\`\"\000-\037]//g; $_ = untaint($_); } # standard log sub ruplog { my $msg = "@_"; $msg =~ s/\n/ /g; $msg =~ s/\s+$//; $msg = sprintf "%s [%s_%s] (%s) %s\n", isodate(time),$$,$ENV{REQUESTCOUNT},$fra,$msg; foreach my $log (@logdir) { if (open $log,'>>',"$log/rup.log") { flock $log,LOCK_EX; seek $log,0,SEEK_END; printf {$log} $msg; close $log; } } } fex-20160919/cgi-bin/fur0000755000174700017470000002611612723400113012744 0ustar fexfex#!/usr/bin/perl -wT # FEX CGI for user registration # # Author: Ulli Horlacher # BEGIN { ($ENV{PERLINIT}||'') =~ /(.+)/s and eval $1 } use utf8; use Fcntl qw(:flock :seek :mode); # import from fex.ph our (@local_hosts,@local_domains,@local_rhosts,@local_rdomains); our (@registration_hosts,@registration_domains); our ($usage_conditions); # import from fex.pp our ($mdomain,@logdir,$spooldir,$fra,$hostname,$sendmail,$admin,$bcc); our $error = "F*EX user registration ERROR"; my $ra = $ENV{REMOTE_ADDR}||0; my ($CASE,$ESAC); # add fex lib (our $FEXLIB) = $ENV{FEXLIB} =~ /(.+)/; die "$0: no $FEXLIB\n" unless -d $FEXLIB; # load common code, local config: $HOME/lib/fex.ph require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n"; my $log = 'fur.log'; my $head = "$ENV{SERVER_NAME} F*EX user registration"; chdir $spooldir or die "$spooldir - $!\n"; my $user = my $id = my $verify = ''; &check_maint; unless (@local_domains or @local_rdomains) { html_error($error, "No domains for registrations are defined.", "Contact $ENV{SERVER_ADMIN} for details." ); } unless (@local_hosts and ipin($ra,@local_hosts) or @local_rdomains and @local_rhosts and (not @registration_hosts or ipin($ra,@registration_hosts))) { html_error($error, "Registrations from your host ($ra) are not allowed.", "Contact $ENV{SERVER_ADMIN} for details." ); } # look for CGI parameters our %PARAM; &parse_parameters; foreach my $v (keys %PARAM) { my $vv = despace($PARAM{$v}); # debuglog("Param: $v=\"$vv\""); $CASE = $v =~ /^user$/i ? $user = normalize_address($vv): $v =~ /^exuser$/i ? $exuser = normalize_address($vv): $v =~ /^demouser$/i ? $demouser = normalize_address($vv): $v =~ /^verify$/i ? $verify = lc(checkchars('URL-parameter',$vv)): $v =~ /^confirm$/i ? $confirm = checkchars('URL-parameter',$vv): $v =~ /^domain$/i ? $domain = lc(checkchars('URL-parameter',$vv)): $ESAC; } if ($confirm) { if ($confirm =~ /^(\w+)$/i) { $confirm = $1; } else { http_die("illegal registration key"); } open $confirm,"<.reg/$confirm" or http_die("no registration key $confirm"); $user = untaint(getline($confirm)); $id = getline($confirm); close $confirm; # unlink ".reg/$confirm"; unless ($user and $id) { http_die("no registration data for key $confirm"); } unless (-f "$user/.auto") { http_die("registration expired"); } # if (-f "$user/@") { http_die("$user is already activated") } open $user,'>',"$user/@" or http_die("open $user/@ - $!\n"); print {$user} $id,"\n"; close $user or http_die("close $user/@ - $!\n"); http_header("200 OK"); print html_header($head); my $url = "$ENV{PROTO}://$ENV{HTTP_HOST}/fup/" . b64("from=$user&id=$id"); pq(qq( '

    Your registration was successful. Your new F*EX account is:

    ' '

    ' '$url' '

    ' '(bookmark this URL!)' '

    ' 'or you can use:' '

    ' '' ' ' ' ' ' ' '
    URL:$ENV{PROTO}://$ENV{HTTP_HOST}/fup/
    Sender:$user
    auth-ID:$id
    ' '' )); furlog("confirm: account $user created"); exit; } unless ($user or $exuser or $demouser) { http_header("200 OK"); print html_header($head); pq(qq( '

    ' )); if (@local_domains and @local_hosts and ipin($ra,@local_hosts)) { $reg = $ra; if (grep(/\*/,@local_domains)) { pq(qq( ' new user (may send to internal or external users):
    ' ' ' '

    ' ' allowed domains are:' '

    '
          ));
          foreach my $ld (@local_domains) {
            print "  $ld\n";
          }
          print "
    \n"; } else { if ($mdomain and not grep /^\Q$mdomain\E$/i,@local_domains) { unshift @local_domains,$mdomain; } my @mydomains = map { "\t\n" } @local_domains; pq(qq( ' new user (may send to internal or external users):
    ' ' \@' )); } } if (@local_rdomains and @local_rhosts and (not @registration_hosts or ipin($ra,@registration_hosts))) { print "

    or

    \n" if $reg; $reg = $ra; pq(qq( ' new external user (may send only to internal users):
    ' ' ' '

    ' )); } if (@demo) { print "

    or

    \n" if $reg; $reg = $ra; local $_ = sprintf "with %d MB quota and %d day%s account life time", @demo,$demo[1]>1 ? 's' : ''; pq(qq( ' new demo user ($_):
    ' ' ' '

    ' )); } if ($reg) { pq(qq( '

    ' ' you must enter your e-mail address and ' '

    ' '

    ' )); if (@local_rdomains) { pq(qq( '


    ' 'internal domains are:' '

    '
          ));
          foreach my $lrd (@local_rdomains) {
            print "  $lrd\n";
          }
        }
        pq(qq(
          '
    ' '


    ' 'User types overview' '' )); } else { html_error($error, "Registrations from your host ($ra) are not allowed.", "Contact $ENV{SERVER_ADMIN} for details." ); } exit; } if ($exuser) { unless (@local_rdomains) { http_die("no \@local_rdomains"); } if (@registration_hosts and not ipin($ra,@registration_hosts)) { html_error($error, "Registrations from your host ($ra) are not allowed.", "Contact $ENV{SERVER_ADMIN} for details." ); } if ($exuser =~ /\@(.+)/) { my $exd = $1; if (@registration_domains and not grep /^\Q$exd\E$/i,@registration_domains) { html_error($error, "Your domain $exd is not allowed for registration.", "Contact $ENV{SERVER_ADMIN} for details." ); } } else { html_error($error,"$exuser is not an email address"); } $user = $exuser; } elsif ($demouser) { $user = $demouser; } elsif ($user) { unless (@local_domains) { html_error($error, "No local domains for registration are defined.", "Contact $ENV{SERVER_ADMIN} for details." ); } my $mydomains = join('|',@local_domains); $mydomains =~ s/\./\\./g; $mydomains =~ s/\*/.*/g; $mydomains .= "|$mdomain" if $mdomain; $user .= '@'.$domain if $domain and $user !~ /@/; # $user .= '@'.$mdomain if $mdomain and $user !~ /@/; unless (@local_hosts and ipin($ra,@local_hosts)) { html_error($error, "Registrations from your host ($ra) are not allowed.", "Contact $ENV{SERVER_ADMIN} for details." ); } if ("@local_domains" ne "*" and $user !~ /\@($mydomains)$/i) { html_error($error, "Illegal domain for username.", "Contact $ENV{SERVER_ADMIN} for details." ); } } else { html_error($error,"No user type found."); } unless (checkforbidden($user)) { html_error($error,"$user is not allowed"); } unless (checkaddress($user)) { html_error($error,"$user is not a valid e-mail address"); } $user = untaint($user); if (-f "$user/@") { html_error( $error, "you are already registered". " (I have lost my auth-ID)" ); } unless (-d $user) { mkdir $user,0770 or http_die("mkdir $user - $!\n"); } if ($exuser) { my $rf; # recipients e-mail address restrictions $rf = "$exuser/\@ALLOWED_RECIPIENTS"; open $rf,'>',$rf or http_die("cannot write $rf - $!\n"); print {$rf} "\@LOCAL_RDOMAINS\n"; print {$rf} "# See also file \@ALLOWED_RHOSTS\n"; close $rf; # recipients ip restrictions $rf = "$exuser/\@ALLOWED_RHOSTS"; open $rf,'>',$rf or http_die("cannot write $rf - $!\n"); print {$rf} "\@LOCAL_RHOSTS\n"; close $rf; if (open $user,'>',"$user/.auto") { print {$user} "fur:external\n"; close $user; } } elsif ($demouser) { my $quota = "$demouser/\@QUOTA"; open $quota,'>',$quota or http_die("cannot write $quota - $!\n"); printf {$quota} "recipient:%d\n",$demo[0]; printf {$quota} "sender:%d\n",$demo[0]; close $quota; if (open $user,'>',"$user/.auto") { print {$user} "fur:demo\n"; close $user; } open $demouser,'>',"$demouser/.demo" and close $demouser; } else { if (open $user,'>',"$user/.auto") { print {$user} "fur:internal\n"; close $user; } } $id = randstring(6); if ("@local_domains" eq "*") { open $id,'>',"$user/@" or http_die("open $user/@ - $!\n"); print {$id} $id,"\n"; close $id or http_die("close $user/@ - $!\n"); http_header("200 OK"); print html_header($head); $uid = "from=$user&id=$id"; $b64 = b64($uid); pq(qq( 'Account created:' '

    '
        '$ENV{PROTO}://$ENV{HTTP_HOST}/fup?$uid'
        '$ENV{PROTO}://$ENV{HTTP_HOST}/fup/$b64'
        '
    ' '' )); exit; } # from fexsend if ($verify eq 'no') { open $id,'>',"$user/@" or http_die("open $user/@ - $!\n"); print {$id} $id,"\n"; close $id or http_die("close $user/@ - $!\n"); http_header("200 OK",'Content-Type: text/plain'); print "$ENV{PROTO}://$ENV{HTTP_HOST}/fup?from=$user&ID=$id\n"; furlog("direct: account $user created"); if ($bcc and open my $mail,"|$sendmail '$bcc' 2>>$logdir[0]/$log") { pq($mail,qq( 'From: fex' 'To: $bcc' 'Subject: F*EX user registration' '' '$user has been auto-registrated with verify=no' )); close $mail; } else { furlog("ERROR: cannot run sendmail - $!\n"); } exit; } unless (-d '.reg') { mkdir '.reg',0770 or http_die("mkdir .reg - $!\n"); } $reg = randstring(8); open $reg,'>',".reg/$reg" or http_die("open .reg/$reg - $!\n"); print {$reg} $user,"\n",$id,"\n"; close $reg or http_die("close .reg/$reg - $!\n"); open my $mail,'|-',$sendmail,$user,$bcc or http_die("cannot start sendmail - $!\n"); pq($mail,qq( 'From: $admin' 'To: $user' 'Subject: F*EX user registration request' '' 'To activate your new F*EX account go to this URL:' '' '$ENV{PROTO}://$ENV{HTTP_HOST}/fur?confirm=$reg' '' )); if ($usage_conditions and open $usage_conditions,$usage_conditions) { print {$mail} "The conditions of usage are:\n\n"; print {$mail} $_ while <$usage_conditions>; close $usage_conditions; } close $mail or http_die("cannot send mail - $!\n"); http_header("200 OK"); print html_header($head); print "confirmation e-mail has been sent to $user\n"; print "\n"; furlog("confirmation request mailed to $user"); exit; # standard log sub furlog { my $msg = "@_"; $msg =~ s/\n/ /g; $msg =~ s/\s+$//; $msg = sprintf "%s [%s_%s] %s %s\n", isodate(time),$$,$ENV{REQUESTCOUNT},$fra,$msg; writelog($log,$msg); } sub normalize_address { my $a = shift; $a = lc(normalize(despace($a))); checkchars('address',$a); $a =~ s:/:_:g; $a =~ s:^\.:_:; return untaint($a); } fex-20160919/cgi-bin/pup0000755000174700017470000001006712624116661012766 0ustar fexfex#!/usr/bin/perl -wT # F*EX CGI for public upload # # Author: Ulli Horlacher # BEGIN { ($ENV{PERLINIT}||'') =~ /(.+)/s and eval $1 } use utf8; # add fex lib (our $FEXLIB) = $ENV{FEXLIB} =~ /(.+)/; die "$0: no $FEXLIB\n" unless -d $FEXLIB; $| = 1; our $error = 'F*EX public upload ERROR'; our $head = "$ENV{SERVER_NAME} F*EX public upload"; our $locale = ''; # import from fex.ph our (@public_recipients); # import from fex.pp our ($FEXHOME); # load common code, local config: $FEXLIB/fex.ph require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n"; $from = $to = ''; chdir $spooldir or http_die("$spooldir - $!\n"); &check_maint; my $qs = $ENV{QUERY_STRING}; (my $multi) = $qs =~ s/(^|&)multi//; # parse HTTP QUERY_STRING (parameter=value pairs) if ($qs) { foreach (split '&',$qs) { if (s/^(\w+)=//) { my $x = $1; # decode URL-encoding s/%([a-f0-9]{2})/chr(hex($1))/gie; if (/([<>\'\`\"\000-\040])/) { http_die(sprintf( "\"&#%s;\" is not allowed in URL parameter", ord($1) )); } setparam($x,$_); } } } # parse HTTP POST body if ($ENV{REQUEST_METHOD} eq 'POST') { if ($ENV{CONTENT_TYPE} =~ /boundary=\"?([\w\-\+\/_]+)/) { $boundary = $1; } else { http_die("malformed HTTP POST (no boundary found)"); } binmode(STDIN,':raw'); READPOST: while (&nvt_read) { if (/^Content-Disposition:\s*form-data;\s*name="([a-z]\w*)"/i) { my $x = $1; while (&nvt_read) { last if /^\s*$/ } &nvt_read; setparam($x,$_); NEXTPART: while (&nvt_read) { last READPOST if /^--\Q$boundary--/; last NEXTPART if /^--\Q$boundary/; } } } } unless (@public_recipients) { html_error($error,"No public recipients defined by administrator"); } if ($to and not grep /^\Q$to\E$/i,@public_recipients) { html_error($error,"$to is not a public recipient"); } if ($to and $from and checkaddress($from)) { nvt_print( "HTTP/1.1 302 Found", "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/fup?from=$from&to=$to&id=PUBLIC", 'Content-Length: 0', "" ); exec($FEXHOME.'/bin/fexsrv') if $ENV{KEEP_ALIVE}; exit; } http_header('200 ok'); print html_header($head); my @locales; foreach my $locale (glob "$FEXHOME/locale/*") { if (-f "$locale/cgi-bin/pup") { my $langf = "$locale/lang.html"; $locale =~ s:.*/::; $lang = $locale; if (open $langf,'<',$langf) { $lang = getline($langf); close $langf; } push @locales,"$lang"; } } print "

    @locales

    \n" if @locales > 1; pq(qq( '
    ' ' ' ' ' ' ' )); if ($from) { pq(qq( ' ' ' ' )); } else { pq(qq( ' ' )); } if ($to) { pq(qq( ' ' ' ' )); } else { if ($multi) { foreach my $pr (@public_recipients) { push @pr,qq() ."$pr
    "; } pq(qq( ' ' )); } else { foreach my $pr (@public_recipients) { push @pr,""; } pq(qq( ' ' )); } } pq(qq( '
    your e-mail address:$from
    your e-mail address:
    recipient:$to
    recipient:@pr
    recipient:
    ' '

    ' ' ' '

    ' )); # set parameter variables sub setparam { my ($v,$vv) = @_; $v = uc(despace($v)); if ($v eq 'LOCALE' and $vv =~ /^(\w+)$/) { $locale = $1; } elsif ($v eq 'FROM') { $from = normalize_email($vv); } elsif ($v eq 'TO') { $to = normalize_email($vv); } } fex-20160919/cgi-bin/sex0000755000174700017470000001353212657131656012770 0ustar fexfex#!/usr/bin/perl -wT # CGI for stream exchange # # Author: Ulli Horlacher use Fcntl qw':flock :seek :mode'; use POSIX qw'mkfifo'; use Digest::MD5 qw'md5_hex'; # add fex lib (our $FEXLIB) = $ENV{FEXLIB} =~ /(.+)/; die "$0: no $FEXLIB\n" unless -d $FEXLIB; $| = 1; # import from fex.pp our ($tmpdir,@logdir,$timeout,$fra,$bs); # load common code, local config: $HOME/lib/fex.ph require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n"; chdir $spooldir or error(500,"$spooldir - $!"); # my $debuglog = "$tmpdir/sex.log"; my $ra = $ENV{REMOTE_ADDR}||0; $fra .= '/'.$ENV{HTTP_X_FORWARDED_FOR} if $ENV{HTTP_X_FORWARDED_FOR}; $timeout *= 10; # normal / public : # in normal mode the recipient needs authentification, not the sender # in public mode the sender needs authentification, not the recipient $user = $id = $pmode = $type = ''; $stream = 'STDSTR'; $mode = $ENV{REQUEST_METHOD} eq 'POST' ? 'PUSH' : 'POP'; # parse HTTP QUERY_STRING if (my $qs = $ENV{QUERY_STRING}) { $qs = decode_b64($qs) if $qs =~ /^\w+=*$/; foreach (split '&',$qs) { setparam(split '=',"$_=") }; } unless ($user) { error(400,"Missing user") } if ($mdomain and $user !~ /@/) { $user .= '@'.$mdomain } if ($user =~ /^anonymous/) { if (@anonymous_upload and ipin($ra,@anonymous_upload)) { mkdirp($user); } else { error(403,"Forbidden"); } } else { unless (-f "$user/@") { error(404,"Unknown user $user") } } chdir $user or error(500,"$user - $!"); $stream = "STREAM/$stream"; if ($mode eq 'PUSH') { if ($pmode eq 'PUBLIC') { &authentificate; $stream =~ s:/STDSTR:/PUBLIC:; } mkdirp($stream); my $fifo = "$stream/fifo"; unless (-p $fifo) { mkfifo($fifo,0600) or error(503,"Cannot create $fifo : $!"); } sexlog($mode); my $lock = "$stream/lock"; open $lock,'>>',$lock or error(503,"Cannot open $lock : $!"); flock $lock,LOCK_EX|LOCK_NB or error(409,"$stream already in use"); chmod 0600,$fifo; unlink "$stream/mode"; unlink "$stream/type"; symlink $pmode,"$stream/mode" if $pmode; symlink $type, "$stream/type" if $type; $SIG{PIPE} = sub { sleep 1; rmrf($stream); exit; }; $SIG{ALRM} = sub { syswrite STDOUT,"."; exit if $!; $ALARM = 1; }; syswrite STDOUT,"HTTP/1.9 199 Hold on"; for (my $i=0;$i<$timeout;$i++) { alarm(1); $ALARM = 0; # will hang until $stream is opend for reading by another process open $fifo,'>',$fifo and last; unless ($ALARM) { error(503,"Cannot open $fifo : $!") } } alarm(0); syswrite STDOUT,"\r\n"; unless (fileno $fifo) { rmrf($stream); error(504,"Timeout"); } header('200 OK'); $B = 0; $shutdown = sub { sexlog($B); rmrf($stream); exit; }; $SIG{PIPE} = sub { sleep 1; &$shutdown; }; # syswrite $fifo,$data if $data; while ($b = sysread(STDIN,$_,$bs)) { $B += $b; syswrite $fifo,$_ or die $!; } &$shutdown; } elsif ($mode eq 'POP') { $stream =~ s:/STDSTR:/PUBLIC: if $id eq 'public'; unless ($id eq 'public' and (readlink "$stream/mode"||'') eq 'PUBLIC' or $user =~ /^anonymous/) { &authentificate; } error(503,"No $stream for $user") unless -d $stream; $type = readlink "$stream/type" || ''; $SIG{ALRM} = sub { error(504,"Timeout") }; alarm($timeout); my $fifo = "$stream/fifo"; if (-e $fifo and not -r $fifo) { error(503,"$stream already in use") } open $fifo,'<',$fifo or error(503,"Cannot open $fifo : $!"); chmod 0,$fifo; alarm(0); header('200 OK',$type); sexlog($mode); while (sysread($fifo,$_,$bs)) { syswrite STDOUT,$_ or die $!; } unlink $fifo; exit; } else { error(405,"Unknown Request"); } exit; sub setparam { my ($v,$vv) = @_; $v = uc(despace($v)); $vv = untaint(normalize($vv)); # $param{$v} = $vv; if ($v eq 'USER') { $user = lc(despace($vv)) } elsif ($v eq 'ID') { $id = despace($vv) } elsif ($v eq 'MODE') { $pmode = uc(despace($vv)) } elsif ($v eq 'TYPE') { $type = uc(despace($vv)) } elsif ($v eq 'STREAM') { $stream = normalize_filename($vv) } elsif ($v eq 'BS' and $vv =~ /(\d+)/) { $bs = $1 } elsif ($v eq 'TIMEOUT' and $vv =~ /(\d+)/) { $timeout = $1 } elsif ($v eq 'ANONYMOUS') { $id = $user ='anonymous'; $stream = $vv; } } sub sexlog { my $msg = "@_"; $msg =~ s/\n/ /g; $msg =~ s/\s+$//; $msg = sprintf "%s [%s_%s] %s (%s) %s\n", isodate(time),$$,$ENV{REQUESTCOUNT},$user,$fra,$msg; foreach my $log (@logdir) { if (open $log,'>>',"$log/sex.log") { flock $log,LOCK_EX; seek $log,0,SEEK_END; printf {$log} $msg; close $log; } } } sub sigdie { local $_ = shift; chomp; sigexit('DIE',$_); } sub sigexit { my ($sig) = @_; my $msg = "@_"; $msg =~ s/\n/ /g; $msg =~ s/\s+$//; $msg = sprintf "%s %s (%s) caught SIGNAL %s\n", isodate(time),$user||'-',$fra||'-',$msg; foreach my $log (@logdir) { if (open $log,'>>',"$log/sex.log") { flock $log,LOCK_EX; seek $log,0,SEEK_END; printf {$log} $msg; close $log; } } if ($sig eq 'DIE') { shift; die "@_\n"; } else { die "SIGNAL @_\n"; } } sub error { nvt_print("HTTP/1.1 @_"); exit; } sub header { my ($status,$type) = @_; return if $HTTP_HEADER; $HTTP_HEADER = $status; nvt_print("HTTP/1.1 $status"); if ($mode eq 'POP') { nvt_print("Server: sexsrv"); if ($type eq 'GZIP') { nvt_print("Content-Type: application/gzip"); } else { nvt_print("Content-Type: application/binary"); } nvt_print("Expires: 0"); nvt_print("Cache-Control: no-cache"); nvt_print("Connection: close"); } nvt_print(""); } sub authentificate { my $rid; error(400,"Missing auth-ID") unless $id; open $id,'<','@' or error(401,"$user/@ - $!"); chomp($rid = <$id>||''); close $id; if ($rid and $sid and $id =~ /^(MD5H:)/) { $rid = $1 . md5_hex($rid.$sid); } error(401,"Wrong auth-ID") if $rid ne $id; } fex-20160919/etc/0000700000174700017470000000000012651452032011454 5ustar fexfexfex-20160919/etc/xinetd_fex0000644000174700017470000000062312770010167013550 0ustar fexfex# default: on # description: F*EX web server # service fex { socket_type = stream wait = no type = unlisted protocol = tcp #flags = IPv6 bind = ADDRESS port = PORT cps = 10 2 user = fex groups = yes server = FEXHOME/bin/fexsrv nice = 0 disable = no } # configuration for https/SSL see /home/fex/doc/SSL # configuration for IPv6 see /home/fex/doc/IPv6 fex-20160919/etc/mime.types0000644000174700017470000000155512172324417013514 0ustar fexfexapplication/ogg ogg ogx application/pdf pdf application/postscript ps ai eps application/x-dvi dvi audio/basic au snd audio/mpeg mpga mpega mp2 mp3 m4a audio/ogg oga spx audio/x-ms-wma wma audio/x-wav wav image/gif gif image/jpeg jpeg jpg jpe image/pcx pcx image/png png image/svg+xml svg svgz image/tiff tiff tif image/x-ms-bmp bmp image/x-portable-anymap pnm image/x-portable-bitmap pbm image/x-portable-graymap pgm image/x-portable-pixmap ppm image/x-rgb rgb image/x-xbitmap xbm image/x-xpixmap xpm image/x-xwindowdump xwd text/plain asc txt text pot video/3gpp 3gp video/dl dl video/dv dif dv video/fli fli video/gl gl video/mpeg mpeg mpg mpe video/mp4 mp4 video/ogg ogv video/quicktime qt mov video/x-msvideo avi video/x-sgi-movie movie fex-20160919/doc/0000755000174700017470000000000012770010176011461 5ustar fexfexfex-20160919/doc/debugging0000644000174700017470000000070312770010175013336 0ustar fexfexIf your F*EX installation does not work as expected then first look in: $FEXHOME/spool/fexsrv.log (log from fexsrv) $FEXHOME/spool/fup.log (log from fup CGI) $FEXHOME/spool/fop.log (log from fop CGI) If this does not help, set in $FEXHOME/lib/fex.ph : $debug = 1; then you will get in $FEXHOME/spool/.debug/ for each download a log file with detailed debugging output. If this does not help at all, contact me :-) framstag@rus.uni-stuttgart.de fex-20160919/doc/concept0000644000174700017470000006744412770010175013055 0ustar fexfexF*EX (Frams' Fast File EXchange) is a service to send big (large, huge, giant, ...) files from a user A to a user B, anywhere on the internet. The sender uploads the file to the F*EX-server and the recipient automatically gets a notification email with a download-URL. Main features of F*EX * file transfer of virtually unlimited file size * recipient and sender only need an email program and a web browser - of any kind, they do not have to install any software * RESEND and REGET for resuming after link failures at last sent byte * auto-notification of recipient * auto-deletion after download * auto-deletion after expiration date (default: 5 days) * full-users can create one time upload URLs for foreign users * full-users can create subusers, who can send only to this full-user * full-users can create groups, an analogy to mailing lists, but for files * self registration possible for internal and external users * maintenance-free: no admin interaction necessary * sending to multiple recipients needs storage on the server only once * quotas for sending and receiving * F*EX is a HTTP web-service and needs no firewall-tunnels * support for (personal or public) streams, too (SEX : Stream EXchange) * for real UNIX users, there are the shell programs fexsend and fexget to avoid annoying web browser usage and for full scripting support * adminstration by CLI or Web * about 10 times faster than apache * authentification modules for LDAP, RADIUS, POP, mailman * server based user address books * (reverse) proxy support * "public upload" similar to "anonymous ftp" possible * "anonymous upload" without registration for enabled IP addresses possible * localization for many languages * authentification by local user database, RADIUS, LDAP, mailman or POP * user and admin can throttle bandwith usage * admin can restrict access based on email or IP addresses * server available for UNIX and Windows hosts * protocol and source-code free available The end user normally uses F*EX with his web browser and the URLs http://YOURFEXSERVER/fup (file upload) and http://YOURFEXSERVER/fop (file download). F*EX is not an anonymous service (exception: "public upload" and "anonymous upload", see later). The admin must register the user with his email address and auth-ID string (low security password). This task can be done either with the CLI program "fac" (F*EX admin control) or http://YOURFEXSERVER/fac Alternativly the users can register theirselves with http://YOURFEXSERVER/fur (F*EX user registration), if the admin allows them to do so. This is done by setting the variables @local_domains and @local_hosts in $FEXHOME/lib/fex.ph Example: @local_hosts = qw(127.0.0.1 10.10.100.0-10.10.255.255); @local_domains = qw(rus.uni-stuttgart.de flupp.org); You can also use wildcard "*" in a domain, for example: @local_domains = qw(uni-stuttgart.de *.uni-stuttgart.de); Then all subdomains are allowed. In addition the administrator can allow external users to fex (only) to internal users. The F*EX functioning scheme is close related to email where any external user can send email to an internal user. This is also possible with F*EX. These users are then called "restricted users". The administrator has to define via configuration variable @local_rdomains the local recipient domains. For example: @local_rdomains = qw(YOURDOMAIN *.YOURDOMAIN OTHERDOMAIN); F*EX full users can create one time upload URLs with http://YOURFEXSERVER/fuc With such a URL a foreign user can send this F*EX full user a single file. F*EX full users can theirselves register "subusers" with http://YOURFEXSERVER/fuc Subusers can only fex to their full-user, not to any others, and they cannot create other subusers. F*EX full users also can create groups, an analogy to mailing lists, but for files: every member of a group can send files to the group address. The administrator can set with fac the CAPTIVE flag for a full user. Then he cannot change anymore his default settings (KEEP, AUTODELETE, etc) The F*EX user is the same as the "sender" in the fup CGI and the "from" parameter in the F*EX URL. The (confusing) naming scheme is historically based :-) The recipient (normally) does not need any registration. He authenticates himself with his unique download-URL which he gets in the notification email. You do not need to build F*EX URLs manually, they are generated by the F*EX programs. A F*EX session is based on unique URL parameters or POST variables (FROM, TO, ID, etc). For security reasons the URL parameters FROM and ID become a MD5-hashed access key link (AKEY for regular users, SKEY for subusers, GKEY for groupusers), generated by the CGIs, to prevent that a third person could easily read these parameters from the user webbrowser URL address field. AKEY and SKEY are used as optional cookies, too, for extending the session life. A SKEY is made of md5_hex("$mainuser:$subuser:$subuserid") A GKEY is made of md5_hex("$mainuser:$groupname:$groupuser:$groupuserid") Note: the AKEY, SKEY and GKEY always can be stolen by a network sniffer! If you need true security, then you have to use https instead of http! After download the file will be deleted after a grace time of 1 minute. This grace time allows a recipient to get the file again if he had problems in saving it. With the fexsend client the sender can change this behavior: option -D means "delay autodelete": do not delete the the file directly after download, but with the nightly fex_cleanup cronjob. More downloads are possible only from the same client (identified by cookie or ip address). option -K means "keep file": do not delete the file after download, but only after expiration date (normally 5 days). More downloads are possible only from the same client (identified by cookie or ip address). If you fex a file to yourself (sender = recipient), then the resulting download link is valid for any client and can be downloaded everywhere and more than once (until expiration date). If you want "delay autodelete" to be the default behaviour for all users and each transfer then set $autodelete = 'DELAY'; # or 'NO' for no autodelete in $FEXHOME/lib/fex.ph In addition, you can add to the "Recipient(s)" field of the fup CGI: ":autodelete=delay" or ":autodelete=no" or ":keep=x" (where x is the number of days). Example: Recipient(s): framstag@rus.uni-stuttgart.de:keep=10 These options are also possible in the server address book (see CGI fuc). If you need more security, then set in fex.ph: $fop_auth = 'yes'; $force_https = 'yes'; With $fop_auth upload is restricted to registered users and download requires (HTTP) authorization. The credentials are the F*EX user email and auth-ID. See extra documentation SSL for using https. If you want to have encrypted emails, then you need a GPG public key for the user fex. Create it with "gpg --gen-key" (use fex@YOURFEXSERVER as the user or the $bcc address from fex.ph if you have set it, see below). Next, the user has to upload his public key via webinterface "user config & operation control" and "Manage e-mail encryption". "Public upload" is a feature similar to anonymous ftp: the sender does not to be registered, but may send only to predefined recipients via http://YOURFEXSERVER/pup The administrator has to define via configuration variable @public_recipients the email addresses for which anyone can upload files without registration (auth-ID is not necessary). For example: @public_recipients = qw(fexmaster@YOURDOMAIN bunny@OTHERDOMAIN); With "anonymous upload" one can use F*EX without registration or authentication. The administrator has to define via configuration variable @anonymous_upload for which IP addresses this feature is available. The administrator can globally forbid certain recipient address via fex.ph configuration (example): @forbidden_recipients = qw(nobody@* *@microsoft.com); The administrator can also forbid a user to fex to any recipient address, but the allowed ones with: fac -r USER By standard installation the base directory $FEXHOME is the same as the login HOME of user fex, but you can move it if you want. $FEXHOME is determined by the full path of fexsrv as configured in /etc/xinetd.d/fex . Change this when you move $FEXHOME! You can also add (name based) virtual hosts with fac. Do not give write permission to any other user to any file in $FEXHOME or below! $FEXHOME contains: spool/ spool directory and user data htdocs/ directory for generic download files bin/ directory for programs cgi-bin/ directory for CGI programs lib/ directory for library and config files doc/ additional documentation locale/ alternative language installation Files in spool: cleanup.log log of daily cleanup cronjob dkey.log log of download keys dop.log log of HTTP document output error.log log of errors fexsrv.log log of all HTTP requests fop.log log of file downloads fup.log log of file uploads fur.log log of user self registrations sex.log log of stream exchanges $user/@ regular user auth-ID $user/@SUBUSER subuser addresses and IDs $user/@ALLOWED_RECIPIENTS recipients restrictions for this user $user/@ALLOWED_RHOSTS recipient's hosts restrictions $user/@UPLOAD_HOSTS upload hosts restrictions $user/@DOWNLOAD_HOSTS download hosts restrictions $user/@ADDRESS_BOOK users recipient address book $user/@GROUP directory of F*EX user groups $user/@OKEY directory with one time upload keys $user/@QUOTA sender and recipient quotas $user/@AUTODELETE autodelete default $user/@KEEP keep default $user/@LOCALE locale default $user/@CAPTIVE user must not change his settings $user/@FEXYOURSELF user can only fex to himself via web interface $to/$from/$file/upload file data in upload progress $to/$from/$file/filename original file name $to/$from/$file/size original file size $to/$from/$file/useragent HTTP header User-Agent $to/$from/$file/uurl upload URL $to/$from/$file/data file data after complete upload $to/$from/$file/keep keep time (autoexpire) in days $to/$from/$file/autodelete autodelete option: YES NO or DELAY $to/$from/$file/comment comment in notification email $to/$from/$file/id file ID (optional) $to/$from/$file/ip sender ip address $to/$from/$file/notify reminder notify flag $to/$from/$file/error error message if file has gone $to/$from/$file/download log of successful downloads $to/$from/$file/restrictions IP based download restrictions (see $user/@ALLOWED_RHOSTS) $to/$from/$file/dkey download key $to/$from/$file/locale locale As you see, the first directory sometimes means sender and sometimes means recipient! It depends on the case of usage (up/download). BEWARE: for the special senders fexmail and anonymous $to and $from are swapped (by fup and fop)! This is to prevent overcrowding of the toplevel spool directory with _fexmail_$RANDOM and _anonymous_$RANDOM recipients. A registered full F*EX user is identified by the file $spooldir/$from/@ Only if this file contains his auth-ID this user is able to send files to others. Otherwise he is just an unpriviledged recipient. You can customize the upload CGI fup by editing $FEXHOME/lib/fup.pl Additional directories in spool: .dkeys/ download keys lookup directory .ukeys/ upload keys lookup directory .akeys/ authentication keys lookup directory .skeys/ subuser keys lookup directory .gkeys/ groupuser keys lookup directory .xkeys/ extra download keys lookup directory .debug/ directory for debug output (optional) .reg/ temporary data for user selfregistration The upload keys (UKEY) are necessary to synchronize the file upload by HTTP POST with the javascript upload status bar which is an asynchronous HTTP GET. The GET process needs to know the corresponding POST process. This is done via UKEY, a unique upload identifier. The download key (DKEY) is a unique identifier for - guess what - downloading. It also prevents an attacker to get the file, because only the recipient knows the DKEY as part of the download URL from the notification email. XKEY is an optional extra download key to have a short download URL in shape http://YOURFEXSERVER//XKEY The XKEY always starts with // and is provided as a COMMENT by the client. Example: fexsend schwuppdiwupp.jpg // The user has to realize that such URLs have very low security. If you need to trace a F*EX request, then set $debug = 1; in fex.ph and look in ~/spool/.debug/ for the correspondening files. The user fex also gets a Bcc of all sent notification emails. This is a help for debugging purposes. If you want these Bcc mails to another address then set in fex.ph: $bcc = 'other@address'; The sender also get a Bcc if he put the string "!bcc!" in the comment field. If you have users within another domain with its own MTA and those users want to fex each other, then their MTA probably will reject the notification email. To prevent this problem you can set in fex.ph @remote_domains = qw(other_domain1 other_domain2 ...); In this case "From: $admin" will be used in the notification emails. F*EX comes with its own web server: fexsrv Standard web servers like apache have been proven problematic, either in speed or because of a 2-GB-limit. It is not possible to use the F*EX CGIs with an alternative web server, because the F*EX CGIs need special fexsrv features. xinetd starts fexsrv for every new connection, which then executes the CGIs fup (file upload), fop (file output), fuc (fex user control), foc (fex operation control), fac (fex admin control), fur (fex user registration) and sex (stream exchange). SEX has the opposite authorization model of FEX: The sender does not need any registration. He can send a stream to any registered SEX user, who must identify himself with his auth-ID. This is because a stream does not cost resources when it is not bound to a recipient. It will block otherwise. The client programs for sexing are sexsend and sexget. You can call them also fuckyou and fuckme :-) With the F*EX client fexsend you can have a streaming file transfer with spooling: on client side there is no temporary buffer file (archive), but the data is sent directly to the F*EX server. This saves time and disk space on the client. Example for a streaming archive upload: fexsend -a music+video.tar *mp3 *avi webmaster@flupp.org Example for a streaming data upload: fpg fex /var/log/* | fexsend -s logs fexmaster@flupp.org The data streaming is implemented via a HTTP extension: the header Content-Length is given -1 which means: unknown length, read until EOF. For streaming receiving you can use "fexget -s-" or "wget -O-". fexsrv also can do generic document output (via dop) like a normal web server. For this, your files must be under $FEXHOME/htdocs and they must not have the same name as the CGIs under $FEXHOME/cgi-bin, because the CGIs have priority. For security reasons, documents to be delivered by dop: - the file must be readable by group or world - the file must be in $FEXHOME/htdocs or a directory specified by @doc_dirs - the filename must not start with a "." - the filename must not contain a "@" - the filename must not end with "~" To enable HTTP basic authentication, write your access token to a file named .htauth which will protect all files in this directory. An user will be prompted for this password by his web browser. To restrict the access to specific client IP addresses, put these IPs into a file named .htaccessfrom which will protect all files below this directory. You can name single IPs, also as IP ranges (example: 129.69.0.0-129.69.255.255) dop is not a regular CGI program (like fup or fop), but a sub-program of fexsrv. *.html files may contain $VARIABLES$ which will be substituted with the value of the corresponding environment variable. See example $SERVER_ADMIN$ in $FEXHOME/htdocs/index.html *.html files may contain <> (even multiline) which will be evaluated. The output from print and printf statements will be placed in. If the perl-code does not end with a ";" then its return value is also added to the output. Same goes for <<>> but without output catching. This perl-code must not contain ">>" strings itself! See example $FEXHOME/htdocs/dynamic.html To chainload external perl-code do not use "require" but "do" statement. Pay attention: do not place security relevant data inside << >> because it will be delivered to the client if the URL ends with a "!" character, see example: http://fex.rus.uni-stuttgart.de/index.html http://fex.rus.uni-stuttgart.de/index.html! If you want to hide your code, then you have to write a CGI script and place it into the cgi-bin directory. Files there will never be delivered by dop. You also can do "chmod o-r file.html" to prevent source code delivery. *.html files may contain conditional blocks: #if (perl-expression) HTML... #elseif (perl-expression) HTML... #else HTML... #endif which will be evaluated at run-time (#else and #elseif are optional). *.html files may contain: #include "FILE" which means: load FILE from current directory at this place in code. dop also can display a directory listing if this directory contains a file named .htindex To restrict the listing to specific files, put a matching regular expression into .htindex Example: echo 'pdf$' > /home/fex/htdocs/doc/.htindex dop can output gzipped files on-the-fly as a streaming document. For example: you have /fex/home/htdocs/big.file but a client requests http://YOURFEXSERVER/big.file.gz then a corresponding big.file.gz will be delivered. dop can also output tar, tgz or zip archives on-the-fly as a streaming document. Just create a symbolic link with files (or directories) you want in this archive and enclose them with ":". The symlink name must end with ".stream". Example: http://fex.rus.uni-stuttgart.de:8080/download/sex.tar fex@fex:~/htdocs/download: ls -l sex* lrwxrwxrwx 1 fex fex 7 2011-01-26 11:46 sexget -> sexsend -rwxr-xr-x 1 fex fex 12110 2012-08-22 09:55 sexsend lrwxrwxrwx 1 fex fex 22 2012-09-01 12:13 sex.stream -> :sexsend:sexget:sexxx: lrwxrwxrwx 1 fex fex 7 2012-09-01 11:28 sexxx -> sexsend It is also possible to create this stream file as a regular file. Then the content must be the file names you want in the streaming archive. Note: you may only use relative paths and without "../" elements. Note: Files beginning with a . or ending with ~ will not be included in the download stream. cronjob fex_cleanup is run once a day and deletes expired uploads, removes inactive accounts and does some other spool houskeeping. See: crontab -l To detect inactive users you can put in fex.ph: $account_expire = "365:notify"; This sends an email to $admin when an user is inactive for 365 days. Or to delete inactive users you can put in fex.ph: $account_expire = "365:delete"; This deletes user accounts automatically which have been inactive for 365 days. Of course you can use any number of days. Inactive users will get an account reactivation request before. The address book may contain the optional parameters autodelete and keep. Address book example entry: flupp framstag@flupp.org keep=99 autodelete=no BUT: these address book parameters are only accepted when using the fexsend or schwuppdiwupp client! They will be ignored when using a webbrowser! Nevertheless you may add autodelete and keep parameters using a webbrowser, but then they are valid for ALL addresses in the "Recipient" field! The clients fexsend and schwuppdiwupp can MD5-encrypt the auth-ID together with a session-ID. The session-ID itself is provided by the server after an initial "GET SID" HTTP request. This is not possible through a proxy, because most proxies do not support persistant tcp sessions. See fex-client_2.pdf for the F*EX protocol specification. To understand and trace the F*EX protocol you can use fexsend with the -v option. Example (--> means send to server, <-- means receive from server): framstag@fex:~: fexsend -v X.png framstag@flupp.org ID data from /home/framstag/.fex/id: http://fex.rus.uni-stuttgart.de framstag@rus.uni-stuttgart.de XXXX Server/User: http://fex.rus.uni-stuttgart.de/framstag@rus.uni-stuttgart.de TCPCONNECT to fex.rus.uni-stuttgart.de --> GET SID HTTP/1.1 --> <-- HTTP/1.1 201 8p2Y2qa2 <-- X-Features: SID,CHECKRECIPIENT,GROUPS,QUOTA,FILEID,MULTIPOST,XKEY <-- X-SID: 8p2Y2qa2 <-- X-Timeout: 30 <-- Content-Length: 0 <-- --> HEAD /fop/framstag@flupp.org/framstag@fex.rus.uni-stuttgart.de/X.png??ID=MD5H:226e896d0adab86892957aa8158b37ba HTTP/1.1 --> <-- HTTP/1.1 200 OK <-- Content-Length: 0 <-- X-Size: 0 <-- X-Features: SID,CHECKRECIPIENT,GROUPS,QUOTA,FILEID,MULTIPOST,XKEY <-- --> POST /fup HTTP/1.1 --> Host: fex.rus.uni-stuttgart.de --> User-Agent: fexsend (Ubuntu 8.04.4 LTS) --> Content-Length: 149935162 --> Content-Type: multipart/form-data; boundary=JhUOtQ3sgV5ZcHJzrTny523nBFqgUNvSAOUHoRMTdZfGpAjs --> --> --JhUOtQ3sgV5ZcHJzrTny523nBFqgUNvSAOUHoRMTdZfGpAjs --> Content-Disposition: form-data; name="FROM" --> --> framstag@fex.rus.uni-stuttgart.de --> --JhUOtQ3sgV5ZcHJzrTny523nBFqgUNvSAOUHoRMTdZfGpAjs --> Content-Disposition: form-data; name="TO" --> --> framstag@flupp.org --> --JhUOtQ3sgV5ZcHJzrTny523nBFqgUNvSAOUHoRMTdZfGpAjs --> Content-Disposition: form-data; name="ID" --> --> MD5H:226e896d0adab86892957aa8158b37ba --> --JhUOtQ3sgV5ZcHJzrTny523nBFqgUNvSAOUHoRMTdZfGpAjs --> Content-Disposition: form-data; name="FILESIZE" --> --> 149934400 --> --JhUOtQ3sgV5ZcHJzrTny523nBFqgUNvSAOUHoRMTdZfGpAjs --> Content-Disposition: form-data; name="FILE"; filename="X.png" --> Content-Type: application/octet-stream --> Content-Length: 149934400 --> X-File-ID: 1283077463 --> --> (file content) --> --JhUOtQ3sgV5ZcHJzrTny523nBFqgUNvSAOUHoRMTdZfGpAjs-- <-- Location: http://fex.rus.uni-stuttgart.de/fop/CoVhikzk/X.png <-- X-Recipient: framstag@flupp.org (autodelete=YES,keep=5) <-- Comment on the HEAD request above: The client fexsend sends it to request whether the file has been sent before and if it was successful or not. On the later case, the server would reply how many bytes has already been received and the client then can send only the missing part. Normally the answer to the HEAD request is 0 (see above), which means: nothing of this file has been received so far. But this is only half of the truth :-) I have omitted in the example above the requests CHECKRECIPIENT and GET ADDRESS_BOOK, to keep it simple in the first run. CHECKRECIPIENT is a HTTP POST request to check whether the recpient's email address is valid to the server. GET ADDRESS_BOOK is a HTTP GET request to check if the recipient with a short address (= address without @) is an alias in the senders server address book. Please use "fexsend -v" by yourself to see the whole protocol dialoge. Many HTTP proxies have a POST limit, which is often at 2 GB, but sometimes lower. To overcome this limitation a F*EX client (like fexsend) may include in the POST the HTTP MIME part "filesize" which indicates the full file size. All incoming file POSTs with this file name will be appended until the full file size is reached. Of course the client has to POST all parts of this file, in the correct order, in asking the server how many bytes has already been received. Example: framstag@fex:/tmp: fexsend -vP wwwproxy.uni-stuttgart.de.de:8080:1024 2GB.tmp . ID data from /home/framstag/.fex/id: http://fex.rus.uni-stuttgart.de:8080 framstag@rus.uni-stuttgart.de xxxxxx Server/User: http://fex.rus.uni-stuttgart.de:8080/framstag@rus.uni-stuttgart.de TCPCONNECT to wwwproxy.uni-stuttgart.de.de:8080 --> HEAD http://fex.rus.uni-stuttgart.de:8080/fop/framstag@rus.uni-stuttgart.de/framstag@rus.uni-stuttgart.de/2GB.tmp??&ID=xxxxxx HTTP/1.1 --> <-- HTTP/1.1 200 OK <-- X-Size: 0 <-- Content-Length: 0 <-- Proxy-Connection: Keep-Alive <-- Connection: Keep-Alive <-- Date: Tue, 08 Jun 2010 15:04:13 GMT <-- TCPCONNECT to wwwproxy.uni-stuttgart.de.de:8080 --> POST http://fex.rus.uni-stuttgart.de:8080/fup HTTP/1.1 --> Host: fex.rus.uni-stuttgart.de:8080 --> User-Agent: fexsend (Ubuntu 8.04.4 LTS) --> Content-Length: 1073677143 --> Content-Type: multipart/form-data; boundary=gqhqeU7FCHMl4ohxJ5knK1y9rF75xYTvabPvZTeWnAhaoDsK --> --> --gqhqeU7FCHMl4ohxJ5knK1y9rF75xYTvabPvZTeWnAhaoDsK --> Content-Disposition: form-data; name="FROM" --> --> framstag@rus.uni-stuttgart.de --> --gqhqeU7FCHMl4ohxJ5knK1y9rF75xYTvabPvZTeWnAhaoDsK --> Content-Disposition: form-data; name="TO" --> --> framstag@rus.uni-stuttgart.de --> --gqhqeU7FCHMl4ohxJ5knK1y9rF75xYTvabPvZTeWnAhaoDsK --> Content-Disposition: form-data; name="ID" --> --> xxxxxx --> --gqhqeU7FCHMl4ohxJ5knK1y9rF75xYTvabPvZTeWnAhaoDsK --> Content-Disposition: form-data; name="COMMENT" --> --> NOMAIL --> --gqhqeU7FCHMl4ohxJ5knK1y9rF75xYTvabPvZTeWnAhaoDsK --> Content-Disposition: form-data; name="FILESIZE" --> --> 2147483748 --> --gqhqeU7FCHMl4ohxJ5knK1y9rF75xYTvabPvZTeWnAhaoDsK --> Content-Disposition: form-data; name="FILE"; filename="2GB.tmp" --> Content-Type: application/octet-stream --> Content-Length: 1073676288 --> X-File-ID: 1275549886 --> --> (file content) --> --gqhqeU7FCHMl4ohxJ5knK1y9rF75xYTvabPvZTeWnAhaoDsK-- 2GB.tmp : 1023 MB in 73 s (14363 kB/s), chunk #1 : 1023 MB <-- HTTP/1.1 206 Partial OK <-- X-Message: Partial OK <-- Server: fexsrv <-- Expires: 0 <-- Cache-Control: no-cache <-- Content-Type: text/html; charset=UTF-8 <-- Connection: close <-- Date: Tue, 08 Jun 2010 15:05:29 GMT <-- TCPCONNECT to wwwproxy.uni-stuttgart.de.de:8080 --> HEAD http://fex.rus.uni-stuttgart.de:8080/fop/framstag@rus.uni-stuttgart.de/framstag@rus.uni-stuttgart.de/2GB.tmp??&ID=xxxxxx HTTP/1.1 --> <-- HTTP/1.1 200 OK <-- X-Size: 2147483748 <-- X-File-ID: 1275549886 <-- Content-Length: 1073676288 <-- Proxy-Connection: Keep-Alive <-- Connection: Keep-Alive <-- Date: Tue, 08 Jun 2010 15:05:29 GMT <-- TCPCONNECT to wwwproxy.uni-stuttgart.de.de:8080 --> POST http://fex.rus.uni-stuttgart.de:8080/fup HTTP/1.1 --> Host: fex.rus.uni-stuttgart.de:8080 --> User-Agent: fexsend (Ubuntu 8.04.4 LTS) --> Content-Length: 1073677254 --> Content-Type: multipart/form-data; boundary=LofreCkx1GmgWNCHZ9exBQoQhiEF7pXSaPp2KUQVPlnarPAw --> --> --LofreCkx1GmgWNCHZ9exBQoQhiEF7pXSaPp2KUQVPlnarPAw --> Content-Disposition: form-data; name="FROM" --> --> framstag@rus.uni-stuttgart.de --> --LofreCkx1GmgWNCHZ9exBQoQhiEF7pXSaPp2KUQVPlnarPAw --> Content-Disposition: form-data; name="TO" --> --> framstag@rus.uni-stuttgart.de --> --LofreCkx1GmgWNCHZ9exBQoQhiEF7pXSaPp2KUQVPlnarPAw --> Content-Disposition: form-data; name="ID" --> --> xxxxxx --> --LofreCkx1GmgWNCHZ9exBQoQhiEF7pXSaPp2KUQVPlnarPAw --> Content-Disposition: form-data; name="COMMENT" --> --> NOMAIL --> --LofreCkx1GmgWNCHZ9exBQoQhiEF7pXSaPp2KUQVPlnarPAw --> Content-Disposition: form-data; name="SEEK" --> --> 1073676288 --> --LofreCkx1GmgWNCHZ9exBQoQhiEF7pXSaPp2KUQVPlnarPAw --> Content-Disposition: form-data; name="FILESIZE" --> --> 2147483748 --> --LofreCkx1GmgWNCHZ9exBQoQhiEF7pXSaPp2KUQVPlnarPAw --> Content-Disposition: form-data; name="FILE"; filename="2GB.tmp" --> Content-Type: application/octet-stream --> Content-Length: 1073676288 --> X-File-ID: 1275549886 --> --> (file content) --> --LofreCkx1GmgWNCHZ9exBQoQhiEF7pXSaPp2KUQVPlnarPAw-- 2GB.tmp : 0 MB in 1 s (128 kB/s), total 2048 MB The default character set for F*EX is UTF-8, because most clients seem to use it. The problem is, it is nowhere defined which character set HTTP uses itself. Important for programmers: The perl variables of the F*EX CGI's (fup, fop, etc) have their UTF-8 flag turned off. This means, they contain UTF-8 data in binary representation. F*EX has support for many languanges. For every language a translated version will be installed in $HOME/locale/ The switch is done at runtime via locale cookie (by fexsrv). Some common functions from fex.pp must be present at any time for any locale in any language, eg notification functions. Therfore there is $HOME/lib/lf.pl (extracted functions from fex.pp). I have additional authentication modules for RADIUS, LDAP, mailman and POP. Please email me if you are interested. framstag@rus.uni-stuttgart.de fex-20160919/doc/reverse_proxy0000644000174700017470000000217111720717010014314 0ustar fexfexYou can prosecute F*EX behind a reverse proxy, but then you are limited to the capabilities of this proxy. For example, if you use apache, then you have a 2 GB upload limitation and a throughput penality. Example for apache reverse proxy: On http://tandem-fahren.de:80 there is an apache On http://tandem-fahren.de:488 there is a F*EX server tandem-fahren.de has ip address 78.46.33.142 If you want to contact the F*EX server via alias URL http://tandem-fahren.de/fex/ then you have to put in httpd.conf: Redirect /fex /fex/ ProxyRequests Off ProxyPass /fex/ http://tandem-fahren.de:488/ ProxyPassReverse http://tandem-fahren.de:488/ SetOutputFilter proxy-html ProxyHTMLExtended On ProxyHTMLURLMap http://tandem-fahren.de:488/ /fex/ ProxyHTMLURLMap / /fex/ ProxyHTMLURLMap /fex/fex/fex/ /fex/ And write to lib/fex.ph : $hostname = 'tandem-fahren.de'; $reverse_proxy_ip = '78.46.33.142'; $durl = 'http://tandem-fahren.de/fex/fop'; See also: http://8d.no/fexproxy.html fex-20160919/doc/xx0000664000174700017470000000546712770010175012060 0ustar fexfexWith xx you have a network wide shell based clip board for files and STDIN/STDOUT: easy data exchange between different accounts on different hosts. usage: send file(s): xx file... or: send STDIN: xx - or: send pipe: ... | xx or: get file(s) or STDIN: xx or: get file(s) quickly: xx -- Pipe example: framstag@tandem:~: uname -a | xx /home/framstag/.fex/tmp/STDFEX : 0 kB in 1 s (0 kB/s) framstag@fex:~: xx transfered: 0 MB (100%) Linux tandem 2.6.24-28-server #1 SMP Wed Aug 18 22:01:20 UTC 2010 i686 GNU/Linux File transfer example: framstag@tandem:~: xx /boot/ making tar transfer file /home/framstag/.fex/tmp/STDFEX : /boot/ /boot/initrd.img-2.6.24-27-generic /boot/vmlinuz-2.6.24-28-generic (...) /boot/System.map-2.6.24-27-generic /home/framstag/.fex/tmp/STDFEX : 34 MB in 2 s (17605 kB/s) framstag@fex:/tmp: xx transfered: 34 MB (100%) Files in transfer-container: drwxr-xr-x root/root 0 2010-10-20 07:37 boot/ -rw-r--r-- root/root 7905085 2010-05-25 15:38 boot/initrd.img-2.6.24-27-generic -rw-r--r-- root/root 1927544 2010-10-16 20:38 boot/vmlinuz-2.6.24-28-generic (...) -rw-r--r-- root/root 906803 2010-03-24 14:33 boot/System.map-2.6.24-27-generic Extract these files? One problem are shared system accounts like root where different persons use them: xx (like fexsend and fexget) uses $HOME/.fex/id which contains personal data. But you can put the ID authorization in the environment variable FEXID. fexsend on your local account gives you a string for "cut and paste", example: framstag@moep:~: fexsend -I export FEXID='fex.rus.uni-stuttgart.de:8080 framstag jmBhf9ht' history -d $(history 1);history -d $(history 1) You then copy these two lines with your mouse into the root account: root@tandem:~# export FEXID'=fex.rus.uni-stuttgart.de:8080 framstag jmBhf9ht' root@tandem:~# history -d $(history 1);history -d $(history 1) (The second line deletes these two lines from the bash history) Now you can use xx (or fexsend and fexget) as normal. Example: root@tandem:~# grep sshd /var/log/daemon | xx transfered: 265 kB in 1 s (265 kB/s) framstag@moep:~: xx | wc -l 434279 After logging out from root@tandem the F*EX authorization data has gone. Internal details: The intermediate transfer file container is $HOME/.fex/tmp/STDFEX When transfering files tar/gzip format is used, whereas STDIN (pipe) will be transfered uncompressed. Tip: If you want to transfer files uncompress, then use: tar cvf - your files... | xx With default usage only one "storage slot" is available: STDFEX But you can use as many "storage slots" as you want by using "xx :TAG" Examples: uname -a | xx grep sshd /var/log/daemon | xx :log xx :log | grep obertux xx :config /boot /etc /root xx :config -- fex-20160919/doc/installation0000644000174700017470000000526112770010175014110 0ustar fexfexPrerequisites: ============== To install the F*EX server, you need a UNIX system with perl, xinetd and /usr/lib/sendmail (either original or a clone like postfix or exim). Your perl must have the following standard core modules: CGI CGI::Carp Digest::MD5 Encode Fcntl File::Basename Getopt::Std IO::Handle POSIX Optional are the non-standard perl modules: Net::DNS (for better domain error handling) Socket6 (for ipv6 support) Net::INET6Glue (for ipv6 support) IO::Socket::INET6 (for ipv6 support) On Debian or Ubuntu Linux simply execute as root: apt-get install xinetd perl-modules libnet-dns-perl libnet-inet6glue-perl test -x /usr/lib/sendmail || apt-get install postfix Do not forget to open port 80 on your firewalls and routers for incoming connections! To install F*EX, simply run "./install", then edit lib/fex.ph and set your local config. If you want to upgrade from a previous F*EX version, you also can run "./install", no old config files will be overwritten. Also index.html is kept. Alternativly use "./install -p 8888" to install F*EX on port 8888 instead on default port 80. Run "./install" again for installing optional localizations (languages). If the install-script does not work for you (no xinetd, no GNU tools, etc) here is what is to be done manually for installing: echo "fex 80/tcp" >> /etc/services echo "fex stream tcp nowait fex /home/fex/bin/fexsrv fexsrv" >> /etc/inetd.conf # restart inetd or reboot useradd -s /bin/bash -c "File EXchange" -m fex cd FEXSOURCEDIR chown -R fex . su - fex cd FEXSOURCEDIR rsync -av bin cgi-bin lib etc htdocs doc $HOME cd $HOME mkdir spool chmod 700 spool vi lib/fex.ph # set your config crontab -e 3 3 * * * exec /home/fex/bin/fex_cleanup Hints: ====== F*EX runs with its own uid (default: fex), which will be created by the install script. F*EX uses a directory (FEXHOME) containing anything needed to run fex. Default is FEXHOME=/home/fex, the home directory of the "fex" user. If you want fex to be installed elsewhere create a new "fex" user account BEFORE running ./install, e.g.: adduser --system --group \ --gecos "File EXchange" \ --home /srv/fex \ --shell /bin/bash \ fex ./install If you run F*EX behind a HTTP reverse proxy, then write to lib/fex.ph : $reverse_proxy_ip = 'internal-IP.address.of.proxy'; $durl = 'http://your.proxy.with.domain/fop'; Be aware that most proxies have a 2 GB file size limit (signed int 32 bit bug)! Of course you have to configure your reverse proxy correctly, especially the URL rewrite rules. See the manual of your reverse proxy. If you want to use https, you need the stunnel package. See file SSL for more information. On problems contact the author: framstag@rus.uni-stuttgart.de fex-20160919/doc/newfeatures0000644000174700017470000000231512770010175013734 0ustar fexfexNew features for users ---------------------- 2016-03-15: - recipient address can have attached :options (keep,autodelete,locale) 2016-01-04: - new Windows client fexit - new MacOS client macfexsend 2015-01-12: - user configuration: save-or-display (MIME) for download - fexsend has new option -S show server/user settings - fexsend has new option -N resend notification email 2014-12-24: - the CLI clients respect the environment variables SSLVERIFY SSLVERSION SSLCAPATH SSLCAFILE SSLCIPHERLIST to enhance HTTPS security - new $HOME/.fex/config for the CLI clients, you can set there the variables $opt_* %autoview %alias see "fexsend -H" and "fexget -H" for details - fexget autoviews images after download 2014-08-06: - you as the sender can download the file, too, without auto-deleting it 2014-03-05: - email enryption option: you can upload your PGP/GPG public key via "user config & operation control" and "Manage e-mail encryption" - fexget checks local storage capacity before download - new FAQ http://fex.rus.uni-stuttgart.de/FAQ/ - notification e-mail resend option via "user config & operation control" 2013-08-05: - allow multiple downloads from same ip - fexget proxy support fex-20160919/doc/Changes0000644000174700017470000015236112770010174012762 0ustar fexfex2016-09-19 dop: do not show return value of <> in dynamic html file if this code ends with a ";" 2016-09-07 new fex.ph config variable $purge 2016-09-01 dop: removed (forgotten) CGI::Carp 2016-08-29 fexsend,fexget: update function aborts if new version is not newer 2016-08-03 added timeout to error output, fixes hanging fup 2016-08-03 fexsend: fixed bug dangling symlinks raise an error in archive mode 2016-07-21 fexsrv: map http client headers HTTP-HOST HTTP-VERSION PROXY* to HTTP_X_HOST HTTP_X_VERSION HTTP_X_PROXY* 2016-07-11 added missing fex.png fexit.png to distribution 2016-05-31 fur: fixed bug no external user registration possible 2016-03-11 fuc: added MIME headers to notification e-mail 2016-03-08 fexsend: added support for recipient:options 2016-03-07 fexsend,fexget: added update function to option -V 2016-03-04 install: fixed bug wrong permissions for /home/fex/locale/*/htdocs 2016-03-02 dop: run embedded <<>> without return value output dop: 10 s timeout for (all) embedded <> 2016-02-26 dop: run <> within perl namespace (package) DOP 2016-02-25 fexsend: added option -T internet speed test 2016-02-22 fexit: added internet speed test 2016-02-11 fexit: added option -s file streaming 2016-02-08 added @extra_header config with default security settings for Content-Security-Policy, X-Frame-Options, X-XSS-Protection, X-Content-Type-Options 2016-02-03 fup: every address or alias can have attached :options (keep,autodelete,locale) 2016-01-29 fexit: added xx clipboard support 2016-01-21 fexsend: fixed bug not working cgi-bin/login 2016-01-15 fup: fixed bug UTF8 error in italian source 2016-01-14 fup: fixed bug after login $info_login instead of $info_1 is displayed 2015-12-29 fexsend: added search pattern argument to option -l 2015-12-25 fup: added +/- download flag in LIST command output 2015-12-18 fup: allow AUTODELETE and KEEP parameter for anonymous user and sender=recipient 2015-12-01 hint for fexget and fexit in notification email 2015-12-01 fixed bug notification email ignores (sometimes) locale 2015-11-27 fixed bug first line in encrypted notification emails gets lost 2015-11-21 fixed bad UTF8 encoding for french spanish czech galician 2015-11-10 fexget: fixed bug timeout for big files on slow storage 2015-10-14 install: fixed bug missing fex group 2015-10-09 fexsend: better support for reverse proxy (closing connection) 2015-10-06 fexsend: abort if file has been modified while uploading 2015-10-04 fup: when forwarding a file, keep time is calculated for today, not for upload day 2015-09-29 fexget: fixed bug no https download 2015-09-26 fex_cleanup: fixed bug send no locale reactivation.txt 2015-09-21 fexget: fixed bug resume download on aborted storage test file leads to corrupted file 2015-09-17 changed LIST output formating (more consistent) 2015-09-17 fexget: fixed bug cannot forward a file that was received from myself 2015-09-16 fexsend: more robust fileID (md5sum of metadata) 2015-09-14 fup: show autodelete=no if sender == recipient 2015-09-11 moved comment to top in notification email 2015-09-08 fup,fuc: fixed bug link to F*EX clients tools.html broken (loop) 2015-09-06 fexsend: added ditto-zip for MacOSX 2015-09-02 fexsend: added MacOSX support 2015-09-01 fac: added option -Rl for local users 2015-09-01 fup: added local users restriction option 2015-08-26 fur: fixed bug no registration possible 2015-08-25 fup: fixed bug uninitialized value when called by sup.html 2015-08-25 fac: option -q quota=0 means use default quota 2015-08-24 better detection of UTF8 in comment 2015-08-14 fixed bug "Wide character in print at (...)/fex.pp" in function pq() 2015-07-29 install: fixed various bugs 2015-07-15 dop: symbolic links generate a HTTP 302 (temporarily redirection) instead of a HTTP 301 (permanently redirection) response 2015-06-16 fexsend: fixed bug hangs with https 2015-06-16 new fex.ph config variable @mailing_lists 2015-06-15 fup: always display fur link, if @local_domains is defined 2015-06-10 fexsrv: fixed warning with https and SIGCHLD 2015-05-16 fexsrv/dop: added active and passive redirect support 2015-05-12 fuc: fixed bug undefined subroutine end_html 2015-04-30 fex_cleanup: fixed bug runtime error with mtime (symlinks) 2015-04-24 fixed bug wrong quota calculation for uploads 2015-04-23 fex_cleanup: follow symbolic links if they contain a / 2015-04-22 fexsend: 60 s timeout for file transfer socket (sys)write 2015-04-22 fup: fixed bug fexsend hangs with SKEY or GKEY recipient URL 2015-04-02 fixed several severe bugs in install script 2015-04-01 group name may only contain (some) ASCII characters 2015-03-29 fop: fixed bug no more download from same (recipient) ip 2015-03-18 added local URL redirect service 2015-03-08 fup: fixed bug uninitialized value $address if alias address is used twice 2015-03-07 disallow email addresses starting with "-" 2015-03-07 fex_cleanup: do not terminate on sendmail error 2015-03-01 no file name in email subject if notification is encrypted 2015-02-28 fexsrv: restrict HTTP header to 64 kB ($bs) and POST (not fup) to 128 MB 2015-02-27 no more usage of CGI.pm at all 2015-02-25 fup: added $auth_hook 2015-02-24 fac(CGI): no more usage of CGI.pm 2015-02-18 fuc: fixed bug no gpg usage help 2015-02-17 fexsend: check SSLeay version and adjust SSL_verify_mode 2015-02-16 fup: save upload URL in spool 2015-02-16 in notification+reminder emails use same protocol for download URL like in upload 2015-02-08 rup: fixed various bugs (not working at all) 2015-02-05 fup: fixed bug cannot send to groups 2015-01-27 fup: set autodelete=no if sender == recipient (use case: provide download link for mailing lists) 2015-01-27 new fex.ph config variable $fex_yourself (default yes) 2015-01-25 fexsend: fixed bug cannot forward a file name with "&" 2015-01-21 main user is always first member of a new group 2015-01-21 substituted CGI::Carp with web error handler via PERLINIT environment 2015-01-17 new fex.ph config variable $mail_authid (default yes) 2015-01-16 fixed bug no notfication for still existing file (overwrite) 2015-01-15 fixed bug no locale reminder notfication 2015-01-15 fixed bug wrong result for recipients with NOTIFICATION=no 2015-01-13 fexsend: added option -N resend notification email 2015-01-13 resending notification email deletes download ip restriction 2015-01-13 fup: fixed bug sending to groups broken 2015-01-10 fexsend: added option -S show server/user settings 2015-01-10 fup: added command LISTSETTINGS 2015-01-09 foc: added save-or-display (MIME) option for download 2015-01-04 fexsend: fixed bug dies too early on multiple files and one file has been already transfered 2014-12-25 fexget,fexsend,sexsend: use default SSL_cipher_list DEFAULT:!3DES:!MD5 2014-12-24 fexget,fexsend,sexsend: evaluate environment variables SSLVERIFY SSLVERSION SSLCAPATH SSLCAFILE SSLCIPHERLIST 2014-12-24 fexget,fexsend,sexsend: use TLS, not SSL 2014-12-23 fexsend: $HOME/.fex/config with $opt_* and %alias variables 2014-12-23 fexget: $HOME/.fex/config with $opt_* and %autoview variables 2014-12-19 fur: fixed bug race condition with fex_cleanup (external->internal) 2014-12-17 install/update: fixed bug some spool files are owned by user root 2014-12-16 fexsrv: fixed bug handling of User-Agent FDM 2014-12-09 added l ll lf to distribution 2014-12-09 fexwall: also mail to sub and group users 2014-12-03 fup: remove file after upload if restricted user has set NOMAIL 2014-12-03 fup: fixed bug wrong message "user notified" if NOMAIL 2014-12-02 fup: also check recipient restrictions on command CHECKRECIPIENT 2014-11-24 fexget: autoview gif jpg png tif after download 2014-11-20 count unfinished upload size into quota, too 2014-11-20 fixed bug wrong quota calculation on SysV UNIX like Solaris 2014-11-18 fexsend: added environment variables SSLVERIFY SSLCAPATH SSLCAFILE 2014-11-18 dop: added HTTP basic authentication for htdoc directory with .htauth file 2014-11-14 ignore @forbidden_recipients if $SPOOL/$USER exists (admin has created user) 2014-11-11 fup: fixed bug groups from other users in address book selection 2014-11-11 fup: added useragent to $SPOOL/$TO/$FROM/$FILE/ 2014-11-10 fup: present locales in recipient query form, too 2014-11-07 FAQ: added text anchor URLs 2014-11-03 added missing fexget fexsend sexget sexsend for tools.html 2014-10-23 fexsend: on multiple recipients check only the first for resume 2014-10-14 fac: added option -L (list files detailed) 2014-10-01 fex_cleanup: fixed bug wrong default spool for virtual hosts 2014-09-19 sex: added transfered bytes to sex.log 2014-09-17 fup: fixed bug no locales presentation 2014-09-14 fex_cleanup: send new release notification to $admin 2014-09-11 dop: exclude .* and *~ from stream files 2014-09-01 fup: upload status bar waits longer, until $timeout 2014-08-27 fex_cleanup: use wget for new release dedection 2014-08-18 fexsend: workaround for stunnel bug (options -s and -g) 2014-08-18 fex_cleanup,fexsend: always restrict permissions on fexsend id-file 2014-08-16 fac: added options -P and -E (more examples) 2014-08-15 install: fixed bug wrong owner in spool 2014-08-15 fex_cleanup: do not terminate on error, but print warning 2014-08-13 fexsrv,fexsend,fexget: reenabled IPv6 support 2014-08-10 fac: added option -/ to set new admin 2014-08-08 moved $admin_pw from fex.ph to auth-ID for user $admin 2014-08-08 fex_cleanup: fixed bug in notify_newrelease 2014-08-08 fac(CGI): switched from HTTP basic authorization to auth-ID/akey 2014-08-08 fexsend: always use CHECKRECIPIENT, not only for aliases 2014-08-07 dop: generate on-the-fly gzipped documents if requested 2014-08-06 fixed bug install script dysfunctional (permission, hostname) 2014-07-25 reenabled vhost support 2014-07-13 dop: in directory index, list only files which are readable by group or other 2014-07-10 fup: fixed bug wildcards not working in @forbidden_recipients 2014-06-25 fup,fop: sender can download the files he has sent, too, if he uses the same ip for upload and download 2014-06-19 fac(CGI): @admin_hosts is now mandatory in fex.ph 2014-06-12 fur: reallow registration of internal and external users from the same ip range 2014-06-05 new fex.ph config variable @forbidden_hosts 2014-06-03 fuc: fixed bug cannot edit and save groups 2014-05-26 fuc: ignore akey cookie to prevent cross-site request forgery 2014-05-26 fup,foc,fuc,rup,pup: better parameter filtering to prevent cross-site scripting attacks 2014-05-25 fup: fixed bug insecure dependency when forwarding a file to a user which has set a default keep value 2014-05-23 fexget: fixed bug download fails on big file and slow disk 2014-05-12 set Reply-To in notification emails for @remote_domains 2014-05-03 fup: fixed bug wrong (old) keep time on forword-copy (bounce) 2014-04-10 fexsend: added "exclude from archive" option -# 2014-03-28 fexsend: do not copy "NOMAIL" comment in forward 2014-03-28 fexget: fixed bug server timeout because of storage check 2014-03-07 new fex.ph config variable $disclaimer to be appended to every email 2014-03-05 added bin/fexwall and doc/newfeatures 2014-03-04 fuc,foc: added PGP/GPG email encryption option 2014-02-26 fex.pp: fixed bug $keep_default ignored 2014-02-13 fur,fex.ph: config variable @local_domains may contain wildcard * in domain names 2014-01-03 fexget: checks storage capacity before download 2013-11-26 dop: substitute $variable$ in HTML document only if there is a corresponding environment variable 2013-10-15 fac: fixed bug wrong output with option -l 2013-10-14 fexget: use archive name as default extraction directory 2013-10-09 fixed bug afex URL for only one download availably 2013-10-07 fup: fixed bug no download links on multiple NOMAIL recipients 2013-09-23 fexsend: fixed bug option -c sends uncompressed file 2013-09-19 sub and group users have the same quota amount like their main user 2013-09-18 fixed bug permission denied for locale htdocs 2013-09-18 anonymous user now with hostname domain instead of mail domain 2013-09-17 dop: set locale cookie, too 2013-09-15 foc: added "Change the disclaimer" option 2013-09-12 fup: expand domainless address with server hostname if such a user exists (needed for fbm/nettest) 2013-09-09 new FAQ design (questions first, then Q+A) 2013-09-04 fac: modify $hostname when vhost fex.ph is created 2013-09-04 fuc: recognize comment=NOMAIL 2013-08-26 fexsend: always show download URL if recipient is "." 2013-08-20 fup,fop: fixed bug no DELETE and RESUME for fexmail and anonymous users (because of storage swap) 2013-08-18 sexsend: fixed bug data corruption when using https 2013-08-18 fop,fup: fixed bug bad file locking when using multiple recipients 2013-08-18 fexsend: fixed bug hangs on server error when sending archive 2013-08-17 fixed bug $sender_from ignored 2013-08-17 fup,foc: added notification email resending on user request 2013-08-16 fac: fixed bug wrong output order for option -l 2013-08-14 fop: fixed bug no multiple downloads for fexmail 2013-08-14 fac: added option -M for resending notification emails 2013-08-09 afex: fixed bug ID for input 2013-08-06 fexsrv: always includes "Server: fexsrv" in HTTP reply fexsend: terminates if no fexsrv HTTP reply 2013-07-28 dop: added .htaccessfrom support 2013-07-27 fex.ph,dop: security enhancement: static documents must be in @doc_dirs dop: documents with leading . are not allowed 2013-07-25 fexsend: added option -= to upload a file with another name 2013-07-21 fixed bug environment variables are cut at newline 2013-07-18 fup,fexsend: use header Content-Location instead of Content-Type for file linking 2013-07-15 fup: modifying keep references actual time, not upload date 2013-07-15 fexsend: fixed bug no feedback on option -x -k (modify keep) 2013-07-13 fup: fixed bug user specific keep and autodelete defaults are ignored 2013-07-12 fup,fop: added file link support 2013-07-12 fexsend: added option -/ for file linking 2013-07-09 fexget: added option -P proxy:port 2013-06-28 new all-in-one FAQ 2013-06-27 fup: to/from storage swap for fexmail and anonymous users 2013-06-27 fup: anonymous recipient with random number 2013-06-26 fop: allow multiple downloads from same ip 2013-06-26 fup,fac: extended "fex yourself" support 2013-06-26 added sup.html 2013-06-22 fop,fexsend: Location output for fexmail for already transfered files 2013-06-19 fexget: fixed bug cannot download MIME file 2013-06-15 fex.ph: new config variable $notify_newrelease checks fex.rus.uni-stuttgart.de for new release and sends mail 2013-06-12 fac(CGI): fixed bug wrong spooldir for virtual server 2013-06-11 fex.ph: new config variable $usage_conditions for registrations mails fop: fixed bug fexmail download possible only once 2013-06-10 fac: added option -D to disable a user (with hooks in fop,fop.fuc,foc,fur) 2013-06-03 fuc: fixed bug user can modify his auth-ID to an illegal value 2013-05-30 install: force creation of $admin_pw 2013-05-30 fex_cleanup: fixed bug wrong fexadmin fexid for reactivation emails 2013-05-25 added afex and asex to distribution 2013-05-23 dop: fixed bug no output on file.stream 2013-05-22 install script installs as user fex (and not as root) 2013-05-19 security patch: config variable @local_rhosts restricts download of files from new external users to specific ip ranges 2013-05-19 use and syntax in notification email header 2013-05-19 added support for $max_fail_handler() 2013-05-18 fac: fixed bug option -rd does not work 2013-05-18 fac: added option -R 2013-05-16 fop: fexmail support (multiple downloads allowed) 2013-05-09 fup: fixed bug anonymous only works if $mdomain is defined 2013-05-09 fop: fixed bug anonymous only works if recipient host is in @anonymous_upload list 2013-05-07 fup: fixed bug multiple Location HTTP headers generate an error with some web browsers 2013-05-03 added support for axel download accelerator (multiple HTTP Range) 2013-05-02 add X-FEX-File-ID header to notification emails 2013-04-23 dop: fixed bug HTTP 301 redirection timeout on symlinks 2013-04-05 fexsend: fixed bug server timeout when sending huge ZIPs 2013-02-20 fac: added -m maintenance mode 2013-02-17 fup: fixed bug stored comment in spool not in UTF8 2013-02-17 fop: fixed bug file deletion also deletes fop.log 2013-02-16 fur,fex.ph: allow "*" for local domains self registration 2013-02-16 fex.ph: new config variable @registration_hosts new config variable @admin_hosts 2013-02-11 fur: fixed bug insecure dependency with exuser 2013-01-31 receiving of reminder emails is user configurable 2013-01-24 fup: decode UTF8 comment 2013-01-07 added X-Frame-Options header to prevent clickjacking 2012-12-26 fup,fexsend: added replyto option 2012-12-21 dop: download manager prevention: no concurrent downloads from same client with HTTP Range 2012-12-17 fop: fixed bug ip based download restriction 2012-12-16 added name based virtual host server 2012-12-15 fexsrv: HTTP error logging to error.log 2012-12-07 fex.ph: added optional config variable @durl 2012-12-04 new feature forward a file from incoming spool 2012-11-21 fac: show more user information 2012-11-20 added CAPTIVE user mode 2012-11-19 fup: with comment NOSTORE file will not be stored ==> benchmarking 2012-11-14 fexsend: fixed bug gkey and skey URL recipients not working 2012-11-12 fexsend: 7z archives without compression 2012-11-08 fop: fixed bug cannot use "?" in file name with fexsend 2012-11-07 fixed security bug restricted user can redirect files 2012-11-06 fup: show download-URL after upload if sender = recipient 2012-11-06 fup,fop,fac: added user up/download IP restriction by admin 2012-11-05 added HTTP Strict Transport Security (HSTS) if $force_https is set 2012-11-05 fixed bug afex accessible via xkey from everywhere 2012-11-02 fup: fixed bug one time upload URL gives "no recipient specified" error 2012-11-01 fup: fixed bug public upload always gives error 2012-10-16 fop,fup: added afex support 2012-10-16 fup: accept recipients . and // 2012-10-15 sex,sexsend: added anonymous mode (no auth-ID necessary) 2012-10-14 fop,fup: added support for fexsend anonymous mode 2012-10-11 fex.ph: added optional config variable $overwrite 2012-10-10 fup: anonymous upload with non-anonymous recipient 2012-09-30 fup: fixed bug groups not working any more (NOMAIL) 2012-09-19 fup: logout functions respects login CGI (or symlink) 2012-09-19 foc: detailed/brief notification mail configuration 2012-09-18 fexsend: added options -. and -n 2012-09-18 fup: added shortmail option in comment 2012-09-17 added mailmode configuration option in fex.ph 2012-09-17 fup: shows download-URL if NOMAIL 2012-09-15 sex: public URL parameter may be in base64 format, too 2012-09-10 dop: added more security checks 2012-09-01 dop: added streaming document output 2012-08-30 sex: fixed bug second receiving client corrupts the stream 2012-08-26 Changed licence from AGPL to Perl Artistic 2012-08-21 schwuppdiwupp: error handling on network failures for Windows removed Tk::FileSelect for Windows 2012-07-11 fop: fixed bug no multiple downloads for anonymous uploads 2012-07-10 fixed French, Spanish and Czech localization (code syntax) bugs 2012-07-09 fup: anonymous upload with modifyable keep option and multiple downloads 2012-07-05 fexsrv: added camel easteregg 2012-07-02 fup: added optional anonymous upload with fex.ph variable @anonymous_upload 2012-07-02 fup: fixed bug throttle 0 configuration is ignored 2012-07-01 fexsend: optional argument '@' as files/recipients separator fixed bug notification email for recipient '.' 2012-06-21 dop: inside HTML documents: #include "file" 2012-06-06 fexget: new option -+ 2012-06-05 fexsend: new option -+ 2012-06-01 fup: show transfered size instead of total size in status window 2012-05-04 fexsrv: added bunny easteregg 2012-05-02 fexsrv: allow HTTP 1.0 with Range header (wget!) disallow negative value in Range (client signed int bug) 2012-04-26 Changed licence from GPL to AGPL 2012-04-07 foc: check new address book for syntax errors 2012-04-06 foc: added comment field for new subuser information 2012-04-04 removed F*IX because of too many bugs and no maintainer any more 2012-03-05 fup: fixed bug shell wildcards in recipient address are expanded to known users from spool 2012-03-05 fex.ph: added optional config variable @locales 2012-03-01 dop: delivers MIME type text/plain if "?!" is appended to URL 2012-02-20 foc: show auth-ID after click on link 2012-02-07 fop: MIME-type text/html is no longer possible for security reasons 2012-02-04 added optional french localization 2012-02-03 fixed bug 0.0.0.0 not recognized as ip address 2012-02-03 fex.ph: added optional config variable $keep_max 2012-02-02 HTTP parameter filtering to prevent cross-site scripting attacks 2012-02-01 config variable @throttle may also contains ip addresses 2012-01-25 pup: locale selection in native language, default autodelete=no 2012-01-25 fup: "send another file" with same keep and autodelete parameters 2012-01-17 fixed bug reactivation.txt in czech instead english 2012-01-06 fup: fixed bug show wrong remaining keep days 2012-01-02 fup.pl: fixed bug bad FAQ link 2011-12-31 fex_cleanup: fixed bug notification emails not localized 2011-12-30 fup: additional dkey.log 2011-12-05 fup: respect @throttle config for all clients 2011-11-29 dop: delivers text files (scripts!) without x-bit as "text/plain" 2011-11-15 fup: fixed bug with $autodelete = $NUMBER; 2011-11-08 fac: added option -S statistics 2011-11-02 fup: show remaining keep time in files listing 2011-10-28 fup: fixed bug uninitialized value when using copy-forward 2011-10-13 fup: FILESIZE hack for firefox 7 to support uploads > 4 GB 2011-10-05 fup: fixed bug wrong sender quota calculation 2011-10-03 fex.ph: added configuration variables @upload_hosts @download_hosts 2011-09-30 fexsend: added option -g for sending encrypted files 2011-09-21 fexsrv: use $default_locale if client sends illegal locale cookie 2011-09-20 fex.ph: added optional config variable $boring for unhumorous mode 2011-09-19 fur: $USER/.auto contains additional info about account creation 2011-09-07 fac(CGI): fixed bug infinitve loop in watch logfile 2011-09-06 fup,fac,fur: new additional login URL type: http://FEXSERVER/fup/B64ID 2011-09-06 fup: show "or select from address book" only if there are entries 2011-09-05 fexsrv: fixed bug locale cookie not fetched on http://cgi?parameter 2011-09-01 rup: fixed bug cannot find files (no more SID in akeys directory) 2011-08-30 fex.ph: new config variable @forbidden_recipients 2011-08-29 fexsend: accept file number for delete option -d, too 2011-08-29 dop: fixed bug no text document output if external file command is non-GNU 2011-08-26 added one time upload OKEY 2011-08-13 fex_cleanup: fixed bug comment missing in reminder email 2011-08-11 dop: #if ... #else ... #elseif ... #endif inside HTML documents show HTML sourcecode if "!" is appended to URL 2011-08-10 fex_cleanup: delete obsolete users, too, via fex.ph $account_expire new FAQ design (with Javascript/CSS) 2011-08-09 fup: show error on invalid SKEY or GKEY 2011-08-09 fuc: fixed bug subuser and groupuser not lowercase forced 2011-08-09 address book may also contain option locale= 2011-08-08 fex_cleanup: auto-expire user accounts with fex.ph variable $account_expire 2011-08-08 fexsend,fup: allow forward with locale 2011-08-08 dop: extra security check: files from lib and spool are not allowed 2011-08-07 fup: subusers and groupusers can also select a locale 2011-08-07 fup: if user selects a locale login, save it as default locale (does not affect fexsend and schwuppdiwupp) 2011-08-07 notification emails come in default locale 2011-08-03 fexsend: fixed bug uninitialized value when using chunked mode added undocumented option -F female mode 2011-07-31 fexsend: added option -s streaming data 2011-07-31 fup: accept streaming data 2011-07-30 fexsend: -a tar archives no longer use a intermediate transferfile, but send via pipe (streaming) 2011-07-30 fexsend: fixed bug no resume on -a archives 2011-07-30 fexsend: always ask server if file already has been uploaded 2011-07-30 fup: more information on F*EX clients download and configuration 2011-07-27 fup: if comment contains "!bcc!" then sender will get a bcc of notification email 2011-07-26 fexget: added option -X do not extract archive file 2011-07-26 fexget: added option -a get all files 2011-07-26 fexsrv: fixed bug uninitialized value when using a reverse proxy 2011-07-26 fex_cleanup: fixed bug notify reminder email not localized 2011-07-22 fac(CGI): fixed bug displaying < and & in logfiles 2011-07-22 fac(CGI): added getting error.log 2011-07-22 fop: allow multiple downloads from any client if sender = recipient 2011-07-16 added doc/reverse_proxy 2011-07-14 added optional czech localization 2011-07-01 FAQ.html reformated 2011-06-30 translate install job 20 times faster 2011-06-27 added robots.txt to disallow web robots indexing 2011-06-22 fup: disable HTML code in file listing (filename & comment) 2011-06-21 added optional italian localization 2011-06-17 fixed bug $bcc is ignored 2011-06-16 fexsend,fexget: better reverse proxy support (always send Host header) 2011-06-16 added optional galician localization 2011-06-15 fup: fixed bug always keep_default days in notification email 2011-06-14 fexsend: transparent proxy detection (and support) 2011-06-14 fixed bug $docdir ignored 2011-06-10 fex.ph: new config variable $bcc for notification emails 2011-06-09 set Reply-To in all notification emails 2011-06-09 fup: fixed security bug everyone can upload files with empty auth-ID 2011-06-05 fup: fixed bug insecure dependency in printf on "forward file" 2011-06-03 fup,fop: added throttle bandwith limit option (fex.ph) 2011-06-02 fup: added bandwith limit option 2011-06-01 added PID and request-number to the logs 2011-06-01 fex_cleanup: fixed bug no expire with AUTODELETE=NO 2011-05-31 support for FEXLIB /usr/local/share/fex/lib /usr/share/fex/lib 2011-05-30 fup,fexsend: added option -x to modify file parameters 2011-05-29 fup,fexsend: forward files with new comment and keep time 2011-05-29 rup: add mdomain to addresses without domain 2011-05-18 fup: fixed bug restricted users can forward files to anybody 2011-05-17 fixed bug access problems with AKEYs: now use SID instead of SIP 2011-05-11 added helper script mksgkeys (regenerates missing SKEYs and GKEYs) 2011-05-10 fex_cleanup: cleanup ADDRESS_BOOK file upload 2011-05-10 fex.ph,fex_cleanup: AUTODELETE=NUMBER ==> delete file on next NUMBER day after download 2011-05-09 fac,fup: added user specific autodelete default 2011-05-09 fac,fex_cleanup: added user specific keep default 2011-04-27 fexsend: fixed bug archiv.zip not working on Windows 2011-04-27 dop: added index function for htdoc directory with .htindex file 2011-04-25 fexsend: better proxy support (non-persistent connections) 2011-04-24 xx: better ESXi support (heuristic guessing of tar format) 2011-04-22 sexsend: base64 support for $FEXID and $FEXXX 2011-04-01 fexsend: continue without SID if SID is not available 2011-03-26 fexsrv: deactivate header_hook (inquisition) if request is a regular fop request 2011-03-18 fexsend: base64 support for $FEXID and $FEXXX 2011-03-09 fexget,fexsend: fixed bug no file listing for https 2011-03-04 removed "use Switch" because of warnings with perl 5.12 2011-02-28 sexsend: added option -g show transfer rate 2011-02-24 dop: evaluate <> inside html documents 2011-02-21 fexsend,fup: added option fexsend -U show authorized (login) URL 2011-02-18 do not modify download URL protocol if $dkey is set in fex.ph 2011-02-18 fac(CGI): fixed bug uninitialized value $server 2011-02-18 URLs in notification emails are derived from config variable $durl 2011-02-17 fup: fixed bug access denied with SKEY 2011-02-08 fup,fop,fuc: fixed bug access problems with sip in AKEYs 2011-02-08 fup: fixed bug no notification email for multiple recipients 2011-02-07 fexsend,fop: do not send same file (filename and mtime) twice 2011-02-06 fup: fixed bug no notification email after first failed upload 2011-01-31 schwuppdiwupp: added ISO-8859-1 support 2011-01-30 schwuppdiwupp: added running camel 2011-01-28 schwuppdiwupp: added chunksize to proxy options 2011-01-28 schwuppdiwupp: fixed bug timeout when using address book 2011-01-28 fexsend: fixed bug chunksize 0 2011-01-27 schwuppdiwupp: added advanced preferences Proxy and TMPDIR 2011-01-26 fex_cleanup: fixed bug uninitialized value in debuglog 2011-01-26 fex_cleanup: added option -v 2011-01-26 fexsend,fexget,sexsend: added option -V show version 2011-01-26 schwuppdiwupp: added drag&drop support for windows 2011-01-26 schwuppdiwupp: added 7zG support 2011-01-25 fuc: fixed bug cannot delete all subusers 2011-01-25 schwuppdiwupp: fixed bug 7-zip not found 2011-01-25 schwuppdiwupp: added drive letters in directory selection 2011-01-24 fop: IE bug workaround to store *.exe files 2011-01-18 schwuppdiwupp: added tar, zip and 7z container 2011-01-17 fexsend: fixed bug option -l not working with https URL 2011-01-16 fup: added 7zip hint in notification emails 2011-01-13 schwuppdiwupp: fixed bug no transfer at all when comment is set 2011-01-12 rup: added logging 2011-01-12 rup: wrong recipient cannot download file, but will get an error 2011-01-12 fac(CGI): fixed bug $server not declared 2011-01-07 fexget: keep file permission in overwrite mode 2011-01-04 fex_cleanup: fixed bug autodelete after partial download 2010-12-26 fex_cleanup: fixed bug too early expire for forwarded files 2010-12-10 new config variable @public_recipients for new CGI pup 2010-12-10 (public upload) - upload without auth-ID 2010-12-09 fex.ph,fur: new config variable @local_rdomain for self- registration of restricted external-to-internal users 2010-12-08 fup,foc: no access to foc for restricted users 2010-12-02 fup: if there is a cgi-bin/login it will be called on "logout" 2010-11-24 fex.ph: new config variable $default_locale 2010-11-24 dop: auto-expires every document (to prevent browser caching) 2010-11-16 fexsrv: better error handling if CGI is not executable 2010-11-09 new SKEYs and GKEYs, because old ones could be not unique access for subuser only with SKEY access for groupuser only with GKEY 2010-11-07 fup,fuc: added GKEY 2010-11-07 fexsend: SKEY or GKEY URLs can be recipients, too 2010-11-04 fexget: added (hidden) option -K 2010-11-03 fexsend: fixed bug proxy usage failed 2010-11-02 fop: fixed bug corrupted download with Internet Explorer 2010-10-25 fop,fup: better locking: no uploading is possible while a download is in progress for the same file 2010-10-24 fix,fop: fixed bug subuser not working (SKEY problem) 2010-10-24 xx: added locking 2010-10-23 xx,fop: added xx :slot option (multiple storage slots) 2010-10-20 fup,fop,fexsend: fexsend for subuser with SKEY 2010-10-19 fup: expires *KEY cookies on logout 2010-10-12 fup: fixed bug wrong interpretation of SKEY parameter+cookie 2010-10-05 fexend,fup: support of http reverse proxy 2010-09-27 fup: fixed bug missing Content-Type in upload status report 2010-09-20 fexsrv: IPv6 http support 2010-09-15 fac(CGI): fixed bug cannot delete and (re)create user 2010-09-15 fac(CGI): fixed bug cannot create user who was a recipient 2010-09-12 fexsend,fop: fixed bug resuming upload does not work with alias 2010-09-12 fup: fixed bug resuming upload handles autodelete and keep parameters incorrectly 2010-09-07 fac(CGI): fixed bug not working if there is no user at all 2010-09-05 fop: extra parameter keep=days 2010-08-31 install: fixed bug wrong ownership for spool files 2010-08-25 perl 5.8 required 2010-08-25 fexget: -s can write to named pipe or character special file 2010-08-21 fop: $limited_download checks dkey cookie instead of client IP 2009-08-20 removed mma 2010-08-18 fex_cleanup: fixed bug not expiring 2010-08-17 fac: fixed bug accept users without domain 2010-08-17 install: fixed bug empty $admin_pw 2010-08-15 fex.ph: optional fix address $sender_from (instead of F*EX user) in notification email From 2010-08-14 added optional spanish localization 2010-08-12 fup: speedup 90% 2010-08-12 fop: speedup 20% 2010-08-12 fop: better fexget compatibility (close connection after file delivery) 2010-08-11 fop: fixed IE download bug (missing header separating line) 2010-08-11 fop: fixed 1 min delay bug on AUTODELETE=YES 2010-08-08 sex: support for compressed streams 2010-08-08 sex,sexsend: removed unneccesary text mode (option -t) 2010-08-08 sex,sexsend: speedup factor 5 2010-08-08 added sexxx 2010-08-06 sex: fixed various bugs in client and server 2010-08-06 fac(CGI): fixed bug AKEY not working 2010-08-03 xx: no user inquiry for postprocessing if output is a pipe 2010-08-02 added optional german localization 2010-07-31 separated subusers in extra file $SPOOL/$USER/@SUBUSER 2010-07-25 fop: log also aborted downloads 2010-07-23 added fac CGI 2010-07-18 fexsrv,fup,fexsend: extra XKEY download with short // URL 2010-07-18 fexsend: fixed bug CHECKRECIPIENT not working 2010-07-16 added cookie support (for AKEY and SKEY) 2010-07-16 fup: fixed bug showstatus window too small for close button 2010-07-13 schwuppdiwupp: added CHECKRECIPIENT 2010-07-12 fop,xx: allow several concurrent downloads of STDFEX 2010-07-10 fop: workaround for stupid IE download bug 2010-07-03 fex.ph,fex.pp: new config variable @remote_domains 2010-07-01 fexsrv,fex.ph: new config variable $force_https 2010-06-29 fop: new config variable $limited_download with default NO => allow multiple downloads through proxy farm (varying IPs) 2010-06-29 fop: note every successful download in spool file "download" 2010-06-25 fexget: fixed bug download status info update too often 2010-06-23 fur: better sendmail clone compatibility: use space instead of comma as address separator 2010-06-19 fexget: new option -o overwrite mode 2010-06-19 fexget: use ./$file.tmp for downloading instead of $HOME/.fex/tmp/ 2010-06-16 schwuppdiwupp: edit and select address book entries 2010-06-15 rup: fixed bug case sensitive recipient address 2010-06-12 fop: send X-File-ID on HEAD request, too 2010-06-12 fexget: added support of X-File-ID 2010-06-11 schwuppdiwupp: (chunked) multi-POST for proxy with 4 GB limit 2010-06-11 schwuppdiwupp: X-File-ID support 2010-06-08 fup,fexsend: (chunked) multi-POST for proxy with 4 GB limit 2010-06-06 fup,fop,fexsend: protocol extension X-File-ID (contains mtime of file) is the successor of X-Size for more reliable resume function 2010-06-02 schwuppdiwupp: added proxy support 2010-05-31 fexsend: fixed bug windows path elements in filename 2010-05-30 better server proxy support: AKEY and SKEY no longer rely on client ip 2010-05-29 fexsend: added proxy support 2010-05-28 fur: allow registration confirmation more than once 2010-05-27 fexsend: added option -b bounce (copy-forward) 2010-05-26 fup,foc: added copy-forward feature 2010-05-20 fexsend: fixed bug uninitialized value with option -@ 2010-05-20 fur: fixed bug $main::admin not declared 2010-05-17 fexsend: added option -H for hints 2010-05-17 fexsend: added option -A for edit server address book 2010-05-16 fexsend: added HTTPS proxy support 2010-05-16 fup: fixed bug uninitialized value (line 1059) 2010-05-13 fup: fixed bug ignored KEEP and AUTODELETE options for groups 2010-05-12 fup: fixed bug ignored autodelete option from ADDRESSBOOK 2010-04-30 fup: fixed bug uninitialized value with CHECKRECIPIENT 2010-04-30 fexsend: no SID for https 2010-04-28 fup: fixed bug case sensitiv group addresses 2010-04-27 fexsend: fixed bug ignored server address book options 2010-04-27 fexsend: displays recipients and options before starting post 2010-04-27 fup: fixed bug ignored server address book autodelete option 2010-04-26 fexsrv: log all HTTP headers (no more ignore list) 2010-04-25 fexsrv: accept HTTP header with continuation lines 2010-04-22 fex.pp: added htdocs/header.html support 2010-04-22 fex.ph: added variable @H1_extra organization link and logo 2010-04-20 fexsrv,fexsend: HTTP header X-Timeout (info server->client) 2010-04-20 fexsrv: logging with locking 2010-04-19 fexsend: removed broken option -A and replaced it with more flexible feature "." for recipient address 2010-04-19 fexsend: fixed bug dies if sender is subuser (ADDRESS_BOOK error) 2010-04-19 fup: fixed bug no COMMENT in notification email 2010-04-19 dop: fixed bug error output with non GNU file command 2010-04-17 fexsend,fexget: added option -i for alternative accounts or servers 2010-04-12 fexsend: new verbose output format --> <-- 2010-04-11 fexsend: added option -Q quota query 2010-04-09 fup,fac: added quota support 2010-03-25 fup: fixed bug "Insecure dependency" when using AKEY parameter (eg: sending a second file) 2010-03-25 fup_template.html: fixed bug upload status window always shows "ERROR: no file data received" 2010-03-24 fexsend: fixed bug dies if there is no server address book 2010-03-22 FIX.jar: fixed bug interpret HTTP response "200 OK" as error. 2010-03-20 fup,fop: set mtime on user directory for last successfull access 2010-03-19 fexsend: fixed bug abort on short address if there is no server address book 2010-03-19 fex_cleanup: better cleanup for dkeys directory 2010-03-18 fup: fixed bug cannot DELETE with group recipient 2010-03-17 fup: fixed bug wrong success message on aborted uploads 2010-03-17 fop: fixed bug cannot handle @group names 2010-03-16 fup,fuc: fixed bug mixed case in F*EX group names and addresses 2010-03-14 fex.pp: do not send notification emails on empty files 2010-03-14 fup,fuc: added F*EX groups 2010-03-12 fup,fop: fixed bug case sensitiv FROM and TO addresses 2010-03-05 fup: fixed bug aliases are not accepted with fop_auth 2010-03-04 fexsrv: use CGI login if it exists as start-page 2010-02-26 fexsend: first check server address book, then mutt aliases 2010-02-26 fop: do not terminate session after ADDRESSBOOK request 2010-02-18 fexget: fixed bug always append existing file, ask for overwriting 2010-02-08 fexsrv: fixed bug uninitialized value in substitution (line 229) 2010-02-08 fex.pp: better qmail compatibility (space separated addresses) 2010-02-07 fac: fixed bug uninitialized $EDITOR environment variable 2009-12-28 fup,fop,fexsend: protocol extension X-Size for more reliable resume function (checks size of file) 2009-12-09 FIX.jar: can send more than one file (in zip archive) 2009-12-04 fex_cleanup: fixed bug send unnecessary reminder on AUTODELETE=NO 2009-11-26 fexsend,fexget,fup: added -z option for logfile inquiry 2009-11-13 fup,fuc: keep and autodelete options in server address book 2009-11-12 fexsrv: support for HTTP/1.0 persistant connections (for proxys) PID:SID in fexsrv.log CONNECT string (debugging help) 2009-11-06 added error.log 2009-11-03 fex_cleanup: also cleanup $SPOOL/.reg directory 2009-10-23 fup: added X-FEX-Filesize header in notification email 2009-10-18 fup: also test if $FROM is a valid email address 2009-10-11 fex_cleanup: fixed bug no cleanup at all on AUTODELETE=NO 2009-09-25 fex.pp: added X-Mailer in sent mails to please stupid spamfilter at hotmail or gmail 2009-09-02 fur,fex.pp: fixed bug not removing quote chars in qqq strings 2009-08-28 rup: fixed bug UTF-8 file names 2009-08-25 FIX.jar: accepts parameters TO, AKEY and SKEY (for subusers) 2009-08-24 fex_cleanup: fixed bug warning unitialized variable 2009-08-17 fex_cleanup: fixed bug typo mitime --> mtime 2009-08-12 fup: fixed bug "send another file" for subusers 2009-08-10 fexsend: fixed bug timeout on big archives 2009-07-27 to and from addresses in spool are now always localpart@domain, 2009-07-27 install contains automatic spool converter 2009-07-27 fup: fixed bug short aliases address list mismatch 2009-07-24 fup,fex_cleanup: fixed bug delete all files for multiple recipients after any download 2009-07-24 fexget: fixed bug delete local file before download 2009-07-20 fup: added autodelete and keep hack for HTML form 2009-07-18 fup: fixed bug leading . in file directory name 2009-07-18 fup: added CHECKRECIPIENT support 2009-07-18 fup: code cleanup, new 3-stage user interface 2009-07-18 fexsend: added CHECKRECIPIENT feature 2009-07-17 fexget: fixed bug wrong UTF8 handling 2009-07-16 fop: fixed bug sending wrong file size if TO or FROM has uppercase chars ==> resuming upload did not work 2009-07-11 fup: can select more than one address from address book 2009-07-08 fup,fex.pp: fixed bug wrong download URLs 2009-07-07 new spool directory layout $TO/$FROM/urlencode($FILENAME) 2009-07-07 fup: be more restrictive in accepting (illegal) parameters values 2009-07-07 fup,fuc: subuser access key name is now SKEY (KEY is depreciated) 2009-07-07 rup: new HTML layout, fixed bug in file select box 2009-07-06 fup: substitute all control characters in file name and comment with "_" 2009-07-02 better install script, guesses IP 2009-06-29 changed spool directory layout $TO/$FROM/$FILE --> $TO/$FROM/md5h($FILENAME) to avoid filename collisions 2009-06-28 added mailman authorization mma 2009-06-28 fup: better address-book integration 2009-06-26 FIX.jar: fixed several bugs, now working with Windows Vista, too 2009-06-25 added fup_template.html as an example for customizing upload page 2009-06-22 fup,fexsend,fexget: LIST also shows COMMENT 2009-06-10 default timeout 10 s --> 30 s 2009-06-01 fexsend: show transfer status on STDERR (also for xx) 2009-05-31 fexsend,fexget: show transfer rate (kB/s) 2009-05-29 fexsend: auto-reconnect after SIGPIPE (link failure, etc) 2009-05-26 fexsrv: ignore HTML anchors in GET requests (from stupid msnbot) 2009-05-17 fup: check if there is enough free space in spool 2009-04-07 new perl based install; requires server IP for xinetd binding 2009-03-25 fexget: fixed bug saving failed if on other partition then FEXHOME 2009-03-25 fexget: fixed bug calculated wrong transfer rate 2009-03-25 fexget: changed default answers to more secure values 2009-03-24 fexsend: new option -l for listing sent files 2009-03-24 fup: support for listing sent files 2009-03-24 fex.pp: default charset is now UTF-8 in HTTP reply 2009-03-16 fur: fixed bug no lower case transformation for user and domain 2009-03-05 fop: fixed bug no parallel download possible on multiple recipients 2009-03-03 dop: send Last-Modified HTTP header (java needs it) 2009-02-27 fuc: send information emails to sub-users by click-on-address 2009-02-22 fop: fixed bug download failed without FROM parameter 2009-02-20 test for /usr/lib/sendmail and /usr/sbin/sendmail 2009-02-18 fop: fixed bug file size query for alias recipient 2009-02-18 fexget: added option -a to get address-book from server 2009-02-17 fup,fuc: better linking 2009-02-14 fup: first send notification emails, then send HTTP 200 OK to client 2009-02-14 fup: accept ADDRESS_BOOK as upload 2009-02-13 fup,foc,fuc: added ADDRESS_BOOK support 2009-02-13 added fix and FIX.jar (Java applet client) 2009-02-11 fop: fixed bug file size request with multiple $to gives always 0 (no upload resume possible with multiple recipients) 2009-02-11 fop: check for valid recipient address (in file path) ==> early abort possible when client uses illegal address for upload (resume-HEAD-request) 2009-02-10 fur: catch errors from sendmail(clone) and save them to $log 2009-02-09 fexsrv: fixed bug wrong log sequence in debug files 2009-02-04 fup: fixed bug cannot delete files by web interface 2009-02-03 fexsrv: fixed bug wrong download URL by HTTP_HOST from client request 2009-01-31 fexsrv: fixed bug handling of missing trailing / in doc requests 2009-01-30 rup: fixed bug wrong download URL in notification email 2009-01-26 fexsend: archive format 7z and zip with default compression 2009-01-26 fup,fuc,foc,rup: link to F*EX start page in top header 2009-01-21 fuc: URL for subusers with KEY parameter 2009-01-21 fup.fuc,foc: fixed bug wrong AKEY lookup 2009-01-20 fexsrv: better handling of URLs with trailing / (==> index.html) 2009-01-20 fop: fixed bug endless loop with fop_auth mode 2009-01-13 fup,fop: support for MIME-file types 2009-01-13 fexsend: added option -M for MIME-file to be displayed in webbrowser on download 2009-01-04 fup: increase minimum timeout to 10 s 2008-12-26 fup: do not allow re-upload (overwrite) if file is in download process 2008-12-23 sexsend,sexget: added HTTPS/SSL support 2008-12-21 fup: fixed bug removing old autodelete and error files failed 2008-12-20 added logwatch 2008-12-18 fexget: fixed bug responsiveness on slow links 2008-12-18 fexget: fixed bug save file name for archives 2008-12-12 fexget: better responsiveness on slow links (modem, ISDN) 2008-12-12 fup: added warning for incompatible clients (konqueror, etc) 2008-12-11 fexsend: allow comments in ID file 2008-12-03 fup,fex.pp: fixed bug UTF-8 subject in notfication email 2008-12-02 fexsend: better responsiveness on slow links (modem, ISDN) 2008-12-02 fop: send UTF-8 filename in HTTP header Content-Disposition 2008-12-02 fexget: save original filename (parse HTTP header) 2008-11-28 fexserv: added special FlashGet (download sucker) brake 2008-11-28 html error messages now with HTTP_HOST und server-time info 2008-11-27 added htdocs/version and htdocs/tools.html 2008-11-27 added fexsend, fexget, sexsend, sexget to htdocs/download 2008-11-27 dop: fixed bug symlink of symlink leads to hangup 2008-11-27 fop: teergrub download managers and other suckers 2008-11-26 fop: with URL parameter ?KEEP file can be downloaded more than once 2008-11-26 fexget: added option -k for keep on server 2008-11-24 fex_cleanup: fixed bug $autodelete not defined 2008-11-24 fexget: added HTTPS/SSL support 2008-11-22 fexsrv: reject requests with IP hostnames in HTTP Host header 2008-11-21 fex.ph,fop: $autodelete="DELAY" allows file download many times (but only from same IP and until next fex_cleanup run) 2008-11-21 fup,fop: fixed bug options keep and delete autodelay do not work with spool on NFS 2008-11-20 fexsend: added HTTPS/SSL support 2008-11-20 fex.ph: added config variable $autodelete 2008-11-20 fup: fixed bug subuser cannot send files 2008-11-19 use md5-hash of $from:$id instead of URL parameters FROM=$from&ID=$id 2008-11-19 fac: set correct exit status 2008-11-16 fup: fixed bug DELETE not working 2008-11-16 install: do not overwrite lib/fup.pl (perhaps contains site config) 2008-11-15 fex_cleanup: clean up $SPOOL/.ukeys/, too 2008-11-14 fup: show "user config" link only after authorization 2008-11-13 foc,fuc,fup: quick sub-user creation with auto-notification. 2008-11-10 fexget: fixed bug query <> instead of 2008-10-29 fup: do not require HTTP authorization if request already contains ID (methode used by xx) 2008-10-28 fex.pp: fixed bug $warning not defined 2008-10-28 fup: fixed bug do not allow subuser in fop_auth mode 2008-10-27 install: do not overwrite existing htdoc/index.html 2008-10-27 fup: fixed bug resend (SEEK) leads to HTTP error 666 2008-10-26 fexsrv: accept HTTP request with absolute URLs (http://...), too 2008-10-23 fexsrv: fixed bug continue connect logfile entry 2008-10-17 fexsrv: fixed bug keep_alive with HTTP/1.0 2008-10-17 fexsrv: fixed bug wrong warning in debug mode with empty line 2008-10-07 fexsrv: moved TIMEOUT message to debug.log 2008-10-06 dop: fixed bug opening file (did not deliver any file!) 2008-10-06 dop: implemented HTTP keep-alive (delivering more than one document per session) 2008-10-04 if config variable $fop_auth is set, download requires 2008-10-04 authentication and upload is restricted to registered users 2008-10-02 dop: declare exectuable scripts as application/octet-stream 2008-10-02 fup: added link to Windows client schwuppdiwupp.exe 2008-09-29 write upload speed to upload directory 2008-09-17 fac: fixed bug locating FEXLIB 2008-09-12 fup: added config lib/fup.pl 2008-09-05 fexsend: added rudimentary windows support 2008-09-03 dop: redirect on relative non-parent symlinks 2008-08-31 added fur (F*EX User (auto-) Registration) 2008-08-25 will die when no hostname is available 2008-08-21 added fexsend to htdocs/download 2008-08-21 fup: added ID mail sendback option 2008-08-20 fac: added -l option 2008-08-19 fexsrv: fixed bug SSL handling 2008-08-15 fup,fuc,fexsrv: dynamic protocol detection (HTTP/HTTPS) 2008-08-14 fup: fixed bug login possible with wrong login data (but no upload) 2008-08-13 fup: showstatus terminates immediately when empty file was uploaded 2008-08-13 fup: showstatus shows error message on illegal recipient address or when no file was uploaded (nececessary for stupid Internet Explorer!) 2008-08-11 splitted debugfiles with time stamp in filename 2008-08-11 fex_cleanup: clean up aborted uploads, .ukeys/ and .debug/, too 2008-08-11 fexsend,fexget: allow more than one file (with all options) 2008-08-08 fup: eliminate superfluous newlines in logfile on error handling 2008-08-08 changed bareword filehandles to indirect filehandles 2008-08-06 fup: decode %NUMBERs in file names from POST 2008-08-02 fexsend: bug fix -A option and argument handling 2008-08-01 fup: regular users can change the recipient in the upload form, sub users can not 2008-07-31 fup: fixed bug internet explorer not showing upload status window 2008-07-31 fup: fixed bug with id / special id / real id mixup 2008-07-31 fuc: nearly complete rewrite, better user interface 2008-07-30 fup: fixed bug when account is a symlink 2008-07-30 fup: fixed bug in authentication of subusers 2008-07-03 fop: workaround for Internet Explorer download bug 2008-07-02 fup,fop: switched default charset from ISO-8859-1 to UTF-8 2008-07-02 fup: uid for showstatus synchronization 2008-06-21 fexget: downloading without wget, file number as argument 2008-06-20 fexget,fop: added DELETE option 2008-06-20 fexsend: send more files in one run 2008-05-30 added missing sex to distribution 2008-05-30 fexsend: added -A archiv to yourself option 2008-05-28 fup: fixed bug in LIST and DELETE commands 2008-05-27 fexsrv: correct HTTP redirect on missing trailing / in URL 2008-05-26 sex,sexsend: better public mode 2008-05-24 sex,sexsend: added text mode option 2008-05-23 added missing foc and rup to distribution 2008-05-20 fexsend: fixed bug in list parsing (-l option) 2008-05-20 dop: fixed bug in file type determining on symbolic links 2008-05-15 fexsrv,dop: fixed bug in HTTP keep_alive multi-requests 2008-05-02 fexsrv,dop: support for HTTP keep_alive multi-requests 2008-05-02 fexsrv: more robust header parsing (ignore superfluous spaces) 2008-04-28 added support for HTTP keep_alive 2008-04-28 fexsrv: added SID (session ID) support 2008-04-28 fexsend: encrypt ID with MD5 and SID 2008-04-20 added foc and rup 2008-04-20 fop: return apropriate error message when file has been (auto)deleted or is expired; error message is kept 3*keep_default days 2008-04-19 install: do not overwrite old fex.ph, but create fex.ph_new instead 2008-04-18 fup: fixed bug filename with path in notification email 2008-04-16 fexsrv,fop,dop: implemented HTTP HEAD 2008-04-14 renamed cgilaunch to fexsrv 2008-04-14 fup: do not send notify-mail if file already exists (overwrite mode) 2008-04-14 fup: do not accept file if authentication fails 2008-04-14 fup,fop,fexsend: new secure download URL scheme with random dkey 2008-04-11 fup: fixed bug in upload bar with 8-bit file names 2008-04-11 fex_cleanup: fixed bug not removing aborted uploads 2008-04-10 added F*EX camel logo 2008-04-09 added dop (generic document output) 2008-04-09 install: better infos 2008-04-08 renamed confusing ID to auth-ID (request by chris@citecs.de) 2008-04-08 fuc: fixed bug with more than 1 sub-user 2008-04-07 fup: readded keep parameter (code got lost sometime?) 2008-04-07 fup: added sender restriction (ALLOWED_RECIPIENTS) 2008-04-07 fac: added restriction option -r and delete user option -d 2008-04-06 fup: use Net::DNS instead of external host command 2008-04-06 fup: more debuglog, fixed wrong error messages 2008-04-06 added doc/concept doc/FAQ 2008-04-02 install: better error handling (patch by chris@citecs.de) 2008-04-02 more docs and improved logging 2008-04-01 cgilaunch: fixed bug in determing REMOTE_HOST when using stunnel 2008-04-01 fexget: added -s streaming option 2008-04-01 sex,sexsend: added public mode 2008-03-31 changed project name to F*EX because of name collision with http://freshmeat.net/projects/fex/ 2008-03-31 added sex, sexsend and sexget to distribution 2008-03-28 xx: changed syntax, now compatible to zz 2008-03-28 added zz to distribution 2008-03-27 fup: fixed bug in mail address verification 2008-03-24 fup,fexsend: show transfer rate in kB if filesize < 2 MB 2008-03-24 fup: code-cleanup, more comments 2008-03-24 fex.pp: umask 077 2008-03-23 fup: fixed bug in using multiple recipients 2008-03-22 first public release 2007-01-27 first file fexed via fex.rus.uni-stuttgart.de 2007-01-15 first file fexed via wwwtest6.belwue.de 2006-11-?? first code fex-20160919/doc/Contribs0000644000174700017470000000261612770010174013172 0ustar fexfexBeate Herrmann : - artwork Sebastian Zaiser : - upload status window Bernd Strehhuber : - dynamic protocol detection Kurt Jaeger : - ipv6 support Andre Hafner : - web admin interface fac - VM Martin Lauer : - FAQ Javascript Code Dominik Greibl : - java client F*IX Sebastian Roth : - many bugfixes and extensions (zip, proxy-support, etc) for F*IX Daniel Dieckmann - fexget proxy support Kilian Krause - Debian package maintainer - SSL security enhancements - annoying, but useful requests ;-) Hanno Hirsch : - bug hunting Nicola Fioravanti (http://revshell.com): - Penetration tests and security debugging Waldemar Bronsch : - German localization Tobias Gunkel : - German localization Hans-Georg Bickel : - Swabian localization Francisco Ruiz : - Spanish localization Anton Meixome : - Galician localization Vanni Piagno : - Italian localization Michal Simunek : - Czech localization Jean-Baptiste Denis : - French localization fex-20160919/doc/IPv60000644000174700017470000000072512770010174012172 0ustar fexfexTo enable IPv6 on the server you need: - The Perl module Socket6 You can install it on Debian or Ubuntu with: apt-get install libsocket6-perl - Add to /etc/xinetd.d/fex the line: flags = IPv6 and remove the "bind" option line. Restart xinetd. To enable IPv6 for fexsend, fexget and sexsend you need: - The Perl module Net::INET6Glue::INET_is_INET6 You can install it on Debian or Ubuntu with: apt-get install libnet-inet6glue-perl fex-20160919/doc/Licence0000644000174700017470000001352512351111777012760 0ustar fexfexF*EX (Frams' Fast File EXchange) is a service to send big (large, huge, giant, ...) files from a user A to a user B via internet. Copyright (C) 2006-2014 Ullrich Horlacher YOU ARE NOT ALLOWED TO USE THIS SOFTWARE FOR MILITARY PURPOSES OR WITHIN MILITARY ORGANIZATIONS! THIS INCLUDES ALSO MILITARY RESEARCH AND EDUCATION, PARAMILITARY AND TERRORISTIC ORGANIZATIONS! This program is free software: you can redistribute it and/or modify it under the terms of the Perl Artistic Licence: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whoever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. fex-20160919/doc/SEX0000644000174700017470000000662412770010175012052 0ustar fexfexSEX is a F*EX companion: Stream EXchange You can imagine SEX as network wide UNIX pipes with a relay between. This can be usefull for piping data from A to B where A and B cannot establish a direct connection, but both can connect by HTTP to the SEX-server. SEX is a synchronous service in conjuction to F*EX which is asynchronous. For seamless integration into the UNIX tool chain, there are the shell-tools sexsend and sexget. Using web browsers for sexing will not work, because they cannot handle streams in a pipe. So far, there are only the UNIX clients. Feel free to implement other clients for other operating systems :-) Authentication is the same as with F*EX. Example: root@lanldap:/var/log: tail -f syslog | sexsend framstag@rus.uni-stuttgart.de framstag@blubb:/tmp: sexget | grep ldap If you need encryption, then use the standard UNIX toolbox and add a appropriate program to the pipe, for example: openssl bf Tips for using SEX for file exchange: I have a lot of (administrative) accounts on even more hosts, where I have to exchange a lot or big files. These hosts often cannot make direct tcp-connects to each other, because of IP-filters, firewalls or missing server software. Only outgoing connections are possible. Therefore NFS, ssh or even ftp are no option. Since today my solution was F*EX: 1) on source host send the files within a container to the F*EX-server: fexsend -a container.tar file1 file2 ... . 2) read or copy the FEXURL with mouse 3) on destination host get container.tar from F*EX-server and extract it: fexget FEXURL tar xvf container.tar rm container.tar Backdraws: - a lot of manually work - creation of container.tar needs (a lot of) time - container.tar needs (too much) disk space on source and destination host and on the F*EX-Server Small solution: Usage of xx (wrapper for fexsend) eliminates manually handling of container.tar. But it will be still created, only automatically. The ressource problems are still there. The new sexy solution: I use SEX (Stream EXchange) instead of FEX (File EXchange)! There is no more a temporary container.tar, but the files are transfered as a stream with the new client sexxx! An example (*): On the source host: root@obertux:~/bin# sexxx . streaming: ./ ./autopatch ./subsys ./pwsync ./cspread ./fspread ./spread ./iptconf ./esxbackup ./esxlist ./getxx ./rscreen On the destination host: framstag@flupp:/tmp: sexxx extracting from stream: drwxr-xr-x root/root 0 2010-08-06 12:48 ./ -rwxr-xr-x framstag/users 170 2010-01-20 13:26 ./autopatch -rwxr-xr-x root/root 336 2006-02-02 15:15 ./subsys -rwxr-xr-x root/root 278 2010-01-18 23:38 ./pwsync lrwxrwxrwx root/root 0 2009-11-03 15:49 ./cspread -> spread lrwxrwxrwx root/root 0 2009-11-03 15:49 ./fspread -> spread -rwxr-xr-x root/root 10354 2010-02-12 14:49 ./spread -rwxr-xr-x root/root 1380 2010-01-14 08:54 ./iptconf -rwxr-xr-x root/root 116 2010-05-04 18:36 ./esxbackup -rwxr-xr-x root/root 344 2010-05-06 13:33 ./esxlist -rwxr-xr-x root/root 93 2010-08-06 12:32 ./getxx -rwxr-xr-x 1000/users 173 2009-11-26 13:40 ./rscreen Now I can transfer any files from a new installed (VM) server to my admin workstation behin a firewall. Or the other direction. (*) The example above has only a few kB, but one can use sexxx for many GB or even TB! On my VMs I get a throughput of 90 MB/s. fex-20160919/doc/SSL0000644000174700017470000000413212770010175012044 0ustar fexfex# http://www.stunnel.org/faq/certs.html # execute this as root! # Redhat+CentOS : stunnel does not work! you need to install stunnel-4 # # Debian+Ubuntu : stunnel-5 does not work! you need to install stunnel-4 # # apt-get install gcc make libssl-dev # yum install gcc make openssl-devel # cd /tmp # wget ftp://ftp.nluug.nl/pub/networking/stunnel/archive/4.x/stunnel-4.57.tar.gz # tar xvzf stunnel-4.57.tar.gz # cd stunnel-4.57 # ./configure --prefix /opt/stunnel-4.57 # make # make install # ln -s /opt/stunnel-4.57/bin/stunnel /usr/local/bin/stunnel4 mkdir /home/fex/etc cd /home/fex/etc/ # create self-signed certificate # see http://www.infodrom.org/Debian/tips/stunnel.html openssl req -new -x509 -days 9999 -nodes -out stunnel.pem -keyout stunnel.pem dd if=/dev/urandom count=2 | openssl dhparam -rand - 1024 >> stunnel.pem openssl x509 -text -in stunnel.pem chmod 600 stunnel.pem cat <stunnel.conf debug = warning output = /home/fex/spool/stunnel.log cert = /home/fex/etc/stunnel.pem sslVersion = all fips = no TIMEOUTclose = 1 exec = /home/fex/bin/fexsrv execargs = fexsrv stunnel EOD ## https://www.stunnel.org/pipermail/stunnel-users/2013-October/004414.html #case $(lsb_release -a 2>/dev/null) in # *CentOS*) echo 'fips = no' >>stunnel.conf;; #esac chown -R fex . stunnel=$(which stunnel4) if [ -z "$stunnel" ]; then echo "no stunnel4 found" >&2 exit fi cat </etc/xinetd.d/fexs # default: on # description: fex web server with SSL # note: only possible on port 443! service fexs { socket_type = stream wait = no type = unlisted protocol = tcp port = 443 cps = 10 2 user = fex groups = yes server = $stunnel server_args = /home/fex/etc/stunnel.conf nice = 0 disable = no } EOD /etc/init.d/xinetd restart echo 'To enforce https, add to fex.ph:' echo '$force_https = 1;' # Hint: on some systems stunnel works not well with xinetd # you can also run stunnel without xinetd, in server daemon mode fex-20160919/doc/fex-client_1.pdf0000644000174700017470000002203412770010175014432 0ustar fexfex%PDF-1.4 %쏢 5 0 obj <> stream xWMoF؛e#G.(6idVdrΒd6 XǙyogg=aB? >4H%W j(nBH":A%bL2M)vX <%C7,z>.hoyOf'A4yZC H R9 VCMt<_W8Ya,: Aa%Y&W/Gꭔ"R;l!R H#`sHEaTzsDM+=#s~?!HW+RI}Ȕs QHrD3*qH$X:bݨʉ)TȄ6)sS=JF,KjD}:Y$hWiytךQGLJZM:;% &~n*_k8 0qoS)B 06- F-3X?AD8cPm7 Ag@GrqBX!Gez`oԑド#4ݙ$D"a|FDH3Dd*dBtsSH9.j߹@ a~1;sP>4|bPi4F(훪7܀ω&TlT4pI53h5/J׉ B8 CGzmؓs+8=e%EDq\ĔG2A:1gXZd v7 aU)؈h J$6tMl7Ds Ñe 2rv:LVVҹAuLV)էpYw~e#3FQ0̿ro*؞er/bP{ZOϗ@ 68u١A>;Y~hO5~w9_:WݭEnWMs{g[y|s\qTZ2^Ɨw捏]rÄt2]* ڇ-uڕCqlI%c;RXEoOE~<}.֭SUc-7+n:7oWkAIsV+B0ݳŮ:<8pWfe54_@1۷׫laLVc(&~endstream endobj 6 0 obj 1181 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 10 0 obj <> endobj 11 0 obj <> endobj 8 0 obj <> endobj 13 0 obj <> endobj 9 0 obj <> endobj 12 0 obj <>stream xmW TS׺>1s@+i؄:թjm @A)$̙'0m$0&LQuVի^}}wvuZuVV~hs37D @|2Pҗtاm‘N]qQNVvIК֭[6MPXfqN?hRgK EycAY<^ZA!AAQY~az1XAЂCa#ve)Ύ*9\,/Κ^[CXm" ,ۃmVbQ^l3 ;}Ƣ}X !bqX8vۅB@9,sa E [m@c>;  \ǧ;4Ì!| >J?<ܓ ,\Y%{| ;^?,5,X7~dz( 92E-]phY+-6xaxw]e@U -Y@pIT$:P^n%@ŹEc7\+sFrԩg| Z3 ܍D.U(MY 8V*ޫ@3&ܶXSuE%E̯ (X)zI W~v[ܴ;:ԓ,Q*/?? .{GEBz=wG2stO_u 4c(ß,o .UҘ'xE]$[_–Z0bQΥ6c(P/ \v>ݏCjjXX"8|NSGb(*g9/roL,c"Iզ!dGP)EpV7f>"EvcX5G83_!gZȃ;䯣47$s"c9,-cʤJ!(2̐ؒ`:B@0@l}󣨫~@_drkBܺ3l_~0`)w /9ҹcҙeL'g%3KQ>[~|B?,sMIʊG7kL` TỨ?@qB)*y μ w]#9_ܴ_ayk`\v YVNKaGk'Ё؂Bna&]"$!uv^1 &ȏ³^<6 ^.Y6"…ںF8~6.c?YFS } F!),D02\!hlE @bm̾bTW} f-:"yr.09?}'O3t#˪omDW4KqW"6|^bXu+fNܬfw9s%a|Ɩf)"Dn| uܑ79sd.ن  B@l)ܕy#+%\BYyRW S~{{g#c;[WZs`ej1聣RcC`pYS!'(K }@=}#gh;ma]qNuK[8 8N>v'γę&+EYH7"ED#"(wU^>͝mp~A@>\ wJ'ѩh |s= dU*FuumT n*-/ |/*>pGI˹B{1S9φGh>jA%,Tx {on6OPpA6KfϾvz-Ѿ2M,2U{J4M AI2VAI@^hqt,:Idc(es9yU2FeJ%jܶ`X7I.?'Nq݉'s]2PL|kK)aRپ fj DVТdã@կS\N cN9}y–D_$߱˭gt};Y|UHV! ~Y JA\*()wb˴ïUrLU LC#-.g|7gWuzYO g8pJe)R/ e'Mqjm ͷ i胊5g6G"C|ꙵK5kZfTѬBe]\$C=TqQUeSPW+k怕QgFEzEjzr\LZ 6h | `ϸl=D?Gg$m@";_YUUW6\X{A6 auH_YWUWbz uJH6FHcz\o\1m:TM6*U1W9ДJ`.SDJ_ fMIH6ls&L׵ efJ v0YpZܯz/qfxљUˠίC6H;sq#a``kko#{Z"&p @獓dH}. |uo$re uZ\EԓĆ%NaGgȭn1#orc8qj&5T(3>|"ezd۹iZv2hkFבU)2@d Nsqp.@Z@Q~ >tj-zn&q)5E62s*UW]JlxThĥւ`.k&R lxa]~a:f\__qŀ wQ'/BPϰڭ(7̽ϪKh(|o}0# FӸ-8Q0 WX}02+Qȉ99wEOw >ZHd +*+R?(f/;fV4?;uLɊh`(QXn_Ro/h-*4,A#`|>/Ӈݬ;gz&o|l~4A+۽v.8( Et:ԑ1ZI]akŕ"-G[PepaSFX^&v岻xve+ ڬn905hq`1.CR&(ŜR2ofM"dBePim@M3D-a$H&;gʹC^CaIuG5%("J3`265ۑ2ѣsJF1SLus4J9]\au<cmL3Ph24y1ǹ~B'NFGzM?j] endstream endobj 14 0 obj <>stream UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 15 0000000000 65535 f 0000001496 00000 n 0000008830 00000 n 0000001437 00000 n 0000001286 00000 n 0000000015 00000 n 0000001266 00000 n 0000001561 00000 n 0000001662 00000 n 0000002163 00000 n 0000001602 00000 n 0000001632 00000 n 0000002512 00000 n 0000002076 00000 n 0000007466 00000 n trailer << /Size 15 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 8953 %%EOF fex-20160919/doc/fex-client_2.pdf0000644000174700017470000002754212770010175014444 0ustar fexfex%PDF-1.4 %쏢 5 0 obj <> stream xX]s}_z4쑠7V7Hte9;t+.IX`"e C ~!%et-ƆQ# fD *$HYRUJb[*[a*LTL1jmD R"r 5 |`TqR@<5\&29QɺJXAEU2llFXƨAXi)a֘nEg=>&AأOUDJ\. T HX1нb6Q ;S> *J|l5#H ""p\vO 5 ҇}Ro}AܖթP\'TJڲz-b*(.SkHu­KnI-ΆƓs{VVȈ(*.<j c^:X*ۅZKrhҮPq:?]]qq;`gDNÐv?;Knn'q4y;UْZN?ˇNMs>6zٝ!/t7;eO7RJ;C,wr{h~'ؒ$ 6tF~@[%;3q#*n׿9h۴]Cwd^vEF-O/j}v49;rѝ-^]TϏ.SUy,Mpi\~P endstream endobj 6 0 obj 1980 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 10 0 obj <> endobj 11 0 obj <> endobj 8 0 obj <> endobj 13 0 obj <> endobj 9 0 obj <> endobj 12 0 obj <>stream xux XS׺!ٻ֡%ݚMhkZB hPa@F0-0d0 (jjОt!////#xd$ĥx,cĒ䘔̷=bqQ8<5>#رce$ TIK/{]zJc#Y3;/G n ݷMrlwjL;>i~vdLܕ;;8z,zm۫,۸vKWJy"x!U xXJ;ċDXC,#]r"MND o/:"%$ۈAb?M61XL70yyS:i/Y~os:.X \೅/ 6 Ջ/mџ\` 1e'_?=ZKe>hE*S?$.6uEI&M~9eG=2Ѣ۩i?W(!OmySC`;}TW 0WR.:6ًir 2f'åZn'8|՜jJ*HW胋($հ$tB 992L8X b%67'X` +| zi#*5N[\T/ےkRdUZL DW.3)ʔJ3҇><}.=/R?1.>>ZyP*e @ ͧ0F)͠'݀k]'a3.bN}P&O;>f8ly{?n~kV**% hm7]~j}X4`d'@WAɁ^a[=jY'ߩWh+/5LS 1 a.v肌ZPAz֠kǐ4o> _<\ՖHB PVG Ƈc.OY5?bO|DO$F!춓UVpb05-[$J.A9L ɸY4`5 dFNc'7)/eӧ8Vp1dvwyɅ:\MFN晵``ZY@eKwq#q{r[yO9KCus4Ah }EFzxcG3GA7́SM8!9vcpJɬuڿٰ֯тկ"!Z2 ׾GψzWѳsxc"ɹp?uusd=I6QG8*N_3*b> J AYY\*W;"BɘԚB*̒3߀.;N%!  V.Mץ3S8rnywPNuB &\[ֲ2 FFXmUUGiqfwX}$/ߡY_juŃ=E`ȅٜl1;G#@Y=XyxObV4 Xw6ob~~oٝ  4&@6w /^:}t@ؕdP.JSaw$zWW#Dƒ ;zkl3;lK3n.HГK~Cw'ވp$:($x$$\A;7&@岎~~sЊ@]4+#=RU Usm͜VnX~4?8Jfl>.P2:&eNy(-AKQʮE_^z.0⧔AE76 FI:W$S+33˃A8\2 F .^Xf^ξԈ4QZ>m+s!lj]e^py<]`??9za8B{|p p Sۏ\˫B_v6KR|dLmpCK_;H$S8AX/{f2FZ= Ra `+-up9-TTfr GZZ!YӹΊ6!\ߨ[Cp i'W3_ G361hkiUP-U9"TJ^ F,U% f]g*t5ZUf[;ۑ& qpVO&>&(wmN6H)V4)ZZU[W\Kr1/1E-Rm J}BRA,|/Z ;@?rhhk)+%U8{*LE^h)}`3=IE!"q PVo>84,CgD[=ghg"VXoǨw |L_<sh y[|# r"K "wOyg DŽ)_$?uJ[XFYP7>Z[|pJD[N*o: \4#bAd$4Ali [rԗ5U`yUZ؄l˯_|dt+BZe h t:G/u$m>Εϳ>qk?Cu'u%n`No|,T+ G/:!D&h9T=',+.G0Uz^l#+tf~&0#v5ݩv:TZr-V8}i1mNj-y\xfˉ;pWK`.u\^t8vTǣV̎ #⍯X59F#{ FrpVd( I&OFC.#c‘+mE0&;!MmO5q05l9ra[DaCEܶ墟?Y!O P0-<ة;r<XŒwcVRАk5bs)h[ K )ލwyu 5 ]*$/\| ޣ7]~ޮlZGCR\3$N%:\_/$yL(̦S33%Lg{Sc3)[̻,7B/ yK@lLV˂GJmLZ")by4oB7ciRg jmk}/yi|fm1V|_I?X ɯyUĿ)z~$h<]`U N~wM8<$yeg5gwb1Ă&). Zk'Wʂ퍩V`~{kWF+2k (6(*U4xg<M?G #̔#63 k?Q{,9,-5w\Q2}"S/{FLmJyMu aP(Kt5l;A\'jNi$8R*hmo\~C1QR8ov|3pPi4XGD\^97[|3ҦGcYQyITXUT LT[WX[~ڧGdIU DN 6,!كsO?>^ARPIr/9>,*ò8 <3 |Y36U2Qh`u|YXSk2s٬%; C6-}@TIQЂv2XUG|_^.#yƂ `+Zzsm]Z$; 'MV8Ϩ*_2$?,j1ucUVVy;+ΐX PmDSn0,}8ȣXbF]e$u}󴥴j*'\*\+062DYNP%&SKp]F'㨯>F+ T)Bq$ $L+I.Q׃x]@(vDӗMJBe +KY7&olrj#WLR R\顢 5P-%?Gp|qaRaۉSو!v^M-,rNs_cfHw{us]S~M ^Y❋^r~ chה|)IHs>gs4ݥ׎ǍG_h YMjT]FY}fLc{n82j,trz8%35Y;\ ٰYp ' SB|lH\\s~ó}6)!LpFWS'InbZB(jb%ʛG)C,>;D cǿ$o;ͽN 8 {5TI7){yQFoX#C*vnT4 Ag992u&! QWa*.KL/0$bE=hroe5-?,ѓъxD@nĩȳ,Џp8ѫsh <8(Dz['<OBCc#zz;!^(ZQ򚲲zS]6*eV1QUD:Fn(Ω)G7\M.o߇k-ⅼS&g: R}3Fȇ׻Zꜝ MM :z<.,0>+RȳF_FܞK :1\Nf=])En?uiłf$YZ]= HυWߞ ~~ A!YGcI $OC]75y)`ƈU׊0,O,fʡsv&O898L-uNctNct'F|}^{q05\jۮ8t~<O'wg7lX=N^5f_ݛtPmy.j4+Dk^F;.JtaE=trfFRJcVGWScGGzKLMS]5\H?d}7'|&9ҥҼf3X^P{&yD>} w30[ JJM_sMl]^6%XHWT@ kB2}%[6JdaRSf5&=TɏΞleD4 ;lhgC#s.VdS <_Vao7TX,Bu;446-:M=n)UYiH2cNi_a-T6[PK2YYC>Κ {Y-rjRR)Wd  R1 ^i2P2e4á:+3tHz1"^TUX[UnwWL=XJKjhQ_`E+Z&V&Y)Zh? PЇ>pV93!Q|(ʫ[XN ".ꈓNF ? v c';*yP?g.A?g endstream endobj 14 0 obj <>stream UnknownApplication Untitled endstream endobj 2 0 obj <>endobj xref 0 15 0000000000 65535 f 0000002295 00000 n 0000011712 00000 n 0000002236 00000 n 0000002085 00000 n 0000000015 00000 n 0000002065 00000 n 0000002360 00000 n 0000002461 00000 n 0000003006 00000 n 0000002401 00000 n 0000002431 00000 n 0000003466 00000 n 0000002919 00000 n 0000010348 00000 n trailer << /Size 15 /Root 1 0 R /Info 2 0 R /ID [<56C093A3A4E46A0AE015D16FB8906053><56C093A3A4E46A0AE015D16FB8906053>] >> startxref 11835 %%EOF fex-20160919/doc/new0000644000174700017470000000017412767765636012227 0ustar fexfexNew release on http://fex.belwue.de/fex.html Important changes: - new fex.ph config variable $purge - fixed various bugs fex-20160919/doc/version0000644000174700017470000000001512770010176013065 0ustar fexfexfex-20160919 fex-20160919/locale/0000755000174700017470000000000012700745703012157 5ustar fexfexfex-20160919/locale/translate0000755000174700017470000001017712654505451014112 0ustar fexfex#!/usr/bin/perl -w # translate english F*EX files into locale languange use File::Basename; use File::Copy; @trfiles = qw( lib/fex.pp cgi-bin/foc cgi-bin/fop cgi-bin/fuc cgi-bin/fup cgi-bin/fur cgi-bin/rup cgi-bin/pup htdocs/FAQ/FAQ.html ); # htdocs/FAQ/meta.faq # htdocs/FAQ/user.faq # htdocs/FAQ/admin.faq # htdocs/FAQ/misc.faq @cpfiles = qw( lang.html htdocs/index.html htdocs/FAQ htdocs/FAQ.html lib/fup.pl ); @FEX = getpwnam('fex') or die "$0: no user fex\n"; $> = $FEX[2]; $) = $FEX[3]; umask 022; $FEXHOME = $ENV{FEXHOME} || $FEX[7]; # require "$FEXHOME/lib/fex.pp" # or die "$0: cannot load $FEXHOME/lib/fex.pp - $!\n"; $tr = "locale/translations"; $lang = shift or &usage; exit if $lang eq 'english'; open $tr,$tr or die "$0: cannot open $tr - $!\n"; while (<$tr>) { $n++; last if /^\s*$/; if (/^#\s*([\w-]+):/ and $lang eq $1) { $ll = $n; } } &usage unless $ll; while (<$tr>) { next if /^#/; next if /^\s*$/; chomp; unless (/[a-z]/i) { die "$0: syntax error in $tr line $. : no text\n"; } $e = $_; for my $l (2 .. $ll) { $_ = <$tr>||''; chomp; unless (/[a-z]/i) { die "$0: syntax error in $tr line $. : no text\n"; } } $T{$e} = $_; while (<$tr>) { last if /^\s*$/ } } close $tr; @E = sort {length $b <=> length $a} keys %T; mkdir "$FEXHOME/locale"; $_ = "$FEXHOME/locale/english"; symlink '..',$_ unless -e; foreach $file (@trfiles) { local $/; mkdirp("$FEXHOME/locale/$lang/".dirname($file)); $fe = "$FEXHOME/$file"; $ft = "$FEXHOME/locale/$lang/$file"; open $fe,"<$fe" or die "$0: cannot read $fe - $!\n"; unlink $ft; # beware symlink! open $ft,">$ft" or die "$0: cannot write $ft - $!\n"; $_ = <$fe>; close $fe; foreach $e (@E) { s/\Q$e/$T{$e}/g; } print {$ft} $_; close $ft; chmod((stat $fe)[2],$ft); print "$ft written\n"; } if ($FEXHOME !~ /fexdev/) { foreach $file (@cpfiles) { my $fs = "locale/$lang/$file"; if (-e $fs) { my $fd = "$FEXHOME/$fs"; mkdirp(dirname($fd)); if (-f $fs) { $fd .= '_new' if -e $fd; if (copy($fs,$fd)) { chmod((stat $fs)[2],$fd); print "$fd written\n"; } } else { if (-f $fd) { my $fds = $fd.'_save'; my $fdn = $fd.'_new'; system "rm -rf $fds $fdn"; rename $fd,$fds; system "tar cf - $fs | (cd $FEXHOME; tar xf -)"; rename $fd,$fdn; rename $fds,$fd; print "$fdn written\n"; } else { system "tar cf - $fs | (cd $FEXHOME; tar xf -)"; print "$fd written\n"; } } } } foreach $fs (qw(fex.ph dop)) { $fd = "$FEXHOME/locale/$lang/lib/$fs"; symlink "../../../lib/$fs",$fd and print "$fd linked\n"; } unless (-f "$FEXHOME/locale/$lang/htdocs/FAQ/meta.faq") { unlink "$FEXHOME/locale/$lang/htdocs/FAQ/FAQ.html"; rmdir "$FEXHOME/locale/$lang/htdocs/FAQ"; } } make_lf($lang); make_lf('english'); # unless -f "$FEXHOME/lib/lf.pl"; exit; sub make_lf { my $lang = shift; my $fexpp = "$FEXHOME/locale/$lang/lib/fex.pp"; my $lf = "$FEXHOME/locale/$lang/lib/lf.pl"; open $fexpp,$fexpp or die "$0: no $fexpp - $!\n"; unlink $lf; open $lf,'>',$lf or die "$0: cannot write $lf - $!\n"; print {$lf} "### auto-generated by install/translate - DO NOT EDIT! ###\n\n"; local $/; $_ = <$fexpp>; s/.*\n(\#\#\#* locale functions)/$1/s; s/\nsub (\w+)/\n\$$1\{$lang\} = sub/gs; s/\n\}\n/\n\};\n/gs; print {$lf} $_; close $lf; close $fexpp; } # emulate mkdir -p sub mkdirp { my $dir = shift; my $pdir; return if -d $dir; $dir =~ s:/+$::; die "$0: cannot mkdir /\n" unless $dir; $pdir = $dir; if ($pdir =~ s:/[^/]+$::) { mkdirp($pdir) unless -d $pdir; } unless (-d $dir) { mkdir $dir,0770 or die "$0: mkdir $dir - $!\n"; } } sub usage { my @langs; open $tr,$tr or die "$0: cannot open $tr - $!\n"; while (<$tr>) { last if /^\s*$/; push @langs,$1 if /^#\s*([\w-]+):/; } foreach my $lang (@langs) { if (not -l "locale/$lang" and -f "locale/$lang/lib/fup.pl") { print "usage: $0 $lang\n"; } } exit 1; } fex-20160919/locale/debian_translate0000755000174700017470000000503712062743423015407 0ustar fexfex#!/usr/bin/perl -w # translate english F*EX files into locale languange, debian special use File::Basename; use File::Copy; @trfiles = qw( lib/fex.pp cgi-bin/foc cgi-bin/fop cgi-bin/fuc cgi-bin/fup cgi-bin/fur cgi-bin/rup cgi-bin/pup ); @cpfiles = qw( htdocs/index.html htdocs/FAQ.html lib/fup.pl lang.html ); $source = shift; $FEXHOME = shift; $dest = shift; $tr = "$source/locale/translations"; mkdirp($dest); unless (-l "$dest/english") { symlink '..',"$dest/english" or die "$0: cannot symlink $dest/english - $!\n"; } foreach $lang (glob "$source/locale/*/lib/fup.pl") { $lang =~ s:.*/locale/::; $lang =~ s:/.*::; next if $lang eq 'english'; next if $lang =~ /_$/; print "\n$lang:\n"; open $tr,$tr or die "$0: cannot open $tr - $!\n"; %T = (); $n = $ll = 0; while (<$tr>) { $n++; last if /^\s*$/; if (/^#\s*([\w-]+):/ and $lang eq $1) { $ll = $n; } } next unless $ll; while (<$tr>) { next if /^#/; next if /^\s*$/; chomp; unless (/[a-z]/i) { die "$0: syntax error in $tr line $. : no text\n"; } $e = $_; for my $l (2 .. $ll) { $_ = <$tr>||''; chomp; unless (/[a-z]/i) { die "$0: syntax error in $tr line $. : no text\n"; } } $T{$e} = $_; while (<$tr>) { last if /^\s*$/ } } close $tr; @E = sort {length $b <=> length $a} keys %T; foreach $file (@trfiles) { local $/; mkdirp("$dest/$lang/".dirname($file)); $fe = "$source/$file"; $ft = "$dest/$lang/$file"; open $fe,"<$fe" or die "$0: cannot read $fe - $!\n"; open $ft,">$ft" or die "$0: cannot write $ft - $!\n"; $_ = <$fe>; close $fe; foreach $e (@E) { s/\Q$e/$T{$e}/g; } print {$ft} $_; close $ft; chmod((stat $fe)[2],$ft); print "$ft written\n"; } foreach $file (@cpfiles) { $fs = "$source/locale/$lang/$file"; $fd = "$dest/$lang/$file"; mkdirp(dirname($fd)); $fd .= '_new' if -f $fd; if (copy($fs,$fd)) { chmod((stat $fs)[2],$fd); print "$fd written\n"; } } foreach $fs (qw(dop fex.ph)) { $fd = "$dest/$lang/lib/$fs"; symlink "$FEXHOME/lib/$fs",$fd or die "$0: cannot symlink $fd - $!\n"; print "$fd linked\n"; } } # emulate mkdir -p sub mkdirp { my $dir = shift; my $pdir; return if -d $dir; $dir =~ s:/+$::; die "$0: cannot mkdir /\n" unless $dir; $pdir = $dir; if ($pdir =~ s:/[^/]+$::) { mkdirp($pdir) unless -d $pdir; } unless (-d $dir) { mkdir $dir,0755 or die "$0: mkdir $dir - $!\n"; } } fex-20160919/locale/translations0000644000174700017470000032451712700745703014637 0ustar fexfex# english: Ulli Horlacher # german: Waldemar Bronsch # swabian: Hans-Georg Bickel # spanish: Francisco Ruiz # galician: Anton Meixome # italian: Vanni Piagno , # czech: Michal Simunek # french: Jean-Baptiste Denis 'english' 'german' 'swabian' 'spanish' 'galician' 'italian' 'czech' 'french' F*EX operation control ERROR F*EX Bedienungssteuerungs-Fehler F*EX Fehler bei dr Bedienongsschdeuerong Error del control de operaciones de F*EX Erro do control de operacións do F*EX Errore di controllo delle operazioni di F*EX Chyba při řízení provozu F*EX Erreur de gestion F*EX back to F*EX operation control Zurück zur F*EX-Bedienungssteuerung Zrigg zur Bedienongsschdeuerong Volver al control de operaciones de F*EX Volver ao control de operacións do F*EX Torna al controllo delle operazioni di F*EX Zpět na řízení provozu F*EX Retour à la gestion de F*EX wrong user or auth-ID Falscher Benutzer oder falsche auth-ID Benutzr odr auth-ID isch falsch usuario o auth-ID erróneo o usuario ou o auth-ID son incorrectos utente o auth-ID sbagliato chybný uživatel nebo ověřovací ID utilisateur ou auth-ID invalide operation control Bedienungssteuerung Bedienongsschdeuerong control de operaciones control de operacións controllo delle operazioni Řízení provozu gestion for user Für Benutzer Fir dr Benutzr para el usuario para o usuario per l'utente pro uživatele pour l'utilisateur You as the sender have a server disk quota of $quota MB and currently using Sie als Absender haben auf dem Server insgesamt $quota MB Speicherplatz und Sie benutzen momentan Du als Absender hosch uffm Server alles en allem $quota MB Platz zom Schbeichra ond Du benutzsch dovo grad Usted como emisario tiene una cuota de disco en el servidor de $quota MB y actualmente en uso Vostede como remitente ten unha cota de disco do servidor que está utilizando actualmente de $quota MB Tu in qualita' di mittente hai una quota disco nel server di $quota MB ed attualmente stai usando Jako odesilatel máte na serveru k dispozici $quota MB. Nyní využíváte Vous disposez de $quota MB d'espace disque en tant qu'expéditeur et vous utilisez actuellement sender quota (used) Absender Speicherplatz (benutzt) Absender Platz zom Schbeichra (benutzt) cuota de envío (usada) cota de remitente (usada) quota mittente (in uso) limit pro odesilatele (využito) quota expéditeur (utilisé) recipient quota (used): Empfänger Speicherplatz (benutzt): Empfänger Platz zom Schbeichra (benutzt): quota de recepción (usada): cota de destinatario (usada): quota destinatario (in uso): limit pro příjemce (využito): quota destinataire (utilisé): Retrieve a list of all your received files in F*EX spool Zeige die Liste aller empfangenen Dateien Zeig mol a Lischde von älle empfangene Dateia Ver la lista de todos los ficheros recibidos en la cola de F*EX Ver a lista de todos os ficheiros recibidos na cola de F*EX Richiama una lista di tutti i tuoi file ricevuti nello spool di F*EX Načíst seznam všech souborů čekajících ve frontě Récupérer une liste de tous les fichiers que vous avez reçus Show download URLs of files you have sent Liste Download URLs von gesendeten Dateien auf Zoig Ronderlad URLs von verschickte Dateia Mostrar direcciones URL de los archivos enviados Amosar os URL dos ficheiros enviados Mostra scarica gli URL dei file inviati Zobrazit URL pro stažení souborů, které jste odeslali Lister les URLs des fichiers que vous avez envoyés Forward a copy of a file you already have uploaded to another recipient Eine Kopie der Datei weiterleiten, welche Sie bereits für einen anderen Empfänger hochgeladen haben A Kobie von der Datei weiderloide, die Du scho fier en andra Empfänger nuffglade hosch Reenviar una copia de un fichero que ha subido a otro destinatario Reenviar unha copia dun ficheiro que cargou a outro destinatario Inoltra una copia di un file che hai gia' caricato per un altro destinatario Přidat příjemce k již nahranému souboru Reexpédier une copie d'un fichier que vous avez déja uploadé à un autre destinataire Redirect files you have uploaded to a wrong or misspelled recipient Leite Dateien weiter, die an eine falsche oder ungültige E-Mail Adresse gegangen sind Dateia weiderloide, die an a falsche oder ogildige E-Mail-Adress gange send Redirigir ficheros que ha subido y enviado a un destinatario equivocado o mal escrito Redirixir ficheiros que cargou e enviou a un destinatario equivocado ou mal escrito Inoltra file che hai caricato ad un destinatario sbagliato o di cui hai sbagliato l'indirizzo Přesměrovat nahrané soubory pro nesprávného či chybně uvedeného příjemce Rediriger un fichier que vous avez déja uploadé vers un mauvais destinataire Resend notification e-mails for files you have sent Benachrichtigungs E-Mails nochmals versenden Sag dem Empfängr no amole Bscheid Reenviar emails de recuerdo Resend notification e-mails for files you have sent Rispedisci e-mail di notifica per file che hai spedito Znovu odeslat zprávy s upozorněním pro soubory, které ste odeslali Renvoyer les messages de notifications pour les fichiers que vous avez envoyés Create a subuser who can send you files. Enter his e-mail address: Subuser anlegen, der Ihnen Dateien schicken kann. Geben Sie seine E-Mail Adresse ein: Subuser olega, der dir Dateia schicka ko. Gib sei E-Mail Adress ei: Crear un subuser que pueda enviar archivos. Escriba su dirección de correo electrónico: Crear un subusuario que poida enviarlle ficheiros. Escriba o seu enderezo de correo: Crea un sottoutente che possa spedirti dei file. Inserisci il suo indirizzo e-mail: Vytvořit poduživatele, který vám může zasílat soubory. Zadejte jeho e-mailovou adresu: Créer un utilisateur qui peut vous envoyer des fichiers. Saisir son adresse électronique: for only one upload nur für einen Upload bloss fir oimal Nufflada por sólo una carga Soamente para un envío per un solo upload pouze pro jedno nahrání pour un upload unique Comment to send with information e-mail: Kommentar, der mit der Informations E-Mail mitgeschickt wird: Kommentar, der mit dr Enformations E-Mail mitgschickt wird: Comentario para enviar la información por e-mail: Comentario que se enviará xunto coa información do correo: Commenta per spedire con un'e-mail di notifica: V informačním e-mailu odeslat komentář: Commentaire à envoyer avec le message d'information: create subuser and send e-mail Subuser anlegen und E-Mail verschicken Subuser olegea ond E-Mail verschicka crear subuser y enviar e-mail Crear un subusuario en enviar un correo crea un sottoutente se spedisci l'e-mail vytvořit poduživatele a odeslat e-mail créer un utilisateur et envoyer un message électronique You can register yourself Sie können sich selbst registrieren Du kosch De selber regischdriera Puede autoregistrarse Podo autorexistrarse Puoi registrarti Můžete se zaregistrovat Vous pouvez vous enregistrer if you do not have a F*EX account yet wenn Sie noch keinen F*EX Account haben wenn De no koi F*EX Konto hosch si no tiene todavía una cuenta en F*EX se non ten aínda unha conta no F*EX se non hai ancora il tuo account F*EX pokud ještě nemáte svůj F*EX účet si vous n'avez pas déjà un compte F*EX You may also use anonymous upload Sie können auch anonymen Upload verwenden Du kosch au anonymes Nufflada nemma Se tambien puede usar anonymous upload Tamén pode usar o envío anónimo Potresti anhe utilizzare anonymous upload Můžete také využít anonymnínahrávání Vous pouvez aussi utiliser l'upload anonyme You may also use simple upload Sie können auch vereinfachten Upload verwenden Du kosch au oifachs Nufflada nemma Puede tambien usar subir simplificado You may also use simple upload Potresti anche usare caricamento semplice Můžete také použít jednoduché nahrávání. Vous pouvez également utiliser l'upload simple $file already exists for $file existiert bereits für $file gibts scho fir $file ya existe para xa existe $file para $file esiste giàper $file již existuje pro Le fichier $file existe déjàpour $file already exists - purge it?! $file existiert bereits - entfernen?! $file gibts scho - wegschmeissa?! $file ya existe - ¡¿Purgarlo?! xa existe $file - purgalo?! $file esiste già - lo vuoi eliminare?! $file již existuje - odstranit jej?! Le fichier $file existe déjà - Effacer?! Manage your subusers and groups Subusers und Gruppen verwalten Onderbenutzr ond Grubba verwalde Gestione sus subusuarios y grupos Xestione os seus subusuarios e grupos Gestisci i tuoi sotto-utenti e gruppi Spravovat své poduživatele a skupiny Gérer vos sous-utilisateurs et vos groupes Change the disclaimer to be sent with notification e-mail Änderung des Disclaimers der in der Benachrichtigungs E-Mail mitversendet wird Änder dr Disclaimer von dr Benochrichtigongs E-Mail Cambiar renuncia de email enviado con emails de notificación Change the disclaimer to be sent with notification e-mail Cambia il disclaimer affinchè venga spedito assieme all'e-mail di notifica Změnit odesílání zřeknutí se odpovědnosti u správy s upozorněním Changer la clause de non-responsabilité à envoyer avec le message de notification Change your auth-ID to Ändern Sie Ihre auth-ID in Ändr die auth-ID noch Cambie su auth-ID en Cambie o seu auth-ID en Cambia il tuo auth-ID in Změnit si ověřovací ID auth-ID na Changer votre auth-ID pour remember it merken aber ned vergessa, gell recordar recórdeo ricordati zapamatovat souvenez-vous en Edit your address book Ihr Adressbuch editieren Dei Adressbüchle bearbeide Edite su libro de direcciones Edite a súa axenda de enderezos Edita la tua rubrica Upravit adresář Éditez votre carnet d'adresses Get detailed notification e-mails (current setting: brief) Ausfürliche Benachrichtigungs E-Mails bekommen (aktuelle Einstellung: kurz) Langs Gschwätz en de Benochrichtigongs E-Mails (aktuelle Eischtellong: kurz) Recibir detallado e-mails de notificación (configuración actual: corto) Obter unha detallada notificación para os correos (axuste actual: breve) Avere dettagliata di notifica e-mail (impostazione attuale: breve) Dostávat podrobné e-maily s oznámením (současné nastavení: zkrácené) Recevoir des emails de notifications détaillés (configuration courante: simple) Get brief notification e-mails (current setting: detailed) Kurze Benachrichtigungs E-Mails bekommen (aktuelle Einstellung: detailliert) Machs kurz en de Benochrichtigongs E-Mails (aktuelle Eischtellong: langs Gschwätz) Recibir corto e-mails de notificación (configuración actual: detallado) Obter unha breve notificación para os correos (axuste actual: detallado) Avere breve notifica e-mail (impostazione attuale: dettagliata) Dostávat e-maily s upozorněním v zkráceném formátu (současné nastavení: detailed) Recevoir des emails de notifications simple (configuration courante: détaillé) Get reminder notification e-mails (current setting: no reminders) Erinnerung E-Mails erhalten (aktuelle Einstellung: keine) Drodenka E-Mails erhalta (aktuelle Eischtellong: koine) Recibir emails de recuerdo (configuración actual: ningunos) Get reminder notification e-mails (current setting: no reminders) Impostaun Promemoria per l'e-mail di notifica (Impostazione attuale: nessun promemoria) Odesílat zprávy s připomenutím (současné nastavení: žádná upozornění) Recevoir les rappels par e-mail (configuration actuelle: pas de rappels) Get no reminder notification e-mails (current setting: send reminders) Keine Erinnerung E-Mails erhalten (aktuelle Einstellung: Erinnerung E-Mails werden verschickt) Koine Drodenka E-Mails erhalta (aktuelle Eischtellong: Drodenka E-Mails werdad verschickt) No recibir emails de recuerdo (configuración actual: Se eniva emails de recuerdo) Get no reminder notification e-mails (current setting: send reminders) Imposta nessun promemoria per l'e-mail di notifica (Impostazione attuale: spedisci promemoria) Neodesílat žádná připomenutí (současné nastavení: odeslat upozornění) Ne pas recevoir les rappels par e-mail (configuration actuelle: rappels envoyés) Save files after download (current setting: display Speichere Dateien nach dem download (aktuelle Einstellung: anzeigen Schpeicher die Dateia nochm Ronderlada (aktuelle Eischtellong: ozeiga Save downloads (current setting: display Save downloads (current setting: display Save downloads (current setting: display Save downloads (current setting: display Save downloads (current setting: display Display files when downloading with web browser (current setting: save Anzeige von Dateien direkt beim download (aktuelle Einstellung: abspeichern Ozeiga von Dateia beim Ronderlada (aktuelle Eischtellong: abschpeichra Display downloads (current setting: save Display downloads (current setting: save Display downloads (current setting: save Display downloads (current setting: save Display downloads (current setting: save You will now get no reminder notification e-mails Sie werden nun keine Erinnerung E-Mails erhalten Du wirsch jetzt koine Drodenka E-Mails meh bekomma Desde ahora ya no se recibe emails de recuerdo You will now get no reminder notification e-mails Non otterrai ora alcun promemoria di notifica e-mail Nyní vám nebudou odesílány žádné zprávy s připomenutím Vous n'allez plus recevoir d'emails de notifications You will now get reminder notification e-mails Sie werden nun Erinnerung E-Mails erhalten Du wirsch jetzt Drodenka E-Mails bekomma Desde ahora se recibe emails de recuerdo You will now get reminder notification e-mails Otterrai ora promemoria di notifica e-mail Nyní vám budou odesílány zprávy s připomenutím Vous allez maintenant recevoir des rappels par e-mail Notification e-mails now come in detailed format Benachrichtigungs E-Mails kommen ab jetzt in detailliertem Format Benochrichtigongs E-Mails kommet ab jetzt mit langem Gschwätz E-mails de notificación desde ahora datallados Os correos de notificación virán a partir de agora en formato detallado Notifica e-mail ora sono disponibili in formato dettagliato E-maily s upozorněním jsou nyní odesílány v podrobném formátu Les emails de notifications sont maintenant au format détaillé Notification e-mails now come in short format Benachrichtigungs E-Mails kommen ab jetzt in kurzem Format Benochrichtigongs E-Mails kommet ab jetzt em kurzem Format E-mails de notificación desde ahora cortos Os correo de notificación virán a partir de agora en formato curto Notifica e-mail ora sono disponibili in formato breve E-maily s upozorněním jsou nyní odesílány ve zkráceném formátu Les emails de notifications sont maintenant au format simple Downloads will now be saved Downloads werden nun gespeichert Ronderlads werdet ab jetzt gschpeichert Descargas están guardadas Downloads will now be saved I downloads saranno ora salvati Stahované soubory se nyní uloží Les téléchargements vont maintenant être sauvés Downloads will now be displayed (if possible) Downloads werden nun angezeigt (wenn möglich) Ronderlads werdet ab jetzt ozeigt (wenns ghot) Descargas están indicadas ahora (si posible) Downloads will now be displayed (if possible) I downloads saranno mostrati (se possibile) Stahované soubory se nyní zobrazí (je-li to možné) Les téléchargements cont maintenant être affichés (si possible) E-mail disclaimer reset to default Der E-Mail Disclaimer wurde auf Standard zurückgesetzt Dr E-Mail Ohängsl isch wieder orginal Renuncia de email reinicializado a defecto E-mail disclaimer reset to default E-mail disclaimer ripristinato su predefinito Zřeknutí se odpovědnosti ve zprávě bylo nastaveno na výchozí hodnotu Clause de non-responsabilité par défaut Disclaimer to be sent with download notification e-mail: In Benachrichtigungs E-Mail angehängter Disclaimer: Disclaimer en dr Benochrichtigongs E-Mail: Renuncia de email enviado con emails de notificación para descargar: Disclaimer to be sent with download notification e-mail: Disclaimer spedito con il download dell'e-mail di notifica: Zřeknutí se odpovědnosti odesílané společně se zprávou s připomenutím stažení: Claude de non-responsabilité à envoyer avec le message de notification: reset the disclaimer to default den Disclaimer zurücksetzen dr Disclaimer zricksetza Reinicializar renuncia de email a defecto reset the disclaimer to default ripristina il disclaimer su predefinito obnovit výchozí zřeknutí se odpovědnosti remise de la clause de non-responsabilité à sa valeur par défaut E-mail disclaimer changed to: Der E-Mail Disclaimer wurde geändert auf: Dr E-Mail Disclaimer isch jetzt: Renuncia de email cambiado á: E-mail disclaimer changed to: E-mail disclaimer modificato in: Zřeknutí se odpovědnosti ve zprávě bylo změněno na: Clause de non-responsabilité de l'email: Back to fup (upload page) Zurück zu fup (Upload Seite) Zrigg zu fup (Nufflad-Seite) Volver a fup (p´gina de carga) Volver a fup (p´xina de carga) Indietro a fup (pagina di caricamento) Zpět na fup (stránku pro nahrávání) Retour à fup (page d'upload) Download URLs of files you have sent Download URLs von gesendeten Dateien Ronderlad URLs von verschickte Dateia URLs de descarga de los archivos enviados Descargar os URL dos ficheiros enviados Scarica URL dei file che sono stati inviati URL pro stažení souborů, které jste odeslali URLs de téléchargement que vous avez envoyés

    to

    an

    an

    vez

    para

    per

    pro

    pour reminder F*EX-upload Erinnerung F*EX-upload Ned vergessa F*EX-upload recuerdo del F*EX-upload recordatorio do envío F*EX ricordo F*EX-upload Oznámení o nahraném souboru na F*EX Pense-bête F*EX-upload value="continue" value="weiter" value="weidr ghods" value="continuar" value="continuar" value="continua" value="pokračovat" value="continuer" #>User: #>Benutzer: #>Benutzr: #>Usuario: #>Usuario: #>Utente: #>Uživatel: #>Utilisateur: user config ERROR ERROR Benutzer-Einstellungen ERROR Benutzr-Eischdellunga ERROR en la confiuración del usuario Produciuse un ERRO na configuación do usuario ERRORE di configurazione utente CHYBA nastavení uživatele ERREUR de configuration utilisateur F*EX user config F*EX Benutzer-Einstellungen F*EX Benutzr-Eischdellunga configuración del usuario F*EX configuración do usuario F*EX Configurazione utente F*EX Nastavení F*EX uživatele Configuration utilisateur F*EX An information e-mail has been sent to your subuser Eine Benachrichtiguns-E-Mail wurde gesendet zu Ihrem Subuser Dein Onderbenutzr isch per E-Mail benochrichdigt worde Un correo electrónico informativo se ha enviado a su subusuario Un correo electrónico informativo enviouse ao seu subusuario Una e-mail di informazione e' stata spedita al tuo sotto-utente Vašemu poduživateli byl odeslán informační e-mail Un message d'information a été envoyé à votre sous-utilisateur A one time upload URL for $otuser has been created Eine einmal gültige upload URL für $otuser wurde angelegt A oimol giltig nufflad URL fir $otuser isch oglegt worda Un URL para subir una vez $otuser ha sido creado Un enderezo URL de nico uso para $otuser acaba de se crear E' stato creato un URL di caricamento utilizzabile una sola volta per l'utente $otuser Jednorázová URL pro nahrání pro $otuser byla vytvořena Une URL d'upload à usage unique pour $otuser a été créée and an information e-mail has been sent to this address und eine Informations-E-Mail wurde an diese Adresse verschickt ond a Was-macha-musch-E-Mail isch do no verschickt worda y un email de informacin ha sido enviado a esta direccin e un correo informativo acaba de se enviar a este enderezo e una e-mail di informazioni è stata spedita a questo indirizzo a informační e-mail byl odeslán na tuto adresu et un message d'information a été envoyé à cette adresse wrong user or auth-ID Falscher Benutzer oder falsche auth-ID Benutzr oddr auth-ID send falsch usuario o auth-ID erróneo o usuario ou o auth-ID son incorrectos utente o auth-ID sbagliato chybný uživatel nebo ověřovací ID utilisateur ou auth-ID invalide no group name specified kein Gruppen-Name angegeben Seggl, Du hosch koin Grubbenoma ogebe nombre de grupo sin especificar non se especificou o nome do grupo nome gruppo non specificato nebyl uveden žádný název skupiny pas de nom de groupe spécifié is already a registered F*EX full user ist bereits ein registrierter F*EX Voll-Benutzer isch scho längscht als Vollbenutzr bei F*EX regischdriert ya es un usuario normal registrado en F*EX xa é un usuario completo rexistrado en F*EX e' gia' un utente F*EX completo registrato je již zaregistrovaným plnohodnotným F*EX uživatelem est déja enregistré en tant qu'utilisateur F*EX Your subuser upload URL is: Ihr Subuser Upload-URL ist: Dei Onderbenutzr Nufflad-URL isch: La URL de subida de su subusuario es: O seu enderezo URL de carga como subusuario: L'URL per il caricamento del tuo sotto-utente e': URL pro nahrání pro vašeho poduživatele je: L'URL d'upload de votre sous-utilisateur est: Your subusers upload URLs are: Die Upload-URLs für Ihre Subusers sind: Dui Nufflad-URLs fier Deine Onderbenutzr send: Las URLs de sus subusuarios son: Os URL de carga dos seus subusuarios Gli URL per il caricamento dei tuoi sotto-utenti sono: URL pro nahrání pro vaše poduživatele jsou: Les URLs d'upload de vos sous-utilisateurs sont: An information e-mail has been sent to Eine Benachrichtigungs-E-Mail wurde gesendet an A Benochrichdigongs-E-Mail isch gschickt worde an Un correo electrónico informativo se ha enviado a Enviouse un correo electrónico informativo Una e-mail di informazione e' stata spedita a Informační e-mail byl odeslán na Un message d'information a été envoyé à Edit address book Adressbuch editieren Adressbüchle bearbeita Editar el libro de direcciones Editar a axenda de enderezos Edita la rubrica Upravit adresář Éditez le carnet d'adresse Entry:aliase-mail address# optional comment Eintrag:AliasE-Mail Adresse# optionaler Kommentar Eidrag:AliasE-Mail Adress# Kommendar (kosch macha oddr bleiba lassa) Entrada:aliasdirección de correo electrónico# comentario opcional Entrada:aliasenderezo de correo electrónico# comentario opcional Entrata:aliasindirizzo e-mail# commento opzionale Položka:aliase-mailová adresa volitelný komentář Entrée:aliasadresse e-mail# comment optionnel Example: Beispiel: Beischbiel: Ejemplo: Exemplo: Esempio: Příklad Exemple: value="submit" value="Absenden" value="Verschicke" valor="enviar" valor="enviar" value="sottometti" value="potvrdit" value="soumettre" You may use these alias names as F*EX recipient addresses on Sie können diese Alias-Namen als F*EX Empfänger-Adressen auf Du kosch selle Alias-Nome als F*EX Empfänger-Adresse uff Puede usar estos alias como direcciones de destinatarios en F*EX en Pode usar estes alias como enderezos de destinatarios do F*EX en Potresti usare questo alias come destinatario di F*EX Tyto aliasy můžete používat jako adresy F*EX příjemce na Vous pouvez utiliser ces alias comme destinataires F*EX sur 'fup' 'fup benutzen.' 'fup nemme.' 'fup' 'fup' 'fup' 'fup' 'fup' Alternatively you can fex a file ADDRESS_BOOK to yourself Alternativ können Sie die Datei ADDRESS_BOOK an sich selbst Du kosch au dui Datei ADDRESS_BOOK an De selber También puede enviar vía fex un fichero ADDRESS_BOOK a si mismo Tamén pode enviar vía fex un ficheiro ADDRESS_BOOK a si mesmo Alternativamente puoi inviare un file ADDRESS_BOOK a te stesso Nebo si můžete poslat soubor sami sobě Vous pouvez aussi vous envoyer un fichier ADDRESS_BOOK containing your alias definitions fexen, welche Ihre Alias-Definitionen enthält fexe, wo Deine Alias-Definitione dren send que contenga sus definiciones de alias que conteña as súas definicións de alias contiene le tue definizioni degli alias obsahuje definované aliasy contenant vos alias aliase-mail addressoptionscomment AliasE-Mail AdresseOptionenKommentar AliasE-Mail AdresseOptionenKommendar aliasdirección de correo electrónicoopcionescomentar aliasenderezo de correo electrónicoopciónscomentar aliasindirizzo e-mailopzionicommento aliase-mailová adresavolbykomentář aliasadresse e-mailoptionscommentaire back to fup (F*EX upload) zurück zu fup (F*EX Upload) zrigg zu fup (F*EX Nufflade) volver a fup (subida a F*EX) volver a fup (subida a F*EX) torna a fup (caricamento F*EX) zpět na fup (F*EX nahrání) retour à fup (F*EX upload) You have to give these URLs to your subusers for fexing files to you Sie müssen diese URLs Ihren Subusers geben, damit sie Dateien an Sie fexen können Du musch selle URLs Deine Onderbenutzr gebba, damit se Dateia an Di fexe kenne Tiene que dar estas URLs a sus subusuarios para que puedan enviarle ficheros vía F*EX Ten que dar estes URL aos seus subusuarios para que poidan enviarlle ficheiros vía F*EX Devi dare questi URL ai tuoi sotto-utenti per spedirti file Aby vám mohli poduživatelé odesílat soubory, sdělte jim tyto URL Vous devez donner ces URLs à vos utilisateurs pour qu'ils puissent vous envoyer des fichiers Or click on the subuser's e-mail address link to send him an Oder klicken Sie auf den E-Mail Adressen-Link des Subusers, um ihm eine Oddr klick halt uff de E-Mail Adresse-Link von Deim Onderbenutzr, no kosch ihm a O pinche en el enlace a la dirección de correo electrónico del subusuario para enviarle un Ou prema sobre a ligazón do enderezo de correo do subusuario para enviarlle un O clicca nel link dell'indirizzo e-mail del sotto-utente per spedirgli un Nebo klikněte na odkaz s e-mailovou adresou poduživatele k odeslání Ou cliquer sur l'adresse de messagerie de votre sous-utilisateurs pour lui envoyer un information e-mail by the F*EX server Benachrichtigungs-E-Mail mit Hilfe des F*EX-Servers zu senden Benochrichdigongs-E-Mail ieber de F*EX-Server schicke correo electrónico informativo del servidor de F*EX correo electrónico informativo vía servidor do F*EX informazione spedita dal server F*EX informačního e-mailu pomocí F*EX serveru message d'information du server F*EX Your F*EX account: Ihr F*EX Account: Dei F*EX Konto: Su cuenta en F*EX: A súa conta no F*EX: Il tuo utente F*EX: Váš F*EX účet: Votre compte F*EX: New auth-ID: Neue auth-ID: Neie auth-ID: Nuevo auth-ID: Novo auth-ID: Nuovo auth-ID: Nové ověřovací ID: Nouvel auth-ID: (Remember your auth-ID when you change it!) (Unbedingt die auth-ID merken wenn sie geändert wird!) (Merk Dir obedingd Dei auth-ID wenn Du se gändert hosch!) (Recuerde su auth-ID cuando lo cambie) (Lembre o seu auth-ID cando o cambie) (Ricordati il tuo auth-ID quando lo cambi!) (Zapamatujte si své ověřovací ID, pokud jej změníte!) (Vous devez vous souvenir de votre auth-ID lorsque vous le changez) Allow special senders (= subusers) to fex files to you: Ihren ausgewählten Partnern (= Subusers) erlauben, Daten an Sie zu senden: Deim erlesene Freindeskreis (= Onderbenutzr) erlaube, Data an Di zom schicka: Permitir a remitentes especiales (= subusuario) que le envín vía F*EX ficheros a usted: Permitirlles a remitentes especiais (= subusuarios) enviarlle a vostede ficheiros por F*EX: Permetti a utenti speciali (= sotto-utenti) di spedirti file: Povolit speciální odesilatele (= poduživatelé), kteří vám mohou zasílat soubory: Autoriser des expéditeurs particuliers (= sous-utilisateurs) à vous envoyer des fichiers: Allow Erlaube Erlaub Permitir Permitir Permetti Povolit Autoriser save and show upload URLs speichern und upload URLs anzeigen abschpeichra ond nufflad URLs ozeiga guardar y mostrar las direcciones URL de carga gardar e amosar URL enviado salva e mostra gli indirizzi di upload uložit a zobrazit URL pro nahrání sauvegarder et lister les URLs d'upload This list has entries in format:<e-mail address>:<encryption-ID> Diese Liste besteht aus Einträgen im Format:<E-Mail Adresse>:<encryption-ID> Sell Lischt beschdoht aus Eidragonge vom Format:<E-Mail Adress>:<encryption-ID> Esta lista tiene las entradas en formato:<e-mail address>:<encryption-ID> Esta lista ten entradas co formato :<enderezo de correo>:<ID-cifrado> Questa lista ha i contenuti nel formato: <e-mail address>:<encryption-ID> Položky seznamu jsou ve formátu:<e-mailová adresa>:<Å¡ifrovacíID> Les entrées de cette liste ont comme format:<adresse e-mail>:<encryption-ID> These special senders may fex files only to you! Diese besonderen Sender können Dateien nur an Sie fexen! Selle Absender send was Bsonders ond kenne Dateia bloß an dich fexe! ¡Estos remitentes especiales pueden enviar ficheros vía F*EX solo a usted! Estes remitentes especiais poden enviar ficheiros vía F*EX a vostede! Questi utenti speciali potrebbero spedire file solo a te! Tito speciální odesilatelé mohou odesílat soubory pouze vám! Ces expéditeurs particuliers peuvent seulement vous envoyer des fichiers It is not necessary to add regular fex users to your list, Es ist nicht notwendig, reguläre FEX Benutzer zu Ihrer Liste hinzuzufügen 'S isch net nedich, daß de reguläre F*EX Benutzr uff Dei Lischde setzsch No es necesario añadir usarios de F*EX normales a su lista, Non é necesario engadir usuarios de F*EX normais á súa lista, Non e' necessario aggiungere utenti regolari fex alla tua lista, Do tohoto seznamu není třeba přidávat běžné F*EX uživatele, Il n'est pas nécessaire d'ajouter des utilisateurs de F*EX à votre liste, because they already can fex weil diese bereits auch so fexen können weil dui kenned sowieso scho fexe porque ellos ya pueden enviar vía F*EX porque eles xa poden enviar vía F*EX perche' possono gia' spedire con F*EX protože ti vždy mohou odesílat soubory parce qu'ils peuvent déja utiliser fex The encryption-ID is necessary to generate a unique upload URL for this subuser Die encryption-ID wird für um eine eindeutige upload URL für diesen Subuser zu erzeugen Die encryption-ID isch notwendig um a eindeutig upload URL für den Subuser zom macha Hace falta una ID de codificación para generarle a este sub-usuario un inequívoco URL para subir Fai falta un ID de codificación para xerarlle a este subusuario un inequívoco URL para subir L'encryption-ID e' necessario per generare un unico URL di caricamento per questo sotto-utente Poduživatel musí mít k vytvoření unikátní URL pro nahrávání šifrovací ID L'encryption-ID est nécessaire pour générer une URL d'upload unique pour cet utilisateur If you omit the encryption-ID a random one will be used Wenn Sie die encryption-ID weglassen, wird eine zufällige gewählt Wenn Du die encryption-ID wegläscht, no wird a zufälliga gnomma Si se omite el cifrado-ID un nombre cualquiera se utilizará Se omite o ID-cifrado, utilizarase un aleatorio Se tu ometti l'ID crittato uno casuale verrà utilizzato Vynecháte-li šifrovací ID, použije se náhodně vygerenrované Si vous ne mentionnez pas l'encryption-ID, il sera généré aléatoirement A F*EX group is similar to a mailing list, but for files Eine F*EX Gruppe ist einem E-Mail-Verteiler ähnlich, allerdings eben für Dateien A F*EX Grupp isch so was wie en E-Mail-Verdoiler, halt fier Dateia Un grupo F*EX es similar a una lista de correo, pero para ficheros Un grupo F*EX seméllase a unha lista de correo, pero para ficheiros Un gruppo F*EX e' simile ad una lista di distribuzione, ma per i file F*EX skupina je podobná poštovní konferenci s tím rozdílem, že se odesílají soubory Un groupe F*EX est similaire à une adresse de diffusion (mailing-list), mais pour les fichiers Edit your F*EX groups: Editieren Sie Ihre F*EX Gruppen: Bearbeit Deine F*EX-Gruppa: Edite sus grupos F*EX: Edite os seus grupos F*EX: Edita i tuoi gruppi F*EX: Upravit F*EX skupiny: Éditez vos groupes F*EX: new group Neue Gruppe Neie Grupp Grupo nuevo Novo grupo nuovo gruppo nová skupina nouveau groupe Your F*EX account on Ihr F*EX Account auf Dei F*EX Konto auf Su cuenta F*EX A súa conta F*EX Il tuo utente F*EX Váš účet pro F*EX Votre compte F*EX sur Your upload URL Ihre upload URL Dei nufflad URL su URL de subir O seu enderezo URL de carga Il tuo URL di caricamento URL pro nahrání Votre URL d'upload to upload one file to $user um eine Datei an $user zu schicken om a Datei an $user zom schicka para subir un fichero a $user para cargarlle un ficheiro a $user per caricare un file per $user jednoho souboru uživateli $user pour uploader un fichier à $user to upload files to $user um Dateien an $user zu schicken om Dateia an $user zom schicka para subir ficheros a $user para subir ficheiros a $user per caricare file a $user pro nahrávání souborů uživateli $user pour uploader des fichiers à $user to upload files to F*EX group "$group" um Dateien fuer F*EX-Gruppe "$group" bereitzustellen wenn De Dateia fier dui F*EX-Grupp "$group" nufflade willsch para subir ficheros al grupo F*EX "$group" para subir ficheiros ao grupo de F*EX "$group" per caricare file al gruppo F*EX "$group" pro nahrávání souborů F*EX skupině "$group" pour uploader des fichiers au groupe F*EX "$group" See http://$ENV{HTTP_HOST}/index.html for more information about Siehe http://$ENV{HTTP_HOST}/index.html fuer mehr Informationen ueber Guck halt uff http://$ENV{HTTP_HOST}/index.html wenn De meh wisse willsch ieber Vea http://$ENV{HTTP_HOST}/index.html para obtener más información sobre Véxase http://$ENV{HTTP_HOST}/index.html para obter más información sobre Vedi http://$ENV{HTTP_HOST}/index.html per ulteriori informazioni Více informací o svém účtu získáte na http://$ENV{HTTP_HOST}/index.html Voir http://$ENV{HTTP_HOST}/index.html pour plus d'informations sur See $proto: Siehe $proto: Guck uff $proto: Vea $proto: Véxase $proto: Vedi $proto: Více $proto: Voir $proto: Questions? ==> F*EX admin: $admin Fragen? ==> Kontaktieren Sie den F*EX Administrator: $admin Froga? ==> Belaeschtig ruhig dr F*EX Adminischdrator: $admin Preguntas? ==> Administrador de F*EX: $admin Preguntas? ==> Administrador do F*EX: $admin Domande? ==> Amministratore F*EX: $admin Máte otázky? ==> Kontaktujte F*EX správce: $admin Questions? ==> Administrateur F*EX: $admin Your F*EX account on Ihr F*EX Account auf Dei F*EX Konto auf Su cuenta F*EX en A sú conta F*EX en Il tuo account F*EX su Váš F*EX účet na Votre compte F*EX sur A F*EX (File EXchange) account has been created for you on Ein F*EX (File EXchange) Account ist fuer Sie angelegt worden auf Du hosch jetzt a F*EX (File EXchange) Konto auf Una cuenta F*EX (File EXchange) se ha creado para usted en Creóuselle a vostede unha conta F*EX (File EXchange) Un account F*EX (File EXchange) e' stato creato per te su Byl vám vytvořen F*EX (File EXchange) účet na Un compte F*EX a été créé pour vous sur 'Use 'Bitte benutzen Sie 'Nemm 'Usa 'Use 'Usa 'Používání 'Utilisez See http://$ENV{HTTP_HOST}/index.html for more information about Siehe http://$ENV{HTTP_HOST}/index.html fuer mehr Informationen ueber Guck halt uff http://$ENV{HTTP_HOST}/index.html wenn De meh wisse willsch ieber Vea http://$ENV{HTTP_HOST}/index.html para obtener más información sobre Véxase http://$ENV{HTTP_HOST}/index.html para obter más información sobre Vedi http://$ENV{HTTP_HOST}/index.html per ulteriori informazioni Informace, jak používat F*EX, naleznete na http://$ENV{HTTP_HOST}/index.html Voir http://$ENV{HTTP_HOST}/index.html pour plus d'informations sur $notify not found in $gf $notify nicht gefunden in $gf $notify net gfonda in $gf $notify no se encontró en $gf $notify non se atopou en $gf $notify non trovato in $gf $notify nebyl v $gf nalezen $notify non trouvé dans $gf Notification e-mail to $notify has been sent Benachrichtigungs-E-Mail an $notify wurde gesendet Benochrichdigongs-E-Mail an $notify isch verschickt worda Correo electrónico de notificación enviado a $notify Enviouse un correo de notificación a $notify E-mail di notifica e' stata spedita a $notify E-mail s oznámením pro $notify byl odeslán Un message d'information a été envoyé à $notify bad addresses:

    \n
      Fehlerhafte Adressen:

    \n
      Was send au des fier Adresse? Die send grottefalsch::

    \n
      dirección errónea:

    \n
      Os enderezos son incorrectos:

    \n
      indirizzo errato:

    \n
      chybné adresy:

    \n
      mauvaises adresses:

    \n
      you are already in group \@$group owned by $user Sie sind bereits in der Gruppe \@$group welche dem Benutzer $user gehört Du bisch doch scho längscht in derra Grupp \@$group von dem Benutzr $user ya pertenece al grupo \@$group propiedad de $user xa pertence ao grupo \@$group propiedade de $user sei gia' nel gruppo \@$group di proprieta' di $user ve skupině \@$group vlastněné uživatelem $user se již nacházíte vous êtes déja dans le groupe \@$group de l'utilisateur $user Go back Zurück No mol von vorne Volver Volver Torna indietro Vrátit se Retour and enter another group name und geben Sie einen anderen Namen für die Gruppe ein ond geb en andra Noma fier dui Grupp ei y introduzca un nuevo grupo e introduza un novo grupo e inserisci un'altro nome del gruppo a zadat jiný název skupiny et saisissez un autre nom de groupe Group \@$group has members: Die Gruppe \@$group hat folgende Mitglieder: Zur Grupp \@$group ghered: Los miembros del grupo \@$group son: Os membros do grupo \@$group son: Il gruppo \@$group ha i componenti: Členové skupiny \@$group: Le groupe \@$group a comme membres: (click address to send a notification e-mail to this user) (Klicken Sie auf die Adresse um eine Benachrichtigungs-E-Mail an diesen Benutzer zu senden) (Schieb Dei Maus uff d' Adress ond klick. Dann wird a Benochrichdigongs-E-Mail an den Benutzr gschickt) (pinche en la dirección para enviar correo electrónico de notificación a este usuario) (prema sobre o enderezo de correo electrónico de notificación a este usuario) (clicca l'indirizzo per spedire una e-mail di notifica a questo utente) (pro odeslání oznamovacího e-mailu uživateli, klikněte na jeho adresu) (cliquer sur l'adresse pour prevenir l'utilisateur avec un message) Edit F*EX group F*EX-Gruppe editieren F*EX-Grupp bearbeide Editar el grupo F*EX Editar o grupo F*EX Edita il gruppo F*EX Upravit F*EX skupinu Éditez le groupe F*EX When a member fexes a file to this list, Wenn ein Mitglied eine Datei für die Gruppe bereitstellt, Wenn oi Mitglied a Datei fier die reschdlich Grupp nuffläd Cuando un miembro envía vía F*EX un fichero a esta lista, Cando un membro envía vía F*EX un ficheiro a esta lista, Quando un componente spedisce un file a questa lista, Odešle-li člen soubor do konference, Lorsque un membre envoie un fichier à cette liste then all other members will receive it dann werden alle anderen Mitglieder diese Datei erhalten no krieget älle andere wo in derre Grupp send, selle Datei entonces todos los demás miembros lo recibirán entón todos os demáis membros o recibirán allora tutti gli altri componenti la riceveranno obdrží jej všichni členové tous les autres membres vont le recevoir New group name: (You MUST fill out this field!) Neuer Name für die Gruppe: (Sie MÜSSEN dieses Feld ausfüllen!) Neier Nome fier d' Grupp: (Des Feld MUSCH Du ausfille!) Nuevo nombre de grupo: (¡DEBE rellenar este campo!) Novo nome de grupo: (DEBE cubrir este campo!) Nuovo nome del gruppo: (DEVI compilare questo campo!) Název nové skupiny: (Toto políčko MUSÍTE vyplnit!) Nouveau nom du groupe: (Ce champ ne peut pas être vide) This list has entries in format:<e-mail address> Diese Liste besteht aus Einträge in folgendem Format haben:<E-Mail Adresse> Die Lischde bschdohd aus Eiträg em Format:<E-Mail Adresse> Esta lista debe tener las entradas en el formato: <dirección de correo electrónico> Esta lista debe ter as entradas no formato: enderezo de correo electrónico> Questa lista deve avere le righe in questo formato:<indirizzo e-mail> Položky seznamu musí být ve formátu:<e-mailová adresa> Cette liste doit avoir des entrées de la forme:<Adresse e-mail> You can name any existing e-mail address Sie können hier eine beliebige gültige E-Mail Adresse angeben Du kosch do a giltige E-Mail-Adress nach Deim Guschto eigebba Puede nombrar cualquier dirección de correo electrónico Pode nomear calquera enderezo de correo electrónico Puoi nominare qualsiasi indirizzo e-mail esistente Jakoukoli existující e-mailovou adresu můžete pojmenovat Vous pouvez désigner n'importe quelle adresse e-mail existante delete file after download Datei nach dem Download löschen Datei nochm Ronderlada löscha borrar el fichero tras su descarga borrar o ficheiro trala súa descarga cancella il file dopo il download smazat soubor po stažení effacer le fichier après le téléchargement do not delete file after download Datei nach dem Download nicht löschen Datei nochm Ronderlada net löscha no borrar el fichero tras su descarga non eliminar o ficheiro despois da descarga non cancellare il file dopo il download nemazat soubor po stažení ne pas supprimer le fichier après le téléchargement delete file after download with delay Datei nach dem Download mit Verzögerung löschen Datei nochm Ronderlada erscht schpäter löscha borrar el fichero tras su descarga con retardo borrar o ficheiro tras a súa descarga con atraso cancella il file dopo il download con ritardo smazat soubor po stažení až po effacer le fichier après un délai à la suite du téléchargement delete file $autodelete days after download Lösche Datei $autodelete Tage nach dem Download Lösch Datei $autodelete Dag nochm Ronderlada borrar archivo $autodelete dias despues del descargar delete file $autodelete days after download cancella file $autodelete giorni dopo il download smazat soubor po $autodelete dnech po stažení effacer $autodelete jours après le téléchargement F*EX service F*EX-Service F*EX-Dienscht Servicio F*EX Servizo F*EX servizio F*EX Služba F*EX Service F*EX Your reqested F*EX auth-ID for $fup?from=$from is: Ihre angefragte F*EX auth-ID fuer $fup?from=$from ist: Dei nochgfrogte F*EX auth-ID fir $fup?from=$from isch: Su auth-ID de F*EX solicitada para $fup?from=$from es: O seu auth-ID de F*EX solicitado para $fup?from=$from é: Il tuo auth-ID di F*EX che hai richiesto per $fup?from=$from e': Vaše požadované F*EX ověřovací ID pro $fup?from=$from je: Votre auth-ID F*EX pour $fup?from=$from est: Or use: Oder Sie verwenden: Odr du nemsch: O use: Or use: Oppure usa Nebo použijte: Ou utilisez: Your reqested F*EX login is: Ihr angefragter F*EX login ist: Dei agfragte F*EX login isch: Su solicitada login de F*EX es: A seu login solicitado de de F*EX é: Il tuo login F*EX richiesto e': Požadované přihlašovací údaje pro F*EX: Votre login F*EX est: Mail has been sent to you Mail wurde gesendet an Sie Mail isch an Dich gschickt worde El mensaje de correo se le ha enviado A mensaxe de correo xa se lle enviou Ti e' stata spedita una e-mail Zpráva vám byla odeslána Le message vous a été envoyé You are not in this group Sie sind nicht in dieser Gruppe Du ghersch net zu derra Grupp Nos es miembro de este grupo Non é membro deste grupo Non sei in questo gruppo Nejste členem této skupiny Vous n'êtes pas dans ce groupe Recipient group has no members Empfänger-Gruppe hat keine Mitglieder Dui Grupp wo des no soll hot koine Miglieder El grupo destinatario no tiene miembros O grupo de destinatarios non ten membros I gruppi di distribuzione non hanno membri Skupina příjemců nemá žádné členy Le groupe destinataire n'a pas de membre No such group Diese Gruppe existiert nicht Selle Grupp gibt's net. Huatsempel No existe tal grupo Non existe tal grupo Non esiste questo gruppo Tato skupina neexistuje Groupe non trouvé unknown dkey Unbekannter dkey Den dkey kenn i net dkey desconocido dkey descoñecido dkey sconosciuto neznámý dkey dkey inconnue has been deleted by %s at %s wurde gelöscht von %s um %s isch glöscht worde von %s um %s ha sido borrado por %s a las %s eliminado por %s és %s e' stato cancellato da %s a %s byl smazán uživatelem %s dne %s a été effacé par %s le %s $filename deleted $filename gelöscht $filename glöscht $filename borrado $filename eliminado $filename cancellato $filename byl smazán $filename effacé $filename not deleted ($s) $filename nicht gelöscht ($s) $filename net glöscht $filename no borrado ($s) $filename non eliminado ($s) $filename non cancellato ($s) $filename nebyl smazán ($s) $filename non effacé ($s) >continue >weiter >Weiterschaffe >continuar >continuar >continua >pokračovat >continuer Files from Dateien von Dateia von Ficheros de Ficheiros de File da Soubory od Fichiers de notification e-mail has been resent Benachrichtigungs-E-Mail wurde erneut verschickt no amole Bscheid gsagt Email de notificación reenviado notification e-mail has been resent E-mail di notifica è stata rispedita Zpráva s upozorněním byla obnovena l'email de notification a été réémis click on the file name to resend a notification e-mail klicken Sie auf den Dateinamen um die Benachrichtigungs-E-Mail erneut zu verschicken klick uf dr Dateinama, om dem Empfängr no amole Bscheid saga haga clic en el nombre de archivo para reenviar click on the file name to resend a notification e-mail clicca sul nome del file per rispedire un'e-mail di notifica pro opětovné odeslání zprávy s upozorněním klikněte na název souboru cliquer sur le nom du fichier pour envoyer à nouveau un email de notification Files for $to (*): Dateien für $to (*): Dateia fier $to (*): Ficheros para %to (*): Ficheiros para %to (*): File per $to (*): Soubory pro $to (*): Fichiers pour $to (*): \nfrom $from \nVon $from \nVon $from \nde $from \nde $from \nda $from \nod $from \nde $from >delete< >löschen< >löscha< >borrar< >eliminar< >cancella< >smazat< >effacer< >forward< >weiterleiten< >weiterleita< >reenviar< >forward< >prosegui< >přeposlat< >faire suivre< Files for other e-mail addresses you own will not be listed here! Dateien für Ihre andere E-Mail Adressen werden hier nicht aufgelistet! Dateia fier Deine andre E-Mail Adressa werded dohanne net uffglischtet! ¡Los ficheros para otras direcciones de correo electrónico suyas no son listadas aquí! Os ficheiros para outros enderezos de correo electrónico que teñ non se listan aquí! File per altri indirizzi di e-mail che ti appartengono non saranno elencati qui! Soubory pro další e-mailové adresy, které vlastníte, zde nebudou uvedeny! Les fichiers associés à vos autres adresses ne vont pas être listés ici! you are overquota Sie haben Ihr Speichervolumen überzogen Dei Schbeicherplatz isch rappelvoll ha excedido su cuota sobrepasou a sú cota Hai superato la quota překročili jste limit vous avez dépassé votre quota cannot receive files: is overquota Kann Dateien nicht annehmen: Speichervolumen überzogen I ko die Dateia net onemme: Dein Schbeicher isch scho vollgschdopft no puede recibir ficheros: ha excedido su cuota non pode recibir ficheiros: sobrepasou a súa cota non e' possibile ricevere il file: eccede la quota assegnata soubory nelze přijmout: překračují limit ne peut pas recevoir de fichiers: quota dépassé You ($from) are not allowed to fex to $to Sie ($from) dürfen nicht fexen an $to Du ($from) derfsch net fexa an $to Usted ($from) no puede enviar vía F*EX a $to Vostede ($from) non está autorizado para enviar, vía F*EX, a $to Tu ($from) non hai il permesso di spedire via F*EX a $to Vy ($from), nemáte dovoleno odesílat soubory pro $to Vous ($from) n'êtes pas autorisé à envoyer un fichier à $to recipient $to is not a registered F*EX full or sub user Empänger $to ist kein registrierter F*EX Voll- oder Subuser Dr Empfänger $to isch koin regischtrierder F*EX Voll- oddr Onderbenutzr el destinatario $to no es un usuario normal de F*EX registrado o un subusuario o destinatario $to non é un usuario normal de F*EX rexistrado ou un subusuario il destinatario $to non e' un utente o sotto-utente F*EX registrato příjemce $to není zaregistrovaným plnohodnotným uživatelem či poduživatelem F*EX le destinataire $to n'est pas un utilisateur ou un sous-utilisateur F*EX no upload key kein upload-Einmalschlüssel koi nufflad-Oimolschlissel ningun llave para subir non se cargou a chave no chiave di caricamento žádný klíč pro nahrání pas de clé d'upload request another one from fordern Sie einen neuen an von frog noch'm Neua bei pida otro de solicitar outra en richiedine un altro da požádat o jiný uživatele demander un autre de Your client seems to be "$1" which is incompatible with F*EX and will probably not work Ihr Client scheint "$1" zu sein, das ist aber inkompatibel mit F*EX und wird vermutlich nicht funktionieren Dein Client isch scheints "$1", des isch abbr inkomatibel mit F*EX ond so wird des wahrscheinlich nix Su cliente parece ser "$1" que es incompatible con F*EX y probablemente no funcionará O seu cliente parece ser "$1" que é incompatíbel con F*EX e probablemente non funcionará Il vostro client sembra essere "$1", che e' incompatibile con F*EX e probabilmente non funzionera' Zřejmě používáte prohlížeč "$1", který není kompatibilní s F*EX a pravděpodobně nebude správně fungovat Votre client semble être "$1" qui est incompatible avec F*EX et ne va sans doute pas fonctionner sender: Absender: Absendr: remitente: remitente: mittente: odesilatel: expéditeur: recipient: Empfänger: Empfängr: destinatario: destinatario: destinatario: příjemce: destinataire: recipient(s): Empfänger: Empfängr: destinatario(s): destinatario(s): destinatario(i): příjemce(i): destinataire(s): recipient(s)< Empfänger< Empfängr< destinatario(s)< destinatario(s)< destinatario(i)< příjemce(i)< destinataire(s)< e-mail address or alias E-Mail Adresse oder Alias E-Mail Adress oddr Alias dirección de correo electrónico o alias enderezo de correo electrónico ou alias indirizzo e-mail o alias e-mailová adresa či alias adresse e-mail ou alias or select from your address book oder aus Ihrem Adressbuch wählen oddr aus Deim Adressbüchle raussuche o seleccione de su libro de direcciones ou seleccione da súa axenda de enderezos o seleziona dal tuo rubrica nebo si vyberte ze svého adresáře ou sélectionner de votre carnet d'adresses and' und' ond' y' e' e a' et' add to recipients list zur Empfänger-Liste hinzufügen uff d' Empfängerlischte setza añada a la lista de destinatarios engadir á lista de destinatarios aggiungi alla lista di distribuzione přidejte jej (je) do seznamu příjemců ajouter à la liste des destinataires check recipient(s) and continue Empfänger überprüfen und fortsetzen Empfängr ieberpriafa ond weitermacha compruebe el/los destinatario(s) y continúe comprobe o/os destinatario(s) e continúe controlla i/il destinatari(o) e continua zkontrolovat příjemce a pokračovat vérifier le ou les destinataires et continuer >or< >oder< >odr< >o< >or< >oppure< >nebo< >ou< or < oder < odr < o < or < oppure < nebo < ou < and < und < ond < y < e < e < a < et < You are a restricted user and may only fex to these recipients: Sie sind ein eingeschränkter Benutzer und können nur an diese Empfänger fexen: Du bisch a eigeschränktr Benutzr ond kosch bloss an die Empfängr fexa: Usted es un usuario restringido y solo puede enviar a estos destinatarios: You are a restricted user and may only fex to these recipients: Sei un utente limitato e puoi inviare solo a questi destinatari: Jste uživatel s omezením a můžete odesílat pouze těmto příjemcům: Vous êtes un utilisateur restreint et vous ne pouvez utiliser fex que pour ces destinataires: fex yourself eigene Adresse verwenden fex dir selbr usar la propria dirección fex yourself fex te stesso zaslat sobě à votre adresse user config & operation control Benutzer Bedienungssteuerung Benutzr Bdienongssteierong configuración de usuario y control de operación configuración de usuario e control de operación configurazion utente & controllo operazioni nastavení uživatele a řízení provozu configuration utilisateur et gestion Alternate Java client (for files > 2 GB or sending of more than one file) Alternativer Java Client (für Dateien größer als 2 GB oder zum Senden von mehr als einer Datei) Alternativer Java Client (fier Dateia wo größer send als 2 GB oder zum Sende von meh als oiner Datei) Cliente java alternativo (par ficheros > 2 GB o envío de más de un fichero) Cliente java alternativo (para ficheiros > 2 GB ou envío de más dun fichero) Client java alternativo (per file > 2 GB o per spedizioni di più di un file) Alternativní Java klient (pro soubory větší než 2 GB či pro odesílání více než jednoho souboru) Client Java alternatif (pour les fichiers > 2 GB ou envoyer plusieurs fichiers d'un coup) Warning: the recipient must not be a mailing list Warnung: die Empfängeradresse darf keine Mailingliste sein Obacht: die Empfängeradress darf koi Mailinglischt sei Aviso: el destinatario no debe ser una lista de correo Warning: the recipient must not be a mailing list Attenzione: il destinatario non deve essere una lista di distribuzione Upozornění: příjemce nemůže být poštovní konference Attention: le destinataire ne peut pas être une liste de diffusion because after download the file will be no more available weil nach dem Download wird die Datei nicht mehr verfügbar sein weil nochm Ronderlada isch die Datei nemme verfügbar porque tras la descarga del fichero ya no estará disponible because after download the file will be no more available siccome dopo il download il file non sarà più disponibile protože soubor již nebude po stažení dostupný parce qu'après le téléchargement, le fichier ne sera plus disponible Contact fexmaster if you want to fex to a mailing list Kontaktieren Sie den fexmaster wenn Sie an eine Mailingliste fexen wollen Frog dr fexmaster wenn Du an a Mailinglischt fexa wilsch Contacte con fexmaster si desea hacer un envío a una lista de correo Contact fexmaster if you want to fex to a mailing list Contatta fexmaster se vuoi fexare ad una lista di distribuzione Chcete-li poslat soubor do poštovní konference, kontaktujte fexmastera Contacter fexmaster si vous voulez fexer à une liste de diffusion he can allow multiple downloads for specific addresses er kann für bestimmte Adressen einen mehrfachen Download freischalten der ko fir beschtemmte Adressa a mehrfaches Ronderlada erlauba el puede permitir múltipes descargas para una direcció,nespecífica he can allow multiple downloads for specific addresses egli puo' permettere download multipli per indirizzi specifici ten může umožnit vícenásobná stahování pro určité adresy il peut autoriser plusieurs téléchargements pour des adresses spécifiques Use a F*EX client if you want to send more than one file or resume an interrupted upload Verwenden Sie einen F*EX client wenn Sie mehr als eine Datei versenden wollen oder einen abgebrochenen Upload wiederaufnehmen wollen Nemm an F*EX client wenn du meh als oi Datei verschicka willsch oder an abbrochona Nufflad wiederaufnehma willsch Use un cliente F*EX si desea enviar más de un fichero o continuar una subida interrumpida Use a F*EX client if you want to send more than one file or resume an interrupted upload Usa F*EX client se vuoi spedire più di un file o riesumare un upload interrotto Pokud chcete odeslat více než jeden soubor, nebo pokračovat v přerušeném nahrávání, použijte klienta pro F*EX Utilisez un client F*EX si vous voulez envoyer plus d'un fichier ou poursuivre un upload interrompue You have to fill out this form completely to continue Sie müssen dieses Formular komplett ausfüllen um fortzufahren Du musch des Formular ganz ausffülla sonsch kosch ned weitrmacha Hace falta cumplimentar este formulario completamente antes de continuar Fai falta cubrir este formulario completamente antes de continuar Devi riempire completamente questo form per continuare Pro pokračování musíte kompletně vyplnit formulář Merci de compléter ce formulaire pour continuer sender quota (used):$quota ($du) MB Absender Quota (benutzt):$quota ($du) MB Absendr Quota (benutzt):$quota ($du) MB cuota de remitente (usada):$quota ($du) MB cota de remitente (usada):$quota ($du) MB quota utente (usata):$quota ($du) MB limit pro odesílání (used):$quota ($du) MB quota expéditeur (utilisé):$quota ($du) MB autodelete: Automatisches Löschen: Automadischs Lösche: autoborrar: autoeliminación: autocancellazione: automatické mazání: suppression automatique keep file max $keep days, then delete it Behalte die Datei für max. $keep Tage, dann lösche sie Bhalt die Datei fier höchschdens $keep Tage, dann kosch se lösche conserve el fichero un máximo de $keep días, a continuación borrelo conserve o ficheiro un máximo de $keep días, a seguir bórreo conserva il file al massimo per $keep giorni, quindi cancellalo uchovat soubor maximálně $keep dnů, pak jej smazat garder les fichiers au maximum $keep jours et les supprimer keep: Bleibt auf Server: Bleibt uffm Server: conserve: gardar: mantieni: uchovat: conserver: $keep days $keep Tage $keep Dag $keep días $keep días $keep giorni $keep dnů $keep jours comment: Kommentar: Kommendar: comentario: comentario: commento: komentář: commentaire: bandwith limit Bandbreitenbeschränkung Bandbroidebschränkong anchura de banda largo de banda limite di banda omezení rychlosti limite de bande passante optional, full speed if empty optional, volle Geschwindigkeit wenn leer optional, volle Lotte wenn leer opcional, velocidad maximal en caso de vacia opcional, velocidade máxima cando baleira opzionale, massima velocita' se vuoto volitelné, je-li prázdné, využije se plná rychlost optionnel, pas de limite si non renseignée optional, will be included in notification e-mail optional, wird in Benachrichtigungs-E-Mail mitgeschickt optional, isch no en dr Benochrichtigongs-Mail mit drbei opcional, será enviado por email de notificación optional, will be included in notification e-mail opzionale, sarà incluso nell'e-mail di notifica volitelné, připojí se ke zprávě s upozorněním optionnel, sera inclus dans votre email de notification no notification e-mail will be send es wird keine Benachrichtigungs-E-Mail verschickt s\'wird koi Benochrichtigongs-Mail verschickt No se enviará ningún correo de notificación non se enviará notificación de correo nessuna notificazione via e-mail verrà spedita žádný e-mail s upozorněním se neodešle aucun message de notification ne sera envoyé If you want to send more than one file, then put them in a zip or tar archive Wenn Sie mehr als eine Datei senden möchten, dann erzeugen Sie ein zip oder tar Archiv Wenn De meh als oi Datei verschigge willsch, no mach a zip oddr a tar Archiv Si desea enviar más de un fichero póngalos en un archivo zip De querer enviar más dun fichero póñaos nun arquivo zip Se vuoi spedire più di un file, mettili in un archivio zip o tar Chcete-li odeslat více jak jeden soubor, zkomprimujte jej do zip nebo tar archivu Si vous voulez envoyer plus d'un fichier, mettez les dans un zip ou une archive tar file: Datei: Datei: fichero: ficheiro: file: soubor: fichier: user config & operation control Benutzer Konfigurations- und Bedienungssteuerung Benutzr Konfigurations- ond Bedienongssteierong configuración de usuario & control de operaciones configuración de usuario e control de operacións configurazione utente & controllo operazioni nastavení uživatele a řízení provozu configuration utilisateur & gestion I have lost my auth-ID! Send it to me by e-mail! Habe meine auth-ID vergessen! Bitte mir diese per E-Mail zuschicken! I hann mei auth-ID vrschlampt! Schick se mir no mol per E-Mail! ¡He perdido mi auth-ID! ¡Envíemelo por correo electrónico! Perdín o meu auth-ID! ¡Envíemo por correo electrónico! Ho perso il mio auth-ID! Spediscimelo via e-mail! Zapomněl jsem své ověřovací ID! Odešli mi jej na e-mail! J'ai perdu mon auth-ID ! Le recevoir par e-mail ! I have lost my auth-ID Habe meine auth-ID vergessen I hann mei auth-ID vrschlampt He perdido mi auth-ID Perdín o meu auth-ID Ho perso il mio auth-ID Zapomněl jsem své ověřovací ID J'ai perdu mon auth-ID you must fill out sender field above Sie müssen oben dazu das \"Absender\"-Feld ausfüllen Du musch drzu do obe des \"Absendr\"-Feld ausfille debe rellenar el campo remitente anterior debe cubrir o campo remitente anterior devi riempire il campo mittente sopra musíte vyplnit políčko odesilatel výše vous devez renseigner le champ expéditeur check ID and continue weiter weider comprobar el ID y continuar comprobar o ID e continuar controlla ID e continua ověřit ID a pokračovat vérifier l'ID et continuer no file specified Keine Datei angegeben Koi Datei ogebbe no se espcificó el fichero non se espcificóu o ficheiro nessun file specificato nebyl uveden soubor aucun fichier spécifié no sender specified Kein Absender angegeben Koin Absendr ogebbe no se especificó el remitente non se especificóu o remitente nessun mittente specificato nebyl uveden odesilatel aucun expéditeur spécifié no recipient specified Kein Empfänger angegeben Koin Empfängr ogebbe no se especificó el destinatario non se especificó o destinatario nessun destinatario specificato nebyl uveden příjemce aucun destinataire spécifié wrong auth-ID specified Falsche auth-ID angegeben Falsch auth-ID ogebbe auth-ID especificado erróneo o auth-ID especificado é incorrecto auth-ID indicato sbagliato bylo uvedeno chybné ověřovací ID auth-ID erroné address book updated Adressbuch aktualisiert Adressbüchle isch uffm neueschte Schdand libro de direcciones actualizado axenda de enderezos actualizada rubrica aggiornata adresář byl aktualizován carnet d'adresses mis à jour cannot rename $upload to Konnte $upload nicht umbenennen in I hab $upload net umbenenne könne in no se puede renombrar $upload a non se pode renomear $upload como non posso rinominare $upload in nepodařilo se přejmenovat $upload na ne peut pas renommer $upload en No file data received Keine Daten erhalten Koine Date kriegt No se ha recibido ningún fichero de datos Non se recibiu ningún ficheiro de datos Nessun file di dati ricevuto Data souboru nebyla přijata aucune donnée reçue File name correct? Stimmt der Dateiname? Isch der Dateinome richdig? ¿Nombre de fichero correcto? Nome de ficheiro correcto? Nome file corretto? Je název souboru správný? Est-ce que le nom du fichier est correct ? File too big (browser-limit: 2 GB!)? Datei zu groß (Browser-Limit: 2 GB!)? Die Datei isch zu groß (Browser-Limit: 2 GB!)? ¿Fichero demasiado grande (límite del navegador: ¡2GB!)? Ficheiro demasiado grande (límite do navegador: 2GB!)? File troppo grande (limite-browser: 2 GB!)? Není soubor příliš velký (limit prohlížeče: 2 GB!)? Fichier trop volumineux (limite du navigateur: 2GB!)? is not allowed at beginning of ist nicht erlaubt am Anfang von des derfsch net mache am Ofang von no se permite al principio de non se permite ao principio de non e' consentito all'inizio di není povoleno na začátku n'est pas autorisé au début de is not allowed in ist nicht erlaubt in des derfsch net mache in no se permite en non se permite en non e' consentito in není povoleno v n'est pas autorisé dans is not allowed ist nicht erlaubt des derfsch net mache no se permite non se permite non e' consentito není povoleno n'est pas autorisé is not allowed at end of ist nicht erlaubt am Ende von des derfsch net mache am End von no se permite al final de non se permite ao final de non e' consentito alla fine di není povoleno na konci n'est pas autorisé à la fin de invalid Content-Length Ungültiger Content-Length Ungültiger Content-Length Content-Length inválido O Content-Length é incorrecto Content-Length non valido Content-Length není platné Content-Length invalide not enough free space for this upload Nicht genug freier Speicher für diesen Upload 'S isch net gnug Schbeicher frei om des nuffzulade no hay espacio libre suficiente para la subida non hai espazo libre suficiente para a subida non c'e' abbastanza spazio per questo caricamento pro nahrání není dost místa pas assez d'espace libre pour cet upload missing sender e-mail address E-Mail Adresse vom Sender fehlt koi E-Mail Adress vom Sender falta la dirección del remitente falt o enderezo do remitente manca l'indirizzo e-mail del mittente chybí e-mailová adresa odesilatele e-mail de l'expéditeur manquant is not a valid e-mail address ist keine gültige E-Mail Adresse des isch koi giltige E-Mail Adress no es una dirección de correo electrónico válido non é un enderezo de correo electrónico correcto non e' un indirizzo e-mail di posta valido není platná e-mailová adresa n'est pas une adresse e-mail valide no file data received - does your file exist or is it >2GB Keinen Datensatz erhalten - existiert die Datei wirklich oder ist es größer als 2 GB I hab koine Date kriegt - Gibt's dui Datei ieberhaupt oddr isch se größer als 2 GB no se ha recibido ningún fichero - existe su fichero o es >2GB non se recibiu ningún ficheiro - existe o seu ficheiro ou é >2GB non e' stato ricevuto nessun file - il tuo file esiste o e' >2GB data souboru nebyla přijata - zkontrolujte, zda soubor existuje nebo není větší než 2 GB pas de donnée reçue - est-ce que votre fichier existe or est-il >2GB file size unknown Dateigröße unbekannt Koi Ohnung, wie groß dui Datei isch tamaño del fichero desconocido tamaño do ficheiro descoñecido dimensione file sconosciuta neznámá velikost souboru taille du fichier inconnue file size Dateigröße So fett isch des Doil tamaño del fichero tamaño do ficheiro dimensione file velikost souboru taille du fichier No file selected Keine Datei ausgewählt Koi Datei ausgwählt Ningún archivo seleccionado No file selected Nessun file selezionato Žádný soubor nebyl vybrán Aucun fichier sélectionné no filename?! Kein Dateiname?! Koin Dateinome?! ¡¿no hay nombre de fichero?! non hai nome de ficheiro?! manca il nome del file ?! zadali jste název souboru?! pas de nom de fichier ?! transfer is already in progress ein Transfer läuft gerade 'S isch grad en Transfer am laufe la transferencia ya está en curso a transferencia xa está en marcha il trasferimento e' gia' in corso přenos již probíhá le transfert est déjà en cours. a download is currently in progress ein Download läuft gerade 'S wird grad was ronderglade una descarga está ahora en curso unha descarga está agora en marcha un download e' al momento in corso probíhá stahování un téléchargement est en cours no file data for Keine Datei-Daten für Koine Datei-Date fier no ha fichero para non hai ficheiro para nessun file per žádná data souboru pro pas de données pour File "$filename" copy-forwarded to $to and notified Datei "$filename" wurde kopiert und an $to weitergeleitet. $to wurde benachrichtigt Datei "$filename" isch kopiert ond an $to weitergleided worde. $to isch benochrichdigt Fichero "$filename" copiada reenviada a $to y notificado Ficheiro "$filename" copiada reenviada a $to e notificada File "$filename" copia inoltrata a $to e notificata Soubor "$filename" kopie byla předána na $to a oznamovací e-mail byl odeslán Le fichier "$filename" a été retransmis à $to et un message a été envoyé forward a copy of "$filename" to: Eine Kopie von "$filename" weiterleiten an: A Kopie von "$filename" weiterschicke an: reenviada una copia de "$filename" a: reenviada unha copia de "$filename" a: inoltra una copia di "$filename" a: předat kopii souboru "$filename" na: Transmettre une copie de "$filename" à: F*EX user registration ERROR F*EX-Benutzer Registrierungsfehler F*EX-Benutzr Regischdrierongsfehler ERROR en el registro del usuario F*EX ERRO no rexistro do usuario F*EX ERRORE di registrazione utente F*EX Chyba při registraci F*EX uživatele ERREUR lors de l'enregistrement de l'utilisateur F*EX F*EX user registration F*EX-Benutzer Registrierung F*EX-Benutzr Regischdrierong registro del usuario de F*EX rexistro do usuario de F*EX registrazione utente F*EX registrace F*EX uživatele Enregistrement d'un utilisateur F*EX illegal registration key Illegaler Registrierungs-Schlüssel Der Regischdrierongsschlissel gildet net clave de registro ilegal chave de rexistro ilegal chiave di registrazione illegale neplatný registrační klíč Clé d'enregistrement illégale no registration key Kein Registrierungs-Schlüssel Koin Regischdrierongsschlissel sin clave de registro sen chave de rexistro non c'e' la chiave di registrazione žádný registrační klíč pas de clé d'enregistrement no registration data for key Keine Registrierungs-Daten für Schlüssel Koine Regischdrierongsdate fier den Schlissel no hay datos de registro para la clave non hai datos de rexistro para a chave non ci sono dati di registrazione per la chiave žádná registrační data pro klíč pas de données d'enregistrement pour la clé Your registration was successful. Your new F*EX account is: Ihre Registrierung war erfolgreich. Ihr neuer F*EX-Account ist: Du hoschs gschafft. Dein neies F*EX-Konto isch: Su registro tuvo existo. Su nueva cuenta F*EX es: O rexistro foi correcto. A súa nova conta F*EX é: La tua registrazione e' stata eseguita con successo. Il tuo nuovo utente F*EX e': Registrace proběhla úspěšně. Váš nový F*EX účet je: Votre enregistrement s'est bien déroulé. Votre nouveau compte F*EX est: bookmark this URL nehmen Sie diese URL in ihre Bookmarks auf des musch en deine Bookmarks aufnehma Crear marcador de este URL engadir este enderezo URL aos marcadores inserisci questo URL nei preferiti přidat URL k oblíbeným sauvegarder cette URL or you can use oder Sie verwenden oder du nemsch o puede usar ou pode utilizar o puoi usare nebo můžete ou vous pouvez utiliser Your domain $exd is not allowed for registration Ihre Domain $exd ist nicht zugelassen für Registrierung Dei Domain $exd ghod ned for d'Regischtrierong Su dominio $exd no está permitido a registrar Your domain $exd is not allowed for registration Il tuo dominio $exd non è permesso per la registrazione Registrace z domény $exd není povolena Votre domaine $exd n'est pas autorisé à l'enregistrement Registrations from your host ($ra) are not allowed Registrierungen von Ihrem Host ($ra) sind nicht erlaubt Regischdrieronga von Deim Host ($ra) send net geschdaddet Los registros desde su equipo ($ra) no están permitidos Os rexistros desde o seu equipo ($ra) non están permitidos Registrazioni dal tuo host ($ra) non sono permesse Registrace z vašeho počítače ($ra) nejsou povoleny Les enregistrements à partir de votre poste ($ra) ne sont pas autorisés Contact $ENV{SERVER_ADMIN} for details Kontaktieren Sie $ENV{SERVER_ADMIN} für Details Wend De an $ENV{SERVER_ADMIN}, wenn De Näheres wisse willsch Contacte con $ENV{SERVER_ADMIN} para obtner más detalles Contacte con $ENV{SERVER_ADMIN} para obter más detalles Contatta $ENV{SERVER_ADMIN} per i dettagli Pro více informací kontaktujte $ENV{SERVER_ADMIN} Contacter $ENV{SERVER_ADMIN} pour des détails supplémentaires $user is disabled $user ist gesperrt $user isch gschperrt $user está bloqueado $user is disabled $user è disabilitato $user je zakázán $user est désactivé or

      oder

      odr

      o

      ou

      o

      nebo

      ou

      you are already registered Sie sind bereits registriert Du bisch doch scho längscht regischdriert ya está registrado xa está rexistrado sei gia' registrato již jste zaregistrovaní Vous êtes déjà enregistré new user (may send to internal or external users) neuer Benutzer (darf an interne oder externe Benutzer senden) neur Benutzr (darf an intern odr extern Benutzr senda) nuevo usuario (permitido a enviar a usuarios internos o externos) novo usuario (permitido enviar a usuarios internos ou externos) nuovo utente (potresti spedire ad utenti interni o esterni) nový uživatel (může odesílat interním či externím uživatelům) nouvel utilisateur (peut envoyer à des utilisateurs internes ou externes) new external user (may send only to internal users) neuer externer Benutzer (darf nur an interne Benutzer senden) neur externer Benutzr (darf bloss an interne Benutzr senda) nuevo usuario externo (solamente permitido a enviar a usuarios internos) novo usuario externo (soamente pode enviar a usuarios internos) nuovo utente esterno (potrebbe spedire solo a utenti interni) nový externí uživatel (může odesílat pouze interním uživatelům) nouvel utilisateur externe (peut seulement envoyer à des utilisateurs internes) internal domains are interne Domains sind interne Domains senn dominio internos son dominios internos domini interni sono interní domény jsou les domaines internes sont allowed domains are: zugelassene Domains sind: die Domains darfsch benutza: domínios permitidos son: allowed domains are: domini consentiti sono: povolené domény jsou: les domaines autorisés sont: you must enter your e-mail address and Sie müssen Ihre E-Mail Adresse eingeben Du musch dei E-Mail Adress ogeba hace falta introducir su dirección de correo electrónico debe escribir o seu enderezo de correo electrónico e devi inserire un indirizzo e-mail e musíte zadat svou e-mailovou adresu a vous devez donner votre adresse e-mail et your e-mail address Ihre E-Mail Adresse dei E-Mail Adress sú dirección de correo electrónico o séu enderezo de correo electrónico il tuo indirizzo e-mail vaše e-mailová adresa votre adresse e-mail F*EX user registration F*EX-Benutzer Registrierung F*EX-Benutzrregischdrierong Registro del usuario de F*EX Rexistro do usuario de F*EX Registrazione utente F*EX Registrace F*EX uživatele Enregistrement F*EX $user has been auto-registrated with $user wurde auto-registriert mit $user isch auto-regischdriert worde mit $user ha sido autoregistrado con $user foi autorexistrado con $user e' stato autoregistrato con $user byl automaticky zaregistrován s l'utilisateur $user a été automatiquement enregistré avec F*EX user registration request F*EX-Benutzer Registrierungs-Anfrage F*EX-Benutzrregischdrierongsofrog Petición de registro de usuario F*EX Petición de rexistro de usuario F*EX Richiesta registrazione utente F*EX Požadavek na zaregistrování F*EX uživatele Demande d'enregistrement d'utilisateur F*EX To activate your new F*EX account go to this URL: Um Ihren neuen F*EX-Account zu aktivieren oeffnen Sie diese URL: Om Die neis F*EX-Konto zu aktiviere, gang uff die URL: Para activar su nueva cuenta en F*EX vaya a esta URL: Para activar a súa nova conta en F*EX vaia a este URL: Per attivare il tuo nuovo utente F*EX vai a questo URL: Pro aktivaci svého nového F*EX účtu přejděte na tuto URL: Pour activer votre nouveau compte F*EX, rendez vous à cette URL: The conditions of usage are: Die Benutzungsbedingungen sind: Die Mitmachregla senn: Los términos de uso son: The conditions of usage are: Le condizioni d'uso sono: Podmínky používání jsou: Les conditions d'usage sont: confirmation e-mail has been sent to $user Bestätigungs-E-Mail wurde gesendet an Benutzer $user Beschdädigongs-E-Mail isch gschickt worde an Benutzr $user Un correo electrónico de confirmación se le ha enviado a $user Envióuselle un correo electrónico de confirmación a $user e-mail di conferma e' stata spedita a $user potvrzovací e-mail byl odeslán uživateli $user Un message de confirmation a été envoyé à $user This is an automatically generated e-mail Dies ist eine maschinell generierte E-Mail Des isch a Automata-E-Mail Este e-mail ha sido generado automaticamente Este correo foi xerado automaticamente Questa e' una e-mail generata automaticamente Toto je automaticky vytvořený e-mail Ceci est un message généré automatiquement Illegal domain for username Illegale Domain fuuml;r Benutzernamen Illegale Domain fier de Benutzrnome Dominio ilegal para el nombre de usuario O dominio deste nome de usuario é irregular Dominio illegale per l'utente Neplatná doména pro uživatelské jméno Domaine invalide pour l'utilisateur is not an email address ist keine E-Mail-Adresse isch koi E-Mail-Adress no es una dirección email is not an email address non è un indirizzo e-mail není e-mailová adresa n'est pas une adresse électronique F*EX redirect ERROR F*EX Umadressierungs-FEHLER F*EX Bei der Omadressierong isch was schiefgloffe ERROR de redirección de F*EX Produciuse un ERRO de redirección de F*EX ERRORE di inoltro F*EX CHYBA při přesměrování F*EX ERREUR de redirection F*EX wrong user or auth-ID Falscher Benutzer oder falsche auth-ID Benutzr oddr auth-ID send falsch usuario o auth-ID erróneo o usuario ou o auth-ID son incorrectos utente o auth-ID sbagliato chybný uživatel nebo ověřovací ID utilisateur ou auth-ID invalide has no no files in spool from you hat keine Dateien in spool von Ihnen hat von Dir koine Dateia em spool no hay ficheros en la cola que haya enviado usted non hai ficheiros na cola da súa parte non ci sono file nello spool per te nemá od vás ve frontě žádné soubory n'a pas de fichiers venant de vous F*EX redirect F*EX Umadressierung F*EX Omadressierong redirección F*EX redirección F*EX inoltro F*EX Přesměrování F*EX Redirection F*EX old (wrong) recipient: Alter (falscher) Empfänger: Alder (falscher) Empfängr: viejo (erróneo) destinatario: antigo (incorrecto) destinatario: vecchio (sbagliato) destinatario: původní (chybný) příjemce: ancien (invalide) destinataire: new recipient: Neuer Empfänger: Neier Empfängr: nuevo destinatario: novo destinatario: nuovo destinatario: nový příjemce: nouveau destinataire: filename: Dateiname: Nome von der Datei: nombre de fichero: nome de fichero: nome file: název souboru: nom de fichier: no upload data found for $file for $oto Keine bereitgestellen Daten gefunden für $file für $oto Koine nuffgladene Date gefonde fierr $file fier $oto no hay datos subidos para $file para $oto non se cargaron datos de $file para $oto nessun file di dati da caricare per $file per $oto u $oto nebyla pro soubor $file nalezena žádná nahraná data pas de données trouvées pour le fichier $file pour $oto notification of file upload \"$filename\" sent to $nto Benachrichtigung vom Datei-Upload \"$filename\" gesendet an $nto Benochrichdigong iber die nuffgladene Datei \"$filename\" gschickt an $nto notificación de las subida del fichero \"$filename\" enviado a $nto enviada a notificación da carga do ficheiro \"$filename\" enviado a $nto notifica del file caricato \"$filename\" spedita a $nto oznámení o nahrání souboru \"$filename\" odesláno na $nto un message d'information concernant le fichier uploadé \"$filename\" a été envoyé à $nto redirect $nto/$from/$fkey failed Umadressierung $nto/$from/$fkey fehlgeschlagen Bei dr omadressierung $nto/$from/$fkey isch was schiefgloffe redirección a $nto/$from/$fkey falló fallou a redirección a $nto/$from/$fkey inoltro $nto/$from/$fkey fallito přesměrování $nto/$from/$fkey selhalo la redirection vers $nto/$from/$fkey a échouée Please avoid download with Internet Explorer, Falls Sie zum Download Internet Explorer benutzen, koennte es Falls Du zom Ronderlada Internet Explorer nemmsch, waer's meglich, dass Por favor, evite usar Internet Explorer para las descargas, Por favor, evite usar Internet Explorer para as descargas, Per favore evita di fare il download con Internet Explorer Nestahujte prosím pomocí prohlížeče Internet Explorer, Merci d'éviter d'utiliser Internet Explorer, because it has too many bugs unter Umstaenden zu Problemen kommen Du a Problem hosch porque tiene demasiados errores porque ten demasiados defectos perche' ha troppi bug protože má příliš mnoho chyb parce qu'il a beaucoup trop de problèmes We recommend Wir empfehlen Mir empfehled Recomendamos Recomendamos Raccomandiamo Doporučujeme používat Nous recommandons #We recommend Firefox or wget #Wir empfehlen Ihnen Firefox oder wget #Nemm lieber Firefox oder wget #Recomendamos Firefox o wget #Recomendámoslle Firefox ou wget #Raccomandiamo di usare Firefox o wget #Doporučujeme použít Firefox či wget #Nous reconmmandons Firefox ou wget We recommend fexget or fexit for download Wir empfehlen fexget oder fexit fuer den Download Mir empfehlad fexget odr fexit firs Ronderlada Recomendamos fexget o fexit para la descarga We recommend fexget or fexit for download Raccomandiamo fexget o fexit per il download Pro stahování doporučujeme fexget nebo fexit, Nous recommandons fexget ou fexit pour un téléchargement because these clients can resume the download after an interruption weil diese Programme einen unterbrochenen Download wiederaufnehmen koennen weil Du mit dene Denger an abbrochana Ronderlad wiederaufnehma kosch porque estos clientes pueden continuar una descarga que ha sido interrumpida because these clients can resume the download after an interruption dato che questi clients possono riesumare il download dopo una interruzione protože tito klienti umožňují pokračovat ve stahování po přerušení parce que ces clients peuvent poursuivre un téléchargement après une interruption After download (or view with a web browser!), Nach Download (oder Ansicht mit dem Web Browser!) Nochm Ronderlada (odr wenn Du's mitm Webbrowser oguckt hosch!) Tras la descarga, Tras a descarga, Dopo il download (o dopo essere stato visto con un browser WEB!) Po stažení (či zobrazení v prohlížeči!), Après le téléchargement (ou visualisation avec un navigateur web) the file will be deleted! wird die Datei geloescht! wird dui Datei gloescht! ¡el fichero se borrará! o ficheiro borrarase! il file sara' cancellato bude soubor smazán! le fichier a été effacé ! When you download the file it will be deleted Wenn Sie die Datei herunterladen dann wird diese eine kurze Zeit Wenn Du die Datei ronderlaedsch, wird se bald drnoch Cuando descargue el fichero se borrará Cando descargue o fichero, este borrarase; Quando scarichi il file sara' cancellato Jakmile si soubor stáhnete, bude po té Lorsque vous téléchargez un fichier, celui-ci sera effacé soon afterwards! danach geloescht werden! gloescht! en breve! moi axiña! poco dopo! ihned smazán! dans les instants qui suivent ! is a container file ist ein Container isch a Schachtel es un archivo contenedor é un ficheiro contedor e' un archivio je soubor archivu est une archive You can unpack it for example with 7zip Sie koennen es z.B. mit 7zip oeffnen Du kosch's z.B. mit 7zip aufmacha Se puede descompactarlo con 7zip Pódese descomprimir con 7zip Puoi decomprimerlo con 7zip Rozbalit jej můžete pomocí programu 7zip Vous pourrez l'ouvrir avec 7zip par exemple This download link only works for you, you cannot distribute it Dieser Download Link funktioniert nur fuer Sie, Sie koennen ihn nicht weitergeben Sell Ronderlad Link isch fei bloss fir Di, du kosch\'n ned weitergaeba Este hipervínculo funciona solamente para tí, no puedes compartirlo Esta ligazón de descarga só funciona para vostede, non a difunda Questo link di download funziona solo per voi, non è possibile distribuire Odkaz je určen pouze vám, nemůžete jej dále šířit le lien de téléchargement ne fonctionnera que vous pour vous, vous ne pourrez pas le diffuser $receiver = 'you $receiver = 'Sie $receiver = 'Di $receiver = 'usted $receiver = 'vostede $receiver = 'te $receiver = 'vy $receiver = 'vous day" Tag" Dag" día" día" giorno" den" jour" days" Tagen" Dag" días" días" giorni" dnů" jours" days< Tagen< Dag< días< días< giorni< dnů< jours< has uploaded the file hat die Datei hod dui Datei ha subido el fichero cargou o ficheiro ha caricato il file nahrál soubor a uploadé un fichier for $receiver. Use fuer $receiver bereitgestellt. Verwenden Sie die URL fier $receiver bereitgschdellt. Nemm para $receiver. Use para $receiver. Use per $receiver. Usa pro $receiver. Stáhnout si jej můžete zde pour $receiver. Utilisez to download this file within $days um die Datei innerhalb von $days herunterzuladen damit Du dui Datei ennerhalb von $days ronderlada kosch para descargar este fichero antes de $days para descargar este fichero antes de $days per scaricare questo file entro $days během $days pour télécharger ce fichier d'ici $days F*EX is not an archive, it is a transfer system for personal files F*EX ist kein Archiv, sondern ein Dateien-Uebertragungssystem F*EX isch koi Archiv sondern a Syschtem zom Dateia iebertraga F*EX no es un archivo, es un sistema personal de transferencia de ficheros F*EX non é un arquivo, é un sistema persoal de transferencia de ficheiros F*EX non e' un sistema di archiviazione, e' un sistema personale di trasferimento di file F*EX není archiv, je to systém pro přenos souborů pro osobní použití F*EX n'est pas un système d'archivage, c'est un système de transfert de fichiers personnels For more information see $index Weitere Informationen finden Sie unter $index Gugsch au do: $index Para más informaciones vir a $index Para máis información, vexa $index Per ulteriori informazioni, vedere $index Pro více informací se podívejte na $index Voir $index pour plus d'informations No notification e-mail has been sent to $to Es wurde keine Benachrichtigungs-E-Mail an $to verschickt $to isch ned benochritigt worda No se ha enviado ningún correo electrónico de notificación a $to No notification e-mail has been sent to $to Nessuna e-mail di notifica è stata inviata a $to Žádný e-mail s oznámením nebyl $to odeslán Aucun email de notification n'a été envoyé à $to Ehh... $ndata BYTES?! You are kidding Moment... $ndata BYTES?! Das ist wohl ein Witz Moment amole $ndata BYTES?! Wilsch me verarsche Un momento... ¡¿$ndata BYTES?! Está bromeando Un intreo... BYTES?! Está de broma Ehh... $ndata BYTES?! Stai scherzando Moment... $ndata BYTŮ?! Děláte si legraci Eh... $ndata BYTES?! Vous rigolez Using F*EX for less than Verwendung von F*EX für weniger als Du nemsch F*EX fir wenigr als Usar F*EX por menos de Usar F*EX para menos de Usare F*EX per meno di Používat F*EX pro tak malý soubor Utiliser F*EX pour moins de ever heard of MIME e-mail Schon mal was von MIME E-Mail gehört Hosch scho mol was von MIME E-Mail ghört ha oído hablar del correo electrónico MIME non lle será mellor usar o correo electrónico MIME? mai sentito parlare delle e-mail MIME určitě jste někdy slyšeli o e-mailu Vous avez déja entendu parlé de l'e-mail received and saved empfangen und abgespeichert empfanga ond abgschpeichert recibido y guardado recibido e gardado ricevuto e salvato přijato a uloženo reçu et sauvegardé Download URL for copy & paste Download URL zum Kopieren Nonderlad URL zom Kopiera URL de descarga para copiar y pegar Descargar o URL para copiar e pegar Scarica l'URL per il copia ed incolla URL pro stažení okopírovat a vložit URL de téléchargement pour copier/coller Link is valid for $keep{$to} days Dieser Link ist für $keep{$to} Tage gültig Sell Link isch fir $keep{$to} Dag giltig El enlace es válido durante $keep{$to} días A ligazón é válida durante $keep{$to} días Il link è valido per $keep{$to} giorni Odkaz je platný $keep{$to} dny(ů) Le lien restera valide $keep{$to} jours old $file for $to overwritten vorhandenes $file für $to überschrieben alts $file fir $to iberschrieba El anterior $file para $to se ha sobreescrito Sobrescribiuse o anterior $file para $to vecchio file $file per $to sovrascritto původní soubor $file pro $to byl nahrazen $file pour $to reécrit. $to notified $to benachrichtigt $to bscheid gsagt $to ha sido notificado $to foi notificado $to notificato $to byl informován $to prévenu $file removed because you are a restricted user $file wurde gelöscht weil Sie ein eingeschränkter Benutzer sind $file isch wieder glöscht worda weil du a bschränkter Benutzer bisch $file se ha borrado porque usted es un usuario restringido $file removed because you are a restricted user $file rimosso perchè sei un utente limitato $file odstraněn, protože jste uživatel s omezením $file supprimé car vous êtes un utilisateur restreint and recipient $to cannot receive e-mail und Empfänger $to keine E-Mail empfangen kann ond Empfängr $to ko koi E-Mail empfanga y el destinatario $to no puede recibir correos electrónicos and recipient $to cannot receive e-mail ed il destinatario $to non può ricevere e-mail a příjemce $to nemůže přijímat poštu et le destinataire $to ne peut pas recevoir d'email send another file eine weitere Datei schicken a weitere Datei schicka enviar otro fichero enviar outro fichero spedire un altro file odeslat další soubor envoyer un autre fichier Upload Status for Upload Status für Nufflad Schtatus fier Estado del proceso de subida para Estado do proceso de carga de Stato del processo di caricamento per Stav nahrávání pro Status d'upload pour file successfully transferred Datei erfolgreich übertragen Datei nufflada hot klappt fichero transferido con &ecaute;xito o ficheiro transferiuse correctamente file trasferito con successo soubor byl úspěšně přenesen fichier transféré avec succès >close< >schließen< >fertig< >cerrar< >cerrar< >chiudi< >zavřít< >fermer< "upload" "upload" "nufflada" "subir" "cargar" "caricamento" "nahrát" "upload" value="logout" value="logout" value="adele" value="salir" value="saír" value="uscita" value="odhlásit" value="déconnexion" Using Microsoft Internet Explorer for download will probably Die Verwendung von Microsoft Internet Explorer für den Download wird wahrscheinlich Des Verwenda vom Microsoft Internet Explorer fier dr Download wird wahrscheinlich Usar Microsoft Internet Explorer para realizar las descargas probablemente Usar Microsoft Internet Explorer para realizar as descargas probablemente Usare Microsoft Internet Explorer per il download probabilmente Používání aplikace Microsoft Internet Explorer pro stahování pravděpodobně Utiliser Microsoft Internet Explorer pour le téléchargement lead to problems, because it is not Internet compatible (RFC 2616) zu Problemen führen, weil er nicht Internet kompatibel (RFC 2616) ist zu Problem fiehra, weil der hald ned Internet kompatibel (RFC 2616) isch le puede dar problemas, porque no es compatible con el estándar de Internet (RFC 2616) traerá problemas porque non é compatíbel co estándar de Internet (RFC 2616) genera problemi in quanto non e' compatibile con Internet (RFC 2616) povede k problémům, protože není Internetově kompatibilní (RFC 2616) entraînera probablement des problèmes, parce qu'il n'est pas compatible avec Internet (RFC 2616) We recommend Wir empfehlen Mir empfehlad Recomendamos Recomendámoslle Si raccomanda Doporučujeme Nous recommandons WARNING: WARNUNG: OBACHT: ADVERTIMIENTO: ATENCIÓN: ATTENZIONE: UPOZORNĚNÍ: ATTENTION: If you really want to continue with Internet Explorer, then Wenn Sie wirklich mit Internet Explorer weitermachen wollen, dann Wenn wirklich mitm Internet Explorer weiterwurschtla wilsch, no Si de verdad quiere continuar con Internet Explorer, Si de todas maneiras quere continuar co Internet Explorer, Se vuoi davvero continuare con Internet Explorer allora, Chcete-li skutečně pokračovat s aplikací Internet Explorer, potom Si vous souhaitez vraiment continuer avec Internet Explorer, alors click here with your right mouse button and select "save as" klicken Sie hier mit der rechten Maustaste und wählen Sie an "speichern unter" klicksch hier mit dr rechta Maustascht ond wählsch "speichern unter" aus pulse aquí con el botón derecho del ratón y seleccione "guardar como" prema aquí co botón dereito do ratón e seleccione "gardar como" cliccare qui con il tasto destro del mouse e selezionare "salva come" zde klikněte pravým tlačítkem myši a vyberte "Uložit jako" cliquez ici avec le bouton droit de la souris et sélectionner "save as" #Meta questions #Meta Fragen #Meta Froga #Meta Preguntas #Meta Preguntas #Meta Domande #Všeobecné Máte otázky #Questions générales #User questions #Benutzer Fragen #Benutzr Froga #Usario Preguntas #Usuario Preguntas #Utente Domande #Uživatel Máte otázky #Questions utilisateurs #Admin questions #Administratoren Fragen #Adminischdrator Froga #Admin Preguntas #Admin Preguntas #Amministratore Domande #Správce Máte otázky #Questions administrateur #Misc questions #Sonstige Fragen #Vermischte Froga #Misc Preguntas #Misc Preguntas #Misc Domande #Misc Máte otázky #Questions diverses Your F*EX account has been inactive for $expire days Ihr F*EX Account ist seit $expire Tagen inaktiv Du hosch dei F*EX Konto seit $expire Tag nemme bnutzt Su cuenta de F*EX ha estado inactivo $expire dias A súa conta F*EX estivo inactiva durante $expire día Il tuo account F*EX è stato inattivo per $expire giorni Váš F*EX účet byl neaktivní $expire dnů Votre compte F*EX a été inactif pendant $expire days you must download this file to reactivate it Sie muessen diese Datei herunterladen um ihn zu reaktivieren Du musch sell Datei ronderlada drmit weiter mitmacha derfsch hace falta descargar este fichero para reactivarla debe descargar este ficheiro para reactivala devi scaricare questo file per riattivarlo pro jeho opětovnou aktivaci si musíte stáhnout tento soubor vous devez télécharger ce fichier pour le réactiver Otherwise your account will be deleted Ansonsten wird Ihr Account geloescht Ansoschda bisch den Account los De lo contrario, su cuenta será eliminada Otherwise your account will be deleted Altrimenti il tuo account verrà eliminato Jinak bude váš účet smazán Sinon votre compte sera supprimé Account created: Account angelegt: Konto oglegt: Cuenta creada: Account created: Account creato: Účet vytvořen: Compte créé: (De)activate e-mail encryption E-Mail Verschlüsselung (de)aktivieren E-Mail Verschlüsslong (de)aktiviera (Des)activar codificación de email (De)activate e-mail encryption (Dis)attiva la crittografia delle e-mail Deaktivovat šifrování pošty (Dés)activer le chiffrement des emails PGP/GPG key deleted PGP/GPG key gelöscht PGP/GPG key glöscht Código PGP/GPG borrado PGP/GPG key deleted PGP/GPG chiave cancellata PGP/GPG klíč byl smazán Clé PGP/GPG supprimé E-mails to you will be sent not encrypted E-Mails an Sie werden nun unverschlüsslt verschickt Du kriegsch E-Mails jetzt overschlüsslt Emails para usted son enviados no codificado a partir de ahora E-mails to you will be sent not encrypted E-mail verso di te saranno spedite non crittografate Zprávy vám budou odesílány v nešifrované podobě Les emails que vous recevrez ne seront pas chiffrés E-mails to you will be encrypted with the PGP/GPG key: E-Mails an Sie werden nun verschlüsslt mit dem PGP/GPG key: Du kriegsch E-Mails jetzt verschlüsslt mit dem PGP/GPG key: Emails para usted son enviados codificado por código PGP/GPG: E-mails to you will be encrypted with the PGP/GPG key: E-mail verso di te saranno crittografate con una chiave PGP/GPG: Zprávy vám budou odesílány šifrované s PGP/GPG klíčem: Les emails que vous recevrez seront chiffrés avec la clé PGP/GPG: Your uploaded file does not contain a PGP/GPG public key for Die hochgeladene Datei enthält keinen PGP/GPG public key für En der nuffgladana Datei isch koi PGP/GPG public key fir El archivo cargado no contiene ningún código PGP/GPG público Your uploaded file does not contain a PGP/GPG public key for Il tuo file caricato non contiene una chiave pubblica PGP/GPG per Nahraný soubor neobsahuje veřejný PGP/GPG klíč pro Votre fichier uploadé ne contient pas de clé publique PGP/GPG pour Select your PGP/GPG public key file Wählen Sie Ihre PGP/GPG public key Datei aus Wähl Dei PGP/GPG public key Datei aus Elija su archivo con el código público Select your PGP/GPG public key file Seleziona il tuo file della chiave pubblica PGP/GPG Vyberte soubor s PGP/GPG veřejným klíčem Sélectionnez le fichier contenant votre clé publique PGP/GPG delete your already uploaded public key löschen Sie Ihren abgelegten public key lösch Dein abglegta public key borre su código público guardado delete your already uploaded public key cancella la tua chiave pubblica già caricata smazat předchozí nahraný veřejný klíč suprrimer votre clé publique déjà uploadée To extract and verify your GPG public key use: Um Ihren GPG public key zu extrahieren und verifizieren benutzen Sie: Om dein GPG public key zom extrahiera ond nochgucka nemsch am beschta: Para extraer y verificar su código publico use: To extract and verify your GPG public key use: Per estrarre e verificare la tua chiave pubblica GPG usa: K rozbalení a ověření svého PGP/GPG veřejného klíče použijte: Pour extraire et vérifier votre clé publique GPG, utilisez: ERROR: no upload received FEHLER: es wurde kein Upload empfangen FEHLER: do isch fei nix okomma ERROR: ningún subir recibido ERROR: no upload received ERRORE: nessun caricamento ricevuto CHYBA: žádný soubor nebyl nahrán ERREUR: aucun upload reçu You cannot send to more than one group Sie können nicht an mehrere Gruppen senden Du kansch net an mehrere Gruppa senda No puede enviar a varios grupos You cannot send to more than one group Non puoi spedire a più di un gruppo Nemůžete odesílat více než jedné skupině Vous ne pouvez pas envoyer à plus d'un groupe file transfer aborted Dateitransfer abgebrochen Dateitransfer abbrocha Trasmisión del archivo aborto file transfer aborted trasferimento file interrotto přenos souboru přerušen transfert de fichier abandonné $from is not allowed to upload from IP $ra $from darf nicht von IP-Adresse $ra hochladen $from darf ned von IP-Adress $ra hochlada $from no está permitido a subir de esta dirección IP $ra $from is not allowed to upload from IP $ra $from non è consentito caricarlo da IP $ra $from z IP adresy $ra není dovoleno nahrávat soubory $from n'est pas autorisé à uploader vers l'IP $ra Group $to does not exist Gruppe $to existiert nicht Grupp $to gibts net Grupo $to no existe Group $to does not exist Il gruppo $to non esiste Skupina $to neexistuje Le groupe $to n'existe pas server runs in NOMAIL mode - groups ($to) are not allowed Server läuft im NOMAIL Modus - Gruppen ($to) sind nicht erlaubt Server läuft em NOMAIL Modus - Gruppa ($to) senn net erlaubt Servidor está en modo NOMAIL - grupos ($to) no están permitidos server runs in NOMAIL mode - groups ($to) are not allowed server eseguto in modalità NOMAIL - i gruppi ($to) non sono permessi Server běží v režimu NOMAIL - skupiny ($to) nejsou povoleny Le serveur tourne en mode NOMAIL - les groupes ($to) ne sont pas autorisés File not found Datei nicht gefunden Datei net gfonda Archivo no encontrado File not found File non trovato Soubor nenalezen Fichier introuvable $to is not a valid recipient $to ist kein gültiger Empfänger $to isch koi gültigr Empfängr $to no es un destinario válido $to is not a valid recipient $to non è un destinatario valido $to není platný příjemce $to n'est pas un destinataire valide File $file already exists in your outgoing spool Datei $file existiert bereits im ausgehenden Spool Datei $file gibts fei scho em nausganganda Spool Archivo $file ya existe en sú spool saliente File $file already exists in your outgoing spool Il file $file esiste già nel tuo spool in uscita Soubor $file se již ve frontě k odeslání nachází Le fichier $file exite déjà dans votre spool sortant fex-20160919/locale/czech/0000755000174700017470000000000012654503773013262 5ustar fexfexfex-20160919/locale/czech/lib/0000755000174700017470000000000012770010165014013 5ustar fexfexfex-20160919/locale/czech/lib/fup.pl0000644000174700017470000000271712624117337015160 0ustar fexfex# config for F*EX CGI fup use utf8; $info_1 = $info_login = <


      F*EX (File EXchange) je služba pro odesílání velkých souborů.

      Odesilatel (vy) nahraje soubor na F*EX server a ten příjemci autimaticky odešle e-mail s oznámením a s URL ke stažení.
      Po jeho stažení, nebo po uplynutí $keep_default dnů, server soubor smaže. F*EX není archiv!

      Přečtěte si také Otázky a odpovědi (FAQ).


      $ENV{SERVER_ADMIN}
      EOD $info_2 = <

      Po potrzení uvidíte lištu s průběhem nahrávání (pouze, pokud máte povolen javascript a povolené automatické otevírání oken).

      POZNÁMKA: Většina webových prohlížečů neumožňuje nahrávat soubory větší než 2 GB!
      Pokud je váš soubor větší, použíjte speciálního klienta pro F*EX.
      Potřebuvoat budete také klient pro obnovení nahrávání v případě přerušení. Váš webový prohlížeč toto neumožňuje.

      UPOZORNĚNÍ: Některé HTTP proxy servery, jako je třeba privoxy, spomalují průběh nahrávání!
      V případě, že se s tímto pborlémem setkáte, bude zřejmě třeba zakázat používání proxy pro $ENV{SERVER_NAME}.

      Pro uživatele Firefoxu: Nemačkejte klávesu ESC, protože jinak se stahování přeruší!

      Přečtěte si také FAQ. EOD fex-20160919/locale/czech/lib/reactivation.txt0000644000174700017470000000006311626705134017251 0ustar fexfexVáš F*EX účet byl úspěšně znovu aktivován fex-20160919/locale/czech/htdocs/0000755000174700017470000000000012654505177014546 5ustar fexfexfex-20160919/locale/czech/htdocs/index.html0000644000174700017470000001335012031360371016525 0ustar fexfex F*EX - File EXchange

      F*EX - Frams' Fast File EXchange

      F*EX (Frams' Fast File EXchange) je služba pro odesílání velkých souborů uživatelem A uživateli B.

      Odesilatel pomocí webového formuláře pro nahrání nahraje soubor na F*EX server a ten příjemci automaticky odešle e-mail s oznámením a s URL ke stažení.

      Říkáte si:

      Proč potřebuji další službu pro přenos souborů?!
      Mám e-mail, ftp, ssh a v neposlední řadě i sendfile!

      Já pravím:

      Stále potřebujete F*EX :-)

      Například chcete poslat svému známému video z vaší poslední dovolené (1 GB). Máte následující možnosti (a s tím související problémy):

      • poslat DVD poštou

        Nepřichází v úvahu - žijeme <> let od roku, kdy byl vynalezen Internet! Posílání paměťových médií je pro staříky.

      • použít e-mail

        Většina e-mailových serverů má limit pro přílohu 10 MB a velikost schránky kolem 100 MB a někdy i méně.

      • uucp

        Proč rovnou nezůstat u psaní klínovým písmem na kamenné destičky?

      • ssh

        Vy máte heslo svého známého, nebo se mu chystáte dát to své jen kvůli přenosu souboru?

      • ftp

        • Pomocí jakého ftp serveru?
        • Pomocí jakého účtu, jakého hesla?
        • Vám nevadí posílání nešifrovaného hesla a souborů přes nezabezpečený Internet?
        • Podporuje vaše proxy pasivní režim pro ftp?
        • V případě anonymního ftp:
          • Umožňuje nahrát 1 GB?
          • Umožňuje po nahrání soubor smazat?
          • Kdo další si váš soubor může stáhnout?
          • Kdo další může váš soubor smazat?
          • Svému známému musíte poslat URL, kde si soubor může stáhnout, on vás musí informovat, že si soubor stáhl, vy jej pak musíte smazat.
            Sečteno a podrženo: Otrava.

      • http

        • Žádné výchozí nahrávání a správa uživatelů - musí se naprogramovat
        • Žádné automatické oznamování
        • Žádné automatické mazání
        • Velice málo http serverů umí zpracovat soubory větší než 2 GB

      • sendfile

        • Používáte UNIX a máte nainstalovaný sendfile?
        • Používá příjemce UNIX a má nainstalovaný sendfile?
        • Nemáte vy ani příjemce firewall, který blokuje port 487?

      • komerční služby jako jsou DropLoad, ALLPeers, YouSendIt, etd.

        • Jaký mají limit (většinou méně než 2 GB)?
        • Co bezpečnost a ochrana osobních údajů: Budou vaše soubory skutečně uloženy a v bezpečí?
        • Jsou provozovány na open-source, nebo na uzavřeném proprietálním softwaru?
        • Jsou přístupné se všemi prohlížeči, nebo potřebujete Javu, Active-X, Flash či jiné hnusné zásuvné moduly?
        • Budou existovat více, jak pár měsíců?
          (DropLoad, ALLPeers a drop.io své služby již ukončili)

      Pokud jste byť na jedinou z výše uvedených otázek odpověděli "ne", potom potřebujete F*EX.

      Hlavní funkce F*EX

      • přenos souborů s prakticky neomezenou velikostí
      • příjemci a uživatelé potřebují pouze program pro elektronickou poštu a webový prohlížeč jakéhokoli typu, nemusí instalovat žádný další software
      • ZNOVU ODESLÁNÍ a ZNOVU STAŽENÍ pro pokračování přesně tam, kde došlo k selhání spojení
      • automatické oznamování pro příjemce
      • automatické mazání po stažení
      • automatické mazání po době platnosti (výchozí: 5 dnů)
      • plnohodnotní uživatelé si mohou vytvářet poduživatelé, kteří mohou odesílat pouze jim
      • plnohodnotní uživatelé mohou vytvářet skupiny, obdoba poštovních konferencí s tím rozdílem, že se jedná o soubory
      • bezúdržbovost: ze strany správce nejsou nutné žádné zásahy s vyjímkou vytváření nových F*EX účtů
      • odesílání více příjemcům spotřebuje na serveru pouze místo pro jednoho příjemce
      • F*EX je webová služba pro protokol HTTP a nepotřebuje žádné tunely ve firewallu
      • podporuje také vysílání
      • pro skalní UNIXové uživatele jsou k dispozici programy pro příkazovou řádku fexsend a fexget pro vyhnutí se použití otravných webových prohlížečů
      • protokol i zdrojový kód jsou volně dostupné (Perl Artistic)

      Promluvme si o SEXu

      F*EX má společníka: Stream EXchange (SEX).

      SEX si můžete představit jako bránu mezi UNIXovými síťovými rourami. Ta může být užitečná k odesílání dat uživatelem A uživateli B, kde A a B mezi sebou nemohou navázat přímé spojení, ale oba dva se mohou připojit pomocí HTTP k SEX serveru. Pro snadné začlenění do řady UNIXových nástrojů slouží nástroje pro příkazovou řádku sexsend a sexget.

      Ověřování je stejné jako u F*EX.

      Máte otázky?

      Přečtěte si FAQ

      kontaktujte: fexmaster
      fex-20160919/locale/czech/htdocs/FAQ/0000750000174700017470000000000012770010165015133 5ustar fexfexfex-20160919/locale/czech/htdocs/FAQ/FAQ.html0000644000174700017470000000035512770010165016440 0ustar fexfex F*EX FAQ ## << do "./xx.pl" or print $! >> ## << $_ = `pwd` >> ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      << do "./faq.pl" or print $! >> fex-20160919/locale/czech/lang.html0000644000174700017470000000002411605621330015046 0ustar fexfexčeština fex-20160919/locale/galician/0000775000174700017470000000000012654503773013737 5ustar fexfexfex-20160919/locale/galician/lib/0000775000174700017470000000000012770010165014470 5ustar fexfexfex-20160919/locale/galician/lib/fup.pl0000644000174700017470000000256512624117315015630 0ustar fexfex# config for F*EX CGI fup use utf8; $info_1 = $info_login = <

      F*EX (File EXchange) é un servizo para enviar (grandes, enormes, xigantes, ...) ficheiros.

      O remitente (vostede) carga o ficheiro no servidor F*EX e o receptor obtén automaticamente unha notificación vía correo cun enderezo URL para descargalo.
      Despois de descargalo ou tras $keep_default días o servidor elimina o ficheiro. F*EX non é un arquivo!

      Vexa máis información en preguntas e respostas.


      $ENV{SERVER_ADMIN}
      EOD $info_2 = <

      Despois de remitilo verá unha barra de progreso de carga (se ten o javascript activado e permite as xanelas emerxentes).

      NOTA: A maior parte dos navegadores non poden cargar ficheiros > 2 GB!
      Se o seu ficheiro é maior, ten que usar un cliente F*EX especial.
      Tamén pode necesitalo para retomar cargas interrompidas. O seu navegador non pode facelo.

      Aviso: algúns proxies HTTP como privoxy retardan a barra de progreso de carga!
      Pode querer desactivar a intermediación do proxy $ENV{SERVER_NAME} se se encontra con este problema.

      Usuarios do Firefox: non prema en [ESC] porque isto abortará a carga!

      Vexa máis información na FAQ. EOD fex-20160919/locale/galician/lib/reactivation.txt0000644000174700017470000000005311632223410017710 0ustar fexfexA sa conta F*EX reactivouse correctamente fex-20160919/locale/galician/htdocs/0000775000174700017470000000000012654505200015206 5ustar fexfexfex-20160919/locale/galician/htdocs/index.html0000644000174700017470000001355012031360371017202 0ustar fexfex F*EX - File EXchange

      F*EX - Frams' Fast File EXchange

      F*EX (Frams' Fast File EXchange) un servizo para enviar voluminosos (grandes, enormes, xigantes, ...) ficheiros dun usuario A a un usuario B.

      O remisor carga o ficheiro no servidor F*EX usando un formulario WWW e o receptor automaticamente obtn unha notificacin va correo cun enderezo URL para descargar.

      Vostede dir:

      Por que necesito outro servizo para transferencia de ficheiros?!
      Teo correo, ftp, ssh e mesmo sendfile!

      Ao que respondo:

      Anda as necesita F*EX :-)

      Por exemplo, quere enviar ao seu amigo o video das ltimas vacacins (1 GB).  Ten as seguintes posibilidades (e problemas):

      • o envo dun DVD va correo postal

        Nin o vou considerar - vivimos na poca actual <> despois da invencin da Internet! O envo de soportes multimedia (fsicos) para avoas.

      • o uso do correo

        A maior parte dos servidores de correo teen un lmite de 10 MB por mensaxe e unha cota de uso de disco duns poucos 100 MB por usuario ou mesmo menor.

      • uucp

        E por que non escritura cuneiforme en laxes de pedra?

      • ssh

        Ou ben tes os contrasinais dos teus amigos ou ben ters que darlles a ta - fai falta iso s para transferir un ficheiro?

      • ftp

        • Usando que servidor ftp?
        • Usando que conta, que contrasinal?
        • Non se lle pasar pola cabeza enviar contrasinais sen cifrar e ficheiros na incerta Internet?
        • O seu proxy permite o ftp pasivo?
        • No caso de ftp annimo:
          • Permite cargas de 1 GB?
          • Permite eliminar a carga despois?
          • Quen pode descargar ademais o seu ficheiro?
          • Quen pode eliminar o seu ficheiro?
          • Ten que enviarlle ao seu amigo/a o URL de descarga, el ten que informarte de que o descargou correctamente, despois ten vostede que eliminalo.
            Definitivamente: unha merda pinchada nun pao.

      • http

        • Nin carga predeterminada nin xestin de usuario - debe ser programada
        • Sen autonotificacin
        • Sen autoeliminado
        • Moi poucos servidores http poden xestionar ficheiros superiores a 2 GB

      • sendfile

        • Executas un UNIX e tes o sendfile instalado?
        • O teu receptor executa UNIX e ten o sendfile instalado?
        • Nin ti nin o teu receptor ten unha devasa que bloquee o porto 487?

      • servizos comerciais como DropLoad, ALLPeers, YouSendIt, etc

        • Que lmite teen (maiormente: < 2 GB)?
        • Como andan de seguranza e privacidade: estarn os seus ficheiros gardados e seguros?
        • Estn baseados en software aberto ou en privativo?
        • Estn accesbeis con calquera outro navegador ou cmpre usar java, active-X, flash ou outros complementos endemoados?
        • Funcionarn aln duns poucos meses?
          (DropLoad, ALLPeers e drop.io xa pecharon as sas portas)

      Se respondeu s unha vez "non" s cuestins anteriores, entn necesita F*EX.

      Principais funcionalidades de F*EX

      • transferencia de ficheiro ou  tamao virtualmente ilimitada
      • receptor e remitente s necesitan un programa de correo e un navegador web - de calquer clase, non teen que instalar ningn software
      • REENVIAR and REOBTER para retomar despois de fallos de ligazn ata que se enve o ltimo byte
      • autonotificacin de receptor
      • autoeliminacin despois da descarga
      • autoeliminacin despois dunha data de expiracin (predeterminada: 5 das)
      • os usuarios con plenos dereitos poden crear subusuarios, que poden envar soamente a este usuario pleno
      • os usuarios con plenos dereitos poden crear grupos, en analoxa coas listas de correo, pero para ficheiros
      • sen mantemetno: non se necesita interaccin acompaando a creacin de novas contas con F*EX
      • o envo a mltiples receptores necesita capacidade de almacenamento no servidor s unha vez
      • F*EX un servizo web por HTTP e non necesita tneles nin devasas
      • permite a distribucin de fluxos, tamn
      • para usuarios reais de UNIX, hai aplicativos da shell como fexsend e fexget que evitan o uso impertinente de navegador
      • o protocolo e o cdigo fonte estn dispobeis libremente (Perl Artistic)

      Falemos de SEX

      F*EX ten un compaeiro: Stream EXchange (SEX).

      Pode imaxinar SEX como unha rede de tubaras UNIX cun reenviador (relay) entre elas. Isto pode ser moi prctico para intercambiar datos entre o usuario A e o usuario B al onde A e B non poden establecer unha conexin directa, pero ambos poden conectar va HTTP ao servidor SEX. Para unha integracin perfecta na cadea de ferramentas UNIX, hai ferramentas de shell como sexsend e sexget.

      A autenticacin a mesma que con F*EX.

      Quedanlle preguntas?

      Vexa a FAQ

      contacto: fexmaster
      fex-20160919/locale/galician/htdocs/FAQ.html0000644000174700017470000002610712031354051016502 0ustar fexfex
      Cuestións meta:
      ===============
      
      Q: Por que o nome "F*EX" e non directamente "FEX"?
      
      A: No momento de facerse público xa había unha (antigo) aplicativo chamado "FEX" en
         freshmeat.net.
      
      
      Q: Por que non usar un servizo comercial como
         DropLoad, ALLPeers, YouSendIt, etc?
      
      A: Teñen un límite de 2 GB ou menor.
         A súa seguranza e privacidade son descoñecidas.
         Non se basean en código fonte aberto.
         Non hai clientes de UNIX (CLI) para eles.
         Necesitan java, active-X, flash ou outros endemoñados complementos.
         Descoñécese canto tempo van funcionar - DropLoad e ALLPeers xa pecharon
         as súas portas.
      
      
      Q: Por que un camelo no logo?
      
      A: O logo inspirouse no camelo de Perl, pero baseáse en Steiff, un camelo de peluxe,
         co cal constituímos o noso tándem. O logo foi debuxado
         por Beate
         http://fex.rus.uni-stuttgart.de/Vortrag/tosa.html
      
      
      Q: Onde podo eu obter as fontes de F*EX?
      
      A: http://fex.rus.uni-stuttgart.de/fex.html
      
      
      Q: Que necesito para instalar F*EX?
      
      A: Un servidor UNIX con entrada no DNS e smtp para o correo de saída.
         E debe ser root nese servidor.
      
      
      Q: Que é o DNS e smtp?
      
      A: Non instale F*EX. Está alén das súas posibilidade.
      
      
      Q: Quen e o autor?
      
      A: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
      
      
      Q: Que licenza ten F*EX?
      
      A: De software libre, Perl Artistic, vexa http://fex.rus.uni-stuttgart.de/doc/Licence
      
      
      Q: Hai unha lista de correo de F*EX?
      
      A: https://listserv.uni-stuttgart.de/mailman/listinfo/fex
      
      
      Q: Onde podo obter asistencia comercial para F*EX?
      
      A: Contacto fex@nepustil.net http://www.nepustil.net/
      
      
      Q: Teñeo máis/outras preguntas diferentes!
      
      A: Preguntarlle ao autor <framstag@rus.uni-stuttgart.de>
      
      
      
      Preguntas de usuario:
      =====================
      
      Q: Que é o "auth-ID"?
      
      A: O auth-ID é unha identificación interna que autentica o usuario.
         Será a primeira xerada polo admin ou o proceso de rexistro automático
         e pode despois modificalo vostede, o usuario. Trátase dun contrasinal
         de baixa seguranza.
      
      
      Q: Podo usar un proxy HTTP?
      
      A: Si.
      
      
      Q: Carguei un ficheiro ENORME pero equivoqueime ao escribir o enderezo do destinatario. Agora teño
         un erro de entrega de correo. Debo volver cargar ese ENORME ficheiro?
      
      A: Non, non fai falta. Pode redirixir o ficheiro con
         http://$HTTP_HOST$/rup
      
      
      Q: Cargue un ficheiro ENORME pero esquecín outro destinatario.
         Debo volver cargar ese ENORME ficheiro?
      
      A: Non, non é necesario. Pode reenviar copia do ficheiro con
         http://$HTTP_HOST$/foc
      
      
      Q: Non podo cargar ficheiros > 2 GB co meu navegador web!?
      
      A: Todos os navegadores teñen defectos na implementación dos
         seus formularios HTML. O límite máis frecuente é de 2 GB, ás veces 4 GB.
      
         Debe usar un cliente especial de F*EX para cargar ficheiros > 2 GB, vexa
         http://$HTTP_HOST$/tools.html
      
      
      Q: A miña descarga abortouse antes de rematar. Podo retomar esa descarga?
      
      A: F*EX permite retomar e descargar, pero o seu cliente tamén debe permitir
         esta funcionalidade. Firefox por exemplo carece desta funcionalidade HTTP, necesitará
         outro cliente como Opera, wget ou fexget.
      
      
      Q: A miña carga foi abortada antes de rematar. Podo retomar esa carga?
      
      A: F*EX permite retomar a carga, pero o seu cliente debe permitir vbnm, 1tupports resuming at upload, but your client also has to support it.
         No web browser has this feature, you need a special F*EX client like
         fexsend, schwuppdiwupp or F*IX.
         See http://$HTTP_HOST$/tools.html
      
      
      Q: O meu navegador non pode iniciar o cliente java F*IX, que indica:
         "non se atopou un entorno de execución java, non se pode iniciar F*IX o miniaplicativo de carga"
      
      A: Non se localiza un complemento java do navegador. En Debian e Ubuntu pode
         instalalo con: "sudo aptitude install sun-java6-plugin"
      
      
      Q: Cando premo[ESC] no Firefox a carga cancélase. Por que?
      
      A: Esta é unha funcionalidade interna do Firefox: ESC termina a operación actual.
         Solución simple: non prema ESC no Firefox.
         Solución complexa: pídalles aos desenvolvedores do Firefox que engadan un atallo de teclado.
      
      
      Q: O envío como un usuario F*EX é doado, pero como recibir ficheiros doutros,
         de fóra?
      
      A: Rexístreos como subusuarios ou cree un grupo F*EX
         con http://$HTTP_HOST$/fuc
      
      
      Q: Ás veces podo descargar un ficheiro máis dunha vez, especialamente cando
         o repito rapidamente. Está a funcionalidade de auteliminación defectuosa?
      
      A: O servidor F*EX ten un períod de gracia de 1 minuto despois da primeira
         descarga correcta no cal o ficheiro aínda está dispoñíbel. Isto é necesario
         porque algúns "xestores de descargas" estúpidos solicitan o ficheiro
         varias veces á vez. Caso contrario poderían indicar un erro ao usuario.
      
      A: O seu fexmaster ten un conxunto AUTODELETE=DELAY como predeterminado, o que significa que
         o proceso de autolimpeza realízase unha vez ao día.
      
      A: Os "Power users" ou usuarios con permisos (usa a forza, Luke!) poden establecer unha marca "non eliminar ata
         despois da descarga".
      
      
      Q: O período de reserva predeterminado é demasiado curto para min, cómpreme máis. Como podo estabelecelo?
      
      A: Use fexsend, pídallo ao seu fexmaster ou lea o código fonte :-)
      
      
      Q: Non podo descargar ficheiros con Internet Explorer, dime "Non se pode
         abrir o sitio da Internet". Que debería facer?
      
      A: Use Firefox ou calquera outro navegador compatíbel con Internet, xa que Internet
         Explorer non o é. Este é un de tanto defectos do Internet Explorer.
      
      
      
      
      Preguntas de administrador:
      ===========================
      
      Q: Non podo instalar un servidor web como fexsrv, porque non teño permisos de root
         Hai algunha versión en puro CGI de F*EX que funcione cun servidor web Apache?
      
      A: F*EX está intimamente unido a fexsrv por varias razóns (rendemento, límite de
         tamaño de ficheiro, concepto de sesiónt, etc.) e non se pode executar como CGI
         con Apache.
         Pero pódelle botar un ollo a
         http://gpl.univ-avignon.fr/filez/
         http://freshmeat.net/projects/eventh/
         http://www.schaarwaechter.de/sp/projekte/dateiaustausch.html (só en alemán!)
         que implementa un intercambio de ficheiros como puros CGI, pero cun tamaño límite de 2 GB por ficheiro.
      
      
      Q: F*EX non funciona! Non podo conectarme co meu navegador web!
      
      A: Comprobe o seu enrutamento, filtros ip e configuración de devasa.
         Tamén comprobe se o seu xinetd está ligado cun tcp-wrapper e configúreo
         correctamente (hosts.allow).
         F*EX necesita o porto 80/tcp (HTTP) e o porto opcional 443/tcp (HTTPS).
      
      
      Q: F*EX é complicado de máis! Necesito algo máis simplificado.
      
      A: Probe http://www.home.unix-ag.org/simon/woof.html
      
      
      Q: Como podo integrar F*EX no xestor de usuarios do meu sitio?
      
      A: F*EX ten varios módulos de autenticación:
         local, RADIUS, LDAP, mailman e POP
         Para os 4 últimos, contacte por favor co autor framstag@rus.uni-stuttgart.de
      
      
      Q: Que que todos os meus usuarios locais poidan usar F*EX automatimente. Como?
      
      A: Permítaos rexistrarse a si mesmos con http://yourfexserver/fur
         Ten que editar lib/fex.ph e establecer (exemplo):
         @local_hosts = qw(127.0.0.1 10.10.100.0-10.10.255.255);
         @local_domains = qw(flupp.org ulm.sub.net);
         (Por suposto, ten que engadir os seus servidores/redes locais reais!)
      
      
      Q: Necesito máis seguranza! Como podo activar HTTPS?
      
      A: Lea doc/SSL e busque "fop_auth" en doc/concept
      
      
      Q: Necesito un aspecto corporativo. Como podo configurar F*EX neste sentido?
      
      A: Vexa a variábel @H1_extra en fex.ph e pode engadir o código HTML a
         htdocs/header.html
      
      A: Vexa htdocs/fup_template.html, modifíqueo ás súas necesidades e úseo como a súa
         páxina de inicio.
      
      
      Q: F*EX é demasiado complicado para os meus pobres usuarios. Necesito un formulario de
         carga simmplificado.
      
      A: Vexa htdocs/fup_template.html
      
      
      Q: Quero que os correos Ccc a (ao usuario admin) se envíen a outro enderezo.
      
      A: Use procmail ou escriba OTHERADDRESS en /home/fex/.forward
      
      
      Q: Podo obter unha versión localizada no meu idioma?
      
      A: Sempre coa súa axuda, si. Contacte co autor framstag@rus.uni-stuttgart.de
      
      
      Preguntas en miscelánea:
      ========================
      
      Q: F*EX é fantástico! Podo unirme ao equipo de desenvolvemento? Que hai que facer?
      
      A: Contacte co autor framstag@rus.uni-stuttgart.de
         As funcionalidades buscadas son:
      
           - un complemento F*EX para o Thunderbird ou o Outlook
           - máis (outras) idiomas dispoñíbeis
      
      
      fex-20160919/locale/galician/htdocs/FAQ/0000750000174700017470000000000012770010165015606 5ustar fexfexfex-20160919/locale/galician/htdocs/FAQ/FAQ.html0000644000174700017470000000035512770010165017113 0ustar fexfex F*EX FAQ ## << do "./xx.pl" or print $! >> ## << $_ = `pwd` >> ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      << do "./faq.pl" or print $! >> fex-20160919/locale/galician/lang.html0000644000174700017470000000000711605620540015524 0ustar fexfexgalego fex-20160919/locale/german/0000755000174700017470000000000012654503773013437 5ustar fexfexfex-20160919/locale/german/lib/0000755000174700017470000000000012770010166014171 5ustar fexfexfex-20160919/locale/german/lib/fup.pl0000644000174700017470000000332312142673550015326 0ustar fexfex# lokale Konfiguration fuer F*EX CGI fup $info_1 = $info_login = <

      F*EX (File EXchange) ist ein Dienst um große (sehr große, riesige, gigantische, ...) Dateien zu senden.

      Der Absender (Sie) lädt eine Datei auf den F*EX Server hoch und der Empfänger bekommt automatisch eine Benachrichtigungs-E-Mail mit der Download-URL.
      Nach dem Download oder nach $keep_default Tagen löscht der Server die Datei.
      F*EX ist kein Archiv!

      Um es zu nutzen, geben Sie Ihre Empfänger E-Mail Adresse(n) in die Felder oben ein.

      Noch immer verwirrt?
      Testen Sie F*EX, indem Sie eine Datei an sich selbst senden (Absender = Empfänger = Ihre E-Mail Adresse).

      Siehe auch Fragen & Antworten.


      $ENV{SERVER_ADMIN}
      EOD $info_2 = <

      Nach dem Abschicken sehen Sie einen Upload Fortschrittsbalken (wenn Sie Javascript aktiviert haben und Popups erlauben).

      Bemerkung: Viele Webbrowser können keine Dateien hochladen, die größer als 2 GB sind!
      Wenn Ihre Datei größer ist, müssen Sie einen speziellen F*EX client nutzen.
      Sie brauchen ihn außerdem, wenn Sie abgebrochene Uploads wiederaufnehmen wollen. Ihr Webbrowser ist dazu nicht in der Lage.

      Wenn Sie mehr als eine Datei verschicken wollen, dann verpacken Sie sie vorher in ein zip oder tar Archiv, z.B. mit 7-Zip.

      Siehe auch FAQ.


      $ENV{SERVER_ADMIN}
      EOD fex-20160919/locale/german/lib/reactivation.txt0000644000174700017470000000006011626030514017414 0ustar fexfexIhr F*EX Account wurde erfolgreich reaktiviert. fex-20160919/locale/german/htdocs/0000755000174700017470000000000012654505200014706 5ustar fexfexfex-20160919/locale/german/htdocs/index.html0000644000174700017470000001344512114162360016707 0ustar fexfex F*EX - File EXchange

      F*EX - Frams' Fast File EXchange

      F*EX (Frams' Fast File EXchange) ist ein Dienst, um große (sehr große, riesige, gigantische, ...) Dateien von User A zu User B zu senden.

      Der Absender lädt die Datei über ein WWW upload Formular auf den F*EX Server hoch und der Empfänger bekommt automatisch eine Benachrichtigungs-E-Mail mit der Download-URL.

      Sie fragen vielleicht:

      Warum brauche ich noch einen Service für Dateitranfer?!
      Ich habe E-Mail, FTP, SSH und sogar sendfile!

      Ich sage:

      Sie brauchen F*EX trotzdem :-)

      Sie möchten zum Beispiel einem Freund das letztes Urlaubsvideo senden (1 GB). Sie haben dazu folgende Möglichkeiten (und Probleme):

      • eine DVD per Briefpost verschicken

        Steht außer Frage - wir leben im Jahr <> nach der Erfindung des Internet! Versand von (Hardware-)Medien ist etwas für Opas.

      • E-Mail benutzen

        Die meisten E-Mail Server haben ein Limit von 10 MB pro E-Mail und ein Speicherkontingent von wenigen 100 MB pro User oder sogar weniger.

      • UUCP

        Warum nicht gleich Keilschrift-Zeichen in Tonplatten eindrücken?

      • SSH

        Sie haben das Passwort Ihres Freundes oder sind gewillt, ihm Ihres zu geben - nur für einen Datei-Transfer?

      • FTP

        • Welchen FTP Server benutzen?
        • Welchen Account benutzen, welches Passwort?
        • Stört es Sie unverschlüsselte Passwörter über das unsichere Internet zu übertragen?
        • Unterstützt Ihr Proxy passives FTP?
        • Im Fall von anonymen FTP:
          • Erlaubt es 1 GB Uploads?
          • Kann man den Upload nach dem Transfer wieder löschen?
          • Wer kann Ihre Datei noch downloaden?
          • Wer noch kann Ihre Datei löschen?
          • Sie müssen Ihrem Freund die Download-URL zukommen lassen und er muss Sie über den erfolgreichen Download informieren, danach müssen Sie die Datei löschen.
            Alles in Allem: eine nervige Sache.

      • HTTP

        • Es gibt keine standardmäßige Upload- und User-Verwaltung (muss erst programmiert werden)
        • Keine Auto-Benachrichtigung
        • Kein automatisches Löschen
        • Sehr wenige HTTP Server können mit Dateien größer 2 GB umgehen

      • sendfile

        • Sie benutzen UNIX und haben sendfile installiert?
        • Ihr Empfänger benutzt UNIX und hat sendfile installiert?
        • Weder Ihr Empfänger noch Sie selbst haben eine Firewall die Port 487 blockiert?

      • Kommerzielle Dienste wie DropLoad, ALLPeers, YouSendIt, etc

        • Welche Beschränkungen haben sie? (meist: < 2 GB)?
        • Was ist mit Sicherheit und Privatsphäre: werden Ihre Dateien sicher und geschützt sein?
        • Basieren sie auf Open Source- oder proprietärer Software?
        • Sind sie mit jedem Browser benutzbar oder braucht man Java, Active-X, Flash oder andere üble Plugins?
        • Werden sie länger als ein paar Monate existieren?
          (DropLoad und ALLPeers haben ihren Betrieb schon eingestellt)

      Wenn Sie auch nur eine der Fragen von oben mit "Nein" beantwortet haben, dann brauchen Sie F*EX.

      Hauptmerkmale von F*EX

      • Datei-Transfer mit praktisch unbegrenzter Dateigröße
      • Empfänger und Absender brauchen lediglich ein E-Mail Programm und einen Web-Browser - es muss keine zusätzliche Software installiert werden
      • RESEND und REGET für Wiederaufnahme bei Link Fehlern beim letzten gesendeten Byte
      • Auto-Benachrichtigung der Empfänger
      • automatisches Löschen nach Download
      • automatisches Löschen nach Ablaufdatum (Standard: 5 Tage)
      • Full-User können Sub-User erstellen, die dann nur an den Full-User senden dürfen
      • Full-User können Gruppen erstellen, eine Analogie zu Mailinglisten, aber für Dateien
      • wartungsfrei: bis auf die Erstellung neuer F*EX Accounts ist keine Interaktion eines Admins erforderlich
      • Für das Senden an mehrere Empfänger wird auf dem Server nur einmal Speicherplatz verbraucht
      • F*EX ist ein HTTP-Web-Dienst und benötigt keine Firewall-Tunnel
      • Unterstützung für Streams
      • für UNIX Benutzer gibt es die Shell-Programme fexsend und fexget, um den lästigen Gebrauch von Webbrowsern zu umgehen
      • Protokoll und Quellcode sind frei verfügbar (Perl Artistic)

      Lassen Sie uns über SEX sprechen

      F*EX hat einen Begleiter: Stream EXchange (SEX).

      Man kann sich SEX als netzwerkweite UNIX Pipes mit einem Relay dazwischen vorstellen. Das kann hilfreich sein, wenn man Daten von User A zu User B leiten will, ohne dass A und B eine direkte Verbindung zueinander aufbauen können, aber beide sich über HTTP zum SEX Server verbinden können. Für eine nahtlose Integration in die UNIX Programm Reihe, gibt es die Shell-Programme sexsend und sexget.

      Die Authentifizierung ist dieselbe wie bei F*EX.

      Noch Fragen?

      Siehe FAQ (Fragen und Antworten)

      Kontakt: fexmaster
      fex-20160919/locale/german/htdocs/FAQ.html0000644000174700017470000002316412435375235016223 0ustar fexfex

      Dieses Dokument ist veraltet. Bitte benutzen Sie die englische FAQ.

      Allgemeine Fragen:
      ==================
      
      F: Warum der Name "F*EX" und nicht einfach "FEX"?
      
      A: Zur Zeit der Veröffentlichung existierte bereits ein (älteres) Programm 
         namens "FEX" auf freshmeat.net.
         
      
      F: Warum nicht einen kommerziellen Dienst benutzen wie
         DropLoad, ALLPeers, YouSendIt, etc?
         
      A: Solche Dienste haben ein Limit von 2 GB oder sogar weniger.
         Es ist unklar wie es bei ihnen mit Sicherheit und Datenschutz aussieht.
         Sie basieren nicht auf Open Source.
         Es gibt keine UNIX (CLI) Clients für sie.
         Sie brauchen Java, Active-X, Flash oder andere bösartige Plugins.
         Es ist unklar wie lange sie noch existieren werden - DropLoad und ALLPeers
         haben bereits aufgehört zu existieren.
      
      
      F: Warum ein Kamel als Logo?
      
      A: Das Logo war inspiriert durch das Perl Kamel, zu Grunde liegt aber ein 
         Plüschkamel von Steiff welches auf unserem Renn-Tandem mitfährt. 
         Das Logo wurde von meiner Stokerin Beate gezeichnet, siehe
         http://fex.rus.uni-stuttgart.de/Vortrag/tosa.html
      
      
      F: Wo kann ich die F*EX Sourcen bekommen?
      
      A: http://fex.rus.uni-stuttgart.de/fex.html
      
      
      F: Was braucht man um F*EX installieren zu können?
      
      A: Ein UNIX Server mit DNS Eintrag und smtp für ausgehende E-Mail.
         Und Sie müssen root auf diesem Server sein.
         
      
      F: Was ist DNS und smtp?
      
      A: Installieren Sie kein F*EX. Es ist jenseits Ihres Horizonts.
      
      
      F: Wer ist der Autor?
      
      A: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
      
      
      F: Unter welcher Lizenz läuft F*EX?
      
      A: Perl Artistic Freie Software, siehe http://fex.rus.uni-stuttgart.de/doc/Licence
      
      
      F: Gibt es eine F*EX Mailing Liste?
      
      A: https://listserv.uni-stuttgart.de/mailman/listinfo/fex
      
      
      F: Wo kann ich einen kommerziellen Support für F*EX bekommen?
      
      A: Nehmen Sie Kontakt auf mit fex@nepustil.net http://www.nepustil.net/
      
      
      F: Ich habe noch weitere Fragen bezüglich dieses Dokuments!
      
      A: Fragen Sie den Autor <framstag@rus.uni-stuttgart.de>
      
      
      Benutzerfragen:
      ===============
      
      Q: Was ist die "auth-ID"?
      
      A: Mit Hilfe der auth-ID werden Sie auf dem Server als ein authorisierter 
         Benutzer identifiziert. Die auth-ID wird zuerst vom Administrator oder 
         durch automatische Registrierung vergeben und kann später durch Sie 
         geändert werden. Bitte beachten Sie dass man hier keine wertvollen
         Passwörter verwenden sollte weil diese unverschlüsselt auf dem 
         Server liegen.
      
      
      F: Kann ich einen HTTP-Proxy verwenden?
      
      A: Ja
      
      
      F: Ich habe eine RIESIGE Datei an eine falsche Adresse versendet. Jetzt 
         bekomme ich eine Fehler-Meldung vom System. Muß ich die RIESIGE Datei
         noch mal hochhladen?
      
      A: Nein, das ist nicht nötig. Sie können die Datei einfach weiterleiten 
         mit Hilfe von http://$HTTP_HOST$/rup
      
      
      F: Ich habe eine RIESIGE Datei versendet doch leider habe ich noch einen 
         Empfänger vergessen. Muß ich die RIESIGE Datei noch mal hochladen?
      
      A: Nein, das ist nicht nötig. Sie können die Datei einfach kopieren und
         weiterleiten mit Hilfe von http://$HTTP_HOST$/foc
      
      
      F: Warum kann ich keine Dateien größer als 2 GB mittels Web-Browser 
         hochladen?
      
      A: Alle Web-Browser die mir bekannt sind haben Fehler in ihrer HTML-FORM
         Implementierung. Dadurch ergibt sich der Limit von 2 GB, manchmal 4 GB.
      
         Sie müssen einen speziellen F*EX Client benutzen um Dateien größer 
         als 2 GB hochzuladen, siehe http://$HTTP_HOST$/tools.html
      
      
      F: Mein Download brach frühzeitig ab. Kann ich ihn wieder aufnehmen?
      
      A: F*EX unterstützt Download-Wiederaufnahme, aber Ihr Client muss es ebenso 
         unterstützen. Firefox zB fehlt diese HTTP Eigenschaft, daher benötigen 
         Sie einen anderen Client wie opera, wget oder fexget.
      
      
      F: Mein Upload brach frühzeitig ab. Kann ich ihn wieder aufnehmen?
      
      A: F*EX unterstützt Upload-Wiederaufnahme, aber Ihr Client muss es ebenso 
         unterstützen. Kein Web-Browser hat diese Unterstützung, Sie 
         benötigen dfür einen speziellen F*EX Client wie
         fexsend, schwuppdiwupp oder F*IX.
         Siehe http://$HTTP_HOST$/tools.html
      
      
      F: Wenn ich die Taste [ESC] in Firefox drücke, dann wird der Upload 
         abgebrochen. Warum?
      
      A: Das ist die eingebaute Funktion von Firefox: ESC unterbricht die 
         laufende Operation. 
         Einfache Lösung des Problems: 
         [ESC] sollte man nicht drücken.
         Komplizierte Lösung: 
         bitten Sie die Firefox-Entwickler, eine Tastatur-Konfiguration hinzuzufügen
      
      
      F: Daten mit F*EX zu versenden ist einfach, wie kann ich aber Daten
         von anderen (von der Aussenwelt) empfangen?
      
      A: Registrieren Sie sie als Ihre Subuser oder legen Sie eine F*EX Gruppe an.
         
      
      F: Es kommt manchmal vor dass ich eine Datei mehrmals herunterladen kann, 
         insbesondere wenn ich die Downloads schnell wiederhole. Ist etwa das 
         automatische Löschen fehlerhaft?
      
      A: Der F*EX-Server wartet 1 Minute lang nach dem ersten erfolgreichen Download.
         In dieser Zeit kann man die Datei nochmal herunterladen. Diese Wartezeit 
         ist notwendig weil manche idiotische "Download Manager" die Datei gleich 
         mehrmals anfordern. Ohne die Wartezeit würden sie dem Benutzer einen
         Fehler melden.
      
      A: Ihr Fexmaster hat die Variable AUTODELETE auf DELAY gesetzt. Das hat
         zur Folge dass das automatische Löschen nur einmal täglich stattfindet.
      
      A: Power-Benutzer (sehen Sie die Software-Quelltexte!) können den Flag
         "nach dem Download nicht löschen" setzen.
      
      
      F: Die Standard Aufbewahrungszeit ist mir zur kurz. Wie kann ich diesen Wert 
         erhöhen?
      
      A: Benutzen Sie fexsend, fragen Sie Ihren Fexmaster oder lesen Sie die 
         Quelltexte :-)
      
      
      F: Ich kann Dateien mit dem Internet Explorer nicht herunterladen, es
         meldet mir "Die Internet-Seite ist nicht verfügbar". Was soll ich tun?
      
      A: Benutzen Sie Firefox oder anderen Internet-kompatiblen Web-Browser, was der 
         Internet Explorer eben nicht ist. Das ist nur einer seiner vielen Bugs.
      
      
      Administrator Fragen:
      =====================
      
      F: Ich kann keinen Web-Server wie fexsrv aufsetzen, mir fehlen dazu die
         Rechte. Gibt es vielleicht eine reine CGI-Version von F*EX die
         unter dem Apache Web-Server läuft?
      
      A: fexsrv ist ein fester Bestandteil von F*EX, dazu gibt es viele Gründe 
         (Leistung, maximale Dateigröße, Session Konzept usw). So kann F*EX nicht 
         als CGI unter Apache laufen, Sie könnten sich aber das hier anschauen:
         
         http://gpl.univ-avignon.fr/filez/
         http://freshmeat.net/projects/eventh/
         http://www.schaarwaechter.de/sp/projekte/dateiaustausch.html
         
         Das sind einfache CGI-Implementierungen von Daten-Übertragungssystemen,
         jedoch begrenzt auf 2 GB.
         
      
      F: F*EX funktioniert überhaupt nicht! Es kommt keine Verbindung zum Server mit 
         meinem Web-Browser zustande!
      
      A: Prüfen Sie Ihr Routing, IP-Filter und die Firewall-Einstellungen.
         Prüfen Sie auch ob Ihr xinetd mit dem TCP-Wrapper verlinkt ist und
         konfigurieren Sie es richtig (hosts.allow).
         F*EX braucht den Port 80/tcp (HTTP) und optional den Port 443/tcp
      
      
      F: F*EX ist mir zu kompliziert! Ich brauche was einfacheres!
      
      A: Probieren Sie http://www.home.unix-ag.org/simon/woof.html
      
      F: Wie kann ich F*EX in das bestehende Benutzer-Management in meinem Netzwerk 
         integrieren?
      
      A: F*EX hat verschiedene Authentifizierungs-Module:
         lokal, RADIUS, LDAP, mailman und POP
         Bezüglich der letzten 4 kontaktieren Sie bitte den Autor.
      
      
      F: Ich möchte dass alle meine lokalen Benutzer automatisch F*EX benutzen 
         können. Wie geht das?
      
      A: Lassen Sie sie sich selbst registrieren.
         Dazu müssen Sie lib/fex.ph editieren (Beispiel):
         
         @local_hosts = qw(127.0.0.1 10.10.100.0-10.10.255.255);
         @local_domains = qw(flupp.org ulm.sub.net);
      
         Natürlich müssen Sie Ihre echten Hosts/Networks eigeben!
      
      
      F: Ich brauche mehr Sicherheit! Wie kann ich HTTPS benutzen?
      
      A: Lesen Sie doc/SSL und schauen Sie auch nach "fop_auth" in doc/concept 
      
      
      F: Die F*EX-Startseite sollte an unsere Firmen-Seiten angepaßt werden. 
         Wie kann ich F*EX entsprechend konfigurieren?
      
      A: Siehe Variable @H1_extra in fex.ph, ausserdem können Sie htdocs/header.html
         hinzufügen.
      
      A: Nehmen Sie fup_template.html, modifizieren Sie die Vorlage nach Ihren 
         Wünschen und nutzen Sie diese als Ihre Startseite.
      
      
      Sonstige Fragen:
      ================
      
      F: F*EX ist großartig! Wie kann ich mich dem Entwicklungs-Team anschließen? 
         Was muß noch gemacht werden?
      
      A: Kontaktieren Sie den Autor wegen:
      
         - ein F*EX plugin für Outlook
         
         - weiteren Übersetzungen in andere Sprachen - Latein wäre toll! :-) 
      
      fex-20160919/locale/german/htdocs/FAQ/0000750000174700017470000000000012770010166015311 5ustar fexfexfex-20160919/locale/german/htdocs/FAQ/FAQ.html0000644000174700017470000000035512770010166016616 0ustar fexfex F*EX FAQ ## << do "./xx.pl" or print $! >> ## << $_ = `pwd` >> ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      << do "./faq.pl" or print $! >> fex-20160919/locale/german/lang.html0000644000174700017470000000001011605620225015220 0ustar fexfexdeutsch fex-20160919/locale/italian/0000755000174700017470000000000012654503773013607 5ustar fexfexfex-20160919/locale/italian/lib/0000755000174700017470000000000012770010166014341 5ustar fexfexfex-20160919/locale/italian/lib/fup.pl0000644000174700017470000000262412624117447015504 0ustar fexfex# configurazione per F*EX CGI fup use utf8; $info_1 = $info_login = <

      F*EX (File EXchange) e' un servizio per spedire grossi (grandi, enormi, giganti, ...) file.

      Il mittente (tu) carica il file nel server F*EX ed automaticamente il destinatario si vede recapitare una e-mail di notifica con il link per effettuare il download.
      Dopo il download o dopo $keep_default giorni, il server cancella il file. F*EX non e' un sistema di archiviazione!

      Guardate anche domande e risposte (Q&A).


      $ENV{SERVER_ADMIN}
      EOD $info_2 = <

      Dopo il caricamento del file vedrete una barra di avanzamento (bisogna avere javascript abilitato ed i popup abilitati).

      NOTA: Parte dei browser-WEB non possono caricare file > 2 GB!
      Se il tuo file e' piu' grande devi usare un client F*EX particolare.
      Hai bisogno anche di un tool per recuperare i download interrotti. Il tuo browser-WEB non puo' farlo.

      Attenzione: alcuni proxy HTTP come privoxy ritardano lo stattttto della barra di avanzamento!
      Potresti voler disabilitare il proxying $ENV{SERVER_NAME} se ti capita di incorrere in questo problema.

      Utenti Firefox: non digitare [ESC] perche' questo interrompera' il caricamento!

      Vedere anche FAQ. EOD fex-20160919/locale/italian/lib/reactivation.txt0000644000174700017470000000006511627130362017574 0ustar fexfexIl tuo account F*EX stato riattivato con successo. fex-20160919/locale/italian/htdocs/0000755000174700017470000000000012654505200015056 5ustar fexfexfex-20160919/locale/italian/htdocs/index.html0000644000174700017470000001342012031360371017050 0ustar fexfex F*EX - File EXchange

      F*EX - Frams' Fast File EXchange

      F*EX (Frams' Fast File EXchange) e' un servizio per spedire grossi (grandi, enormi, giganti, ...) file da un utente A ad un utente B.

      Il mittente carica il file nel server F*EX usando una form WWW di carico mentre al destinatario viene recapitata una e-mail di notifica con un link per effettuare il download.

      Direte:

      Per quale motivo ho bisogno di un altro servizio per effettuare il trasferimento dei files?!
      Per questo ho gia' la posta elettronica(e-mail), l'ftp, l'ssh ed anche il comando sendfile!

      Io dico:

      Nonostante tutto hai bisogno di F*EX :-)

      Supponiamo, per esempio, che tu voglia spedire ai tuoi amici il video delle tue ultime vacanze (1 GB). Hai le seguenti possibilita' (e problemi):

      • spedire un DVD con il servizio postale

        Fuori discussione - viviamo nell'anno <> dopo l'invenzione di Internet! Spedire supporti hardware e' da trogloditi.

      • usare la posta elettronica (e-mail)

        Gran parte dei server di posta elettronica hanno un limite di 10 MB per ognuna delle e-mail e la quota totale e' di meno di 100 MB per utente.

      • uucp

        Perche' non usare la scrittura cuneiforme su una lastra di pietra?

      • ssh

        Avete la password dei vostri amici oppure siete disposti a dargli la vostra? - solo per trasferire un file?

      • ftp

        • Quale server ftp usare?
        • Quale utente usare, quale password?
        • Non vi dispiace mandare password e files non crittografati su Internet (insicura per definizione)?
        • Il vostro proxy supporta l'ftp passivo?
        • In caso di ftp anonimo:
          • Permette di caricare file da 1 GB?
          • Permette di cancellare il file caricato subito dopo?
          • Chi altri puo' fare il download del vostro file?
          • Chi altri puo' cancellare il vostro file?
          • Dovete mandare ai vostri amici il link per lo scarico, loro devono informarvi di avere effettuato il download del file e voi dovete cancellarlo subito dopo.
            In poche parole: una rottura di scatole.

      • http

        • Non esiste un programma di default - deve essere costruito.
        • Non esiste l'auto-notifica.
        • Non esiste l'auto-cancellazione.
        • Pochissimi server HTTP possono trattare file piu' grandi di 2 GB.

      • sendfile

        • Avete UNIX ed avete sendfile installato?
        • Il vostro destinatario ha UNIX ed ha sendfile installato?
        • Sicuri che ne' voi, ne' il vostro destinatario avete un firewall che blocca la porta 487?

      • servizi commerciali come DropLoad, ALLPeers, YouSendIt, eccetera

        • Quale limite hanno (gran parte: < 2 GB)?
        • Cosa dire di sicurezza e privacy: i vostri file saranno salvi e sicuri?
        • Sono basati su servizi open source o su proprietari?
        • Sono accessibili con qualsiasi browser oppure hanno bisogno di java, active-X, flash o qualche altro plug-in?
        • Sopravviveranno per piu' di qualche mese?
          (Per esempio servizi quali DropLoad, ALLPeers e drop.io hanno gia' terminato la loro attivita')

      Se avete risposto "no" ad almeno ad una delle domande, avete bisogno di F*EX.

      Principali caratteristiche di F*EX

      • trasferimento file di dimensioni virtualmente illimitate.
      • il destinatario ed il mittente hanno bisogno solo di un programma di posta elettronica e di un browser WEB di qualsiasi tipo: non devono installare nulla.
      • funzioni RESEND e REGET per riprendere l'esecuzione dopo un blocco della connessione all'ultimo byte.
      • auto-notifica del destinatario.
      • auto-cancellazione dopo il download.
      • auto-cancellazione dopo un periodo di 5 giorni (per default).
      • gli utenti "full" possono creare "sottoutenti" o utenti "limitati" i quali possono spedire solo a questo server.
      • gli utenti "full" possono creare gruppi in analogia a quanto succede per le liste di distribuzione, solo che viene fatto per i file.
      • manutenzione semplice: non e' necessario l'intervento dell'amministratore per la creazione di nuovi utenti F*EX.
      • l'invio di file a piu' destinatari occupa nel server solo lo spazio di una sola spedizione.
      • F*EX e' un web-service di tipo HTTP e non ha bisogno di "tunnels" nel firewall.
      • sono supportati anche i flussi (stream).
      • per gli utenti che conoscono UNIX, ci sono gli script-shell fexsend e fexget che evitano l'uso di un browser-WEB.
      • i protocolli ed il codice sorgente sono liberamente disponibili (Perl Artistic).

      Parliamo di SEX

      F*EX ha un compagno: Stream EXchange (SEX).

      Potete immaginare che SEX sia una specie di lunga pipe UNIX con un relay in mezzo. Questo servizio puo' essere utilizzato per il travaso di dati da un utente A ad un utente B quando A e B non possono stabilire una connessione diretta ma entrambi possono stabilire una connessione HTTP con il server SEX. Per una completa integrazione con i tool di concatenazione dei comandi di UNIX, ci sono gli script-shell sexsend and sexget.

      L'autenticazione e' la stessa utilizzata da F*EX.

      Altre domande?

      Vedi le FAQ

      contattate: fexmaster
      fex-20160919/locale/italian/htdocs/FAQ.html0000644000174700017470000002570712437323352016373 0ustar fexfex

      Questo documento non è aggiornato. Si prega di utilizzare il inglese FAQ.

      Domande Generiche:
      ==================
      
      Q: Perche' il nome e' "F*EX" invece del piu' corto "FEX"?
      
      A: Al momento della pubblicazione c'era gia' un (vecchio) programma
         nominato "FEX" su freashmeat.net
      
      
      Q: Perche' non usare un servizio commerciale come
         DropLoad, ALLPeers, YouSendIt, ecc. ?
      
      A: Tutti hanno un limite di 2 GB o meno.
         I loro livelli di sicurezza e privacy sono sconosciuti.
         Non sono servizi basati su software open-source.
         Non ci sono client UNIX (a linea di comando) per loro.
         Hanno bisogno di java, Active-X, Flash o altri plug-in.
         Non si sa quanto tempo sopravviveranno - DropLoad e ALLPeers hanno
         gia' concluso la loro attivita'.
      
      
      Q: Perche' c'e' un cammello nel logo?
      
      A: Il logo e' stato ispirato al cammello del Perl, ma e' basato sul
         cammello di peluche della Steiff che ci portiamo insieme con noi
         nelle nostre corse con il tandem.
         Il logo e' stato disegnato dal mio "fuochista" Beate
         http://fex.rus.uni-stuttgart.de/Vortrag/tosa.html
      
      
      Q: Dovo posso prendere i sorgenti di F*EX ?
      
      A: http://fex.rus.uni-stuttgart.de/fex.html
      
      
      Q: Dove posso installare F*EX ?
      
      A: In un host UNIX con una entry DNS ed un SMTP per la spedizione
         delle e-mail. Su questo server bisogna avere i privilegi di root.
      
      
      Q: Cosa sono DNS e SMTP?
      
      A: Lascia perdere F*EX. E' al di la' delle tue possibilita'.
      
      
      Q: Chi e' l'autore ?
      
      A: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
      
      
      Q: Che tipo di licenza ha F*EX ?
      
      A: Perl Artistic free software, vedete http://fex.rus.uni-stuttgart.de/doc/Licence
      
      
      Q: C'e' una mailing list per F*EX ?
      
      A: https://listserv.uni-stuttgart.de/mailman/listinfo/fex
      
      
      Q: Dove posso trovare un servizio commerciale per F*EX ?
      
      A: Contattate fex@nepustil.net http://www.nepustil.net/
      
      
      Q: Ho altre domande che non trovo in questo documento.
      
      A: Chiedete all'autore <framstag@rus.uni-stuttgart.de>
      
      
      
      Domande Utente:
      ===============
      
      Q: Cos'e' il campo "auth-ID" ?
      
      A: Il campo auth-ID e' un identificativo interno che individua l'utente;
         e' lo username.
         E' creato la prima volta o dall'amministratore o attraverso il processo
         di registrazione automatico e puo' essere successivamente modificato
         da te (che sei l'utente).
         Pensa come se fosse una password a bassa sicurezza.
      
      Q: Posso usare un proxy HTTP ?
      
      A: Si'.
      
      
      Q: Ho caricato un file ENORME, ma ho fatto un errore di battitura
         nell'indirizzo del destinatario. Ora mi trovo con una e-mail
         di errore.
         Devo effettuare di nuovo il caricamento di questo ENORME file?
      
      A: No, non e' necessario. Puoi ridirigere il file con
         http://$HTTP_HOST$/rup
      
      
      Q: Ho caricato un file ENORME ma ho dimenticato uno dei destinatari.
         Devo ricaricarlo?
      
      
      A: No, non e' necessario. Puo' inoltrare il file con
         http://$HTTP_HOST$/foc
      
      
      Q: Posso caricare file di dimensioni > di 2 GB con il mio browser !?
      
      A: Tutti i browser che conosco hanno dei bug nella loro implementazione
         delle FORM HTML.
         Il limite e' per lo piu' di 2 GB, molto spesso e' di 4 GB.
         Dovete usare uno speciale client F*EX per caricare file > 2GB,
         vedete http://$HTTP_HOST$/tools.html
      
      
      Q: Il mio download si e' bloccato prima di finire.
         Posso riprenderlo?
      
      A: F*EX supporta il recupero del download ma anche il vostro client deve
         supportare questa funzione. Firefox, per esempio, non ha questa funzione,
         serve un'altro client come Opera, Wget o Fexget.
      
      
      Q: Il caricamento del mio file si e' interrotto prima di finire.
         Posso riprenderlo?
      
      A: F*EX supporta la ripresa del caricamento interrotto di un file ma anche
         il client deve supportarlo. Nessun browser WEB ha questa funzionalita',
         avete bisogno di uno speciale client F*EX come fexsend, schwuppdiwupp o F*IX.
         Vedete http://$HTTP_HOST$/tools.html
      
      
      Q: Il mio browser WEB non puo' eseguire il client java F*IX
         in quanto non trova l'ambiente java runtime e quindi
         non puo' caricare la applet F*IX
      
      
      A: Manca il plug-in java per il vostro browser WEB. Sui sistemi Debian e
         Ubuntu potete installarlo con questo comando:
         "sudo aptitude install sun-java6-plugin"
      
      
      Q: Quando schiaccio [ESC] in firefox il caricamento si cancella. Perche'?
      
      A: Si tratta di una caratteristica di firefox: il tasto ESC termina
         l'operazione corrente.
         Soluzione semplica: non schiacciate ESC in Firefox.
         Soluzione complessa: chiedete agli sviluppatori di Firefox di aggiungere
         la configurazione della tastiera.
      
      
      Q: Spedire come utente F*EX e' facile, ma come posso
         ricevere i file da altri utenti all'esterno?
      
      A: Registrali come tuoi "sotto-utenti" oppure crea un gruppo F*EX
         con http://$HTTP_HOST$/fuc
      
      
      Q: Qualche volta posso scaricare un file piu' di una volta,
         specialmente quando ripeto l'operazione velocemente.
         La funziona di autodelete e' poco affidabile?
      
      A: Il server F*EX rende disponibile il file scaricato ancora per un
         periodo di 1 minuto. Questo e' necessario per evitare che alcuni
         "download managers" piuttosto stupidi diano errore in quanto
         richiedono il file parecchie volte di seguito.
      
      A: Il vostro fexmaster ha impostato la variabile AUTODELETE=DELAY
         come default, il che significa che il processo di
         autocancellazione e' eseguita una volta al giorno.
      
      A: Certi utenti (usate i sorgenti!!!) possono impostare il flag
         "non cancellare dopo il download".
      
      
      Q: La finestra temporale prima che il file sia cancellato e' troppo
         stretta per me, ho bisogno di allargarla. Come posso fare?
      
      A: Usate fexsend, chiedete al vostro fexmaster oppure leggete il
         codice sorgente :-)
      
      
      Q: Durante il download di un file con Internet Explorer
         mi dice "Non posso aprire il sito Internet". Cosa posso fare?
      
      A: Usate Firefox o qualsiasi altro browser WEB compatibile con Internet,
         dato che Internet Explorer non lo e'. Questo e' uno dei tanti bug di
         Internet Explorer.
      
      
      
      
      Domande Amministrative:
      =======================
      
      Q: Non posso installare un server web come fexsrv perche'
         non ho i permessi di root. Esiste una pura versione CGI
         di F*EX eseguibile con un web server Apache ?
      
      A: F*EX e' rigidamente vincolato a fexsrv per diverse ragioni (performance,
         limite dimensione file, concetto di sessione, etc) e non puo' essere
         eseguito come una CGI sotto apache.
         Potete dare un'occhiata a
         http://gpl.univ-avignon.fr/filez/
         http://freshmeat.net/projects/eventh/
         http://www.schaarwaechter.de/sp/projekte/dateiaustausch.html (Solo in Tedesco!)
         il quale implementa uno scambio file come pura CGI, ma ha il limite dei 2 GB.
      
      
      Q: F*EX non funziona per nulla!
         Non mi posso connettere con il mio browser web!
      
      A: Controllate il routing, le impostazioni del firewall e di ipfilters.
         Controllate anche che il vostro xinetd sia collegato con il
         wrapper-tcp e sia configurato correttamente (hosts.allow).
         F*EX necessita della porta 80/tcp (HTTP) e opzionalmente
         della 443/tcp (HTTPS).
      
      
      Q: F*EX e' troppo complicato!
         Mi serve qualcosa di piu' semplice.
      
      A: Provate http://www.home.unix-ag.org/simon/woof.html
      
      
      Q: Come posso integrare F*EX nell'ambiente di gestione
         dell'utente esistente nel mio sito?
      
      A: F*EX ha diversi moduli di autenticazione:
         locale, RADIUS, LDAP, mailman e POP
         Per gli ultimi 4 si prega di contattare l'autore
         framstag@rus.uni-stuttgart.de
      
      
      Q: Vorrei che i miei utenti locali usassero
         F*EX automaticamente. Come??
      
      A: Lasciate che si registrino da soli con http://yourfexserver/fur
         Dovete editare il file lib/fex.ph ed impostare (esempio):
         @local_hosts = qw(127.0.0.1 10.10.100.0-10.10.255.255);
         @local_domains = qw(flupp.org ulm.sub.net);
         (Ovviamente dovete iunserire i vostri dati reali!)
      
      
      Q: Ho bisogno di maggior sicurezza! Come posso abilitare HTTPS??
      
      A: Leggete la documentazione doc/SSL ed anche cercate "fop_auth" in doc/concept
      
      
      Q: Ho bisogno di un look aziendale.
         Come posso configurare F*EX per questo?
      
      A: Potete Guardare la variabile @H1_extra nel file fex.ph ed aggiungere
         codice HTML al file htdocs/header.html
      
      A: Guardate il file htdocs/fup_template.html, modificatelo secondo i vostri
         bisogni ed utilizzatelo come start-page.
      
      
      Q: F*EX e' troppo complicato per i miei utenti.
         Ho bisogno di una form semplificata.
      
      A: Guardate il file htdocs/fup_template.html
      
      
      Q: Vorrei che le e-mail BCC indirizzate all'amministratore
         fex fossero spedite ad altro indirizzo.
      
      A: Usate procmail o scrivete OTHERADDRESS in /home/fex/.forward
      
      
      Q: Posso avere una versione localizzata
         nella mia lingua??
      
      A: Con il vostro aiuto, si'. Per favore contattate l'autore a
         framstag@rus.uni-stuttgart.de
      
      
      Domande varie:
      ==============
      
      Q: F*EX e' ottimo! Posso lavorare con
         il team di sviluppo?
         Che cosa c'e' bisogno di fare?
      
      A: Contattate l'autore framstag@rus.uni-stuttgart.de
         Funzionalita' richieste:
      
           - Un plug-in F*EX per thunderbird o outlook
           - Supporto in altre lingue
      
      
      fex-20160919/locale/italian/htdocs/FAQ/0000750000174700017470000000000012770010166015461 5ustar fexfexfex-20160919/locale/italian/htdocs/FAQ/FAQ.html0000644000174700017470000000035512770010166016766 0ustar fexfex F*EX FAQ ## << do "./xx.pl" or print $! >> ## << $_ = `pwd` >> ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      << do "./faq.pl" or print $! >> fex-20160919/locale/italian/lang.html0000644000174700017470000000001111605620477015402 0ustar fexfexitaliano fex-20160919/locale/spanish/0000755000174700017470000000000012654503773013633 5ustar fexfexfex-20160919/locale/spanish/lib/0000755000174700017470000000000012770010166014365 5ustar fexfexfex-20160919/locale/spanish/lib/fup.pl0000644000174700017470000000270711615070623015523 0ustar fexfex# config for F*EX CGI fup $info_1 = $info_login = <

      F*EX (File EXchange) es un servicio para enviar ficheros (grandes, enormes, gigantes, ...).

      El remitente (usted) sube el fichero al servidor F*EX y el destinatario recibe automáticamente una notificación por correo electrónico con una URL de descarga.
      Tras la descarga o tras $keep_default días el servidor borra el fichero. ¡F*EX no es un archivador!

      Vea también preguntas y respuestas.


      $ENV{SERVER_ADMIN}
      EOD $info_2 = <

      Tras pulsar el botón de enviar verá una barra de progreso de la subida (si tiene javascript activado y permite las ventanas emergentes)

      NOTE: ¡La mayoría de los navegadores web no pueden subir ficheros > 2 GB!
      Si su fichero es más grande tiene que usar un cliente de F*EX especial.
      También necesita uno para poder continuar con una subida interrumpida. Su navegador no puede hacerlo.

      Aviso: ¡algunos proxys HTTP como privoy retrasan la barra de progreso de la subida!
      Quizá quiera desabilitar el proxy para $ENV{SERVER_NAME} si se encuentra con problemas.

      Usuarios de firefox: ¡no pulse [ESC] porque aborta la subida!

      Vea también la FAQ. EOD fex-20160919/locale/spanish/lib/reactivation.txt0000644000174700017470000000006011626277145017625 0ustar fexfexSu cuenta de F*EX ha sido reactivado con exito. fex-20160919/locale/spanish/htdocs/0000755000174700017470000000000012654505200015102 5ustar fexfexfex-20160919/locale/spanish/htdocs/index.html0000644000174700017470000001412712031360371017101 0ustar fexfex F*EX - File EXchange

      F*EX - Frams' Fast File EXchange

      F*EX (Frams' Fast File EXchange) es un servicio para enviar ficheros (grandes, enormes, gigantes, ...) de un usuario A a otro B.

      El remitente sube el fichero al servidor F*EX usando el formulario de subida WWW y el destinatario automáticamente recibe una notifiación por correo electrónico con la URL de desacarga.

      Usted dirá:

      ¡¿Por qué necesito de otro servicio de transferencia de ficheros?!
      ¡Tengo el correo electrónico, ftp, ssh e incluso sendfile!

      Yo le respondo:

      Aun así necesita F*EX :-)

      Por ejemplo, quiere enviar a un amigo su último video de las vacaciones (1 GB). Tiene las siguientes posibilidades (y problemas):

      • enviar un DVD por correo postal

        Sin comentarios - ¡vivimos en el año <> tras la invención de internet! Enviar DVDs/CDs es para los abuelos.

      • usando el correo electrónico

        La mayoría de los servidores de correo tienen una límite de 10 MB por mensaje de correo electrónico y una cuota de almacenamiento de uno 100 MB por usuario e incluso menos.

      • uucp

        ¿Por qué no escritura cuneiforme sobre planchas de piedra?

      • ssh

        ¿Tiene la contraseña de su amigo o está deseando darle la suya tan sólo para la transferencia de un fichero?

      • ftp

        • Usando ¿qué servidor FTP?
        • Usando ¿qué cuenta y con qué contraseña?
        • ¿No le importa enviar contraseñas sin cifrar y ficheros a través de internet que no es seguro?
        • ¿Su proxy soporta ftp pasivo?
        • En caso de usar ftp anónimo:
          • ¿Permite subi 1 GB?
          • ¿Permite borrar los ficheros subidos después?
          • ¿Quién más puede descargar su fichero?
          • ¿Quién más puede borrar su fichero?
          • Tiene que enviarle a su amigo la URL de descarga, él tiene que informarle de que la descarga ha finalizado sin problemas y tiene que borrar el fichero después.
            En resumen: un grano en el culo.

      • http

        • No hay una administración de ficheros subidos y usuarios - hay que programarla
        • No hay autonotificación
        • No hay autoborrado
        • Muy pocos servidores http pueden manejar ficheros de más de 2 GB

      • sendfile

        • ¿Tiene UNIX y tiene sendfile instalado?
        • ¿Su destinatario tiene UNIX y tiene sendfile instalado?
        • ¿Ni usted ni su destinatario tiene un cortafuegos que bloquee el puerto 487?

      • servicios comerciales como DropLoad, ALLPeers, YouSendIt, etc.

        • ¿Qué limite tienen (la mayoría: < 2 GB)?
        • ¿Qué pasa con la seguridad y la privacidad: estarán sus ficheros a salvo?
        • ¿Están basados en software abierto o propietario?
        • ¿Son accesible con cualquier navegador o necesita java, active-X, flash u otro plugins?
        • ¿Sobrevirá más de unos cuantos meses?
          (DropLoad y ALLPeers ya han finalizado su actividad)

      Si ha contestado sólo una vez "no" a las preguntas anteriores, entonces necesita F*EX.

      Principales características de F*EX

      • transferencia de ficheros de tamaño virtualmente ilimitado
      • el destinatario y el remitente solo necesitan un programa de correo electrónico y un navegador web - de cualquier tipo, no necesitan instalar ningún software
      • RESEND y REGET para continuar las descargas interrumpidas por fallos en el enlace
      • autonotificación al destinatario
      • autoborrado tras la descarga
      • autoborrado tras la fecha de expiración (por defecto: 5 días)
      • los usuarios normales pueden crear subusuarios, que pueden enviar solo al usuario normal que lo definió
      • los usuarios normales puede crear grupos, una anología de las listas de correo, pero para ficheros
      • sin mantenimiento: no es necesaria la intervención del administrador más allá de crear la cuentas en F*EX
      • para enviar a múltiples destinatarios solo es necesario subir el fichero una vez
      • F*EX es un servicio web HTTP y no necesita que se creen túneles en los cortafuegos
      • también soporta streams
      • los usuarios UNIX reales, puede usar los programas para el shell fexsend y fexget para evitar el uso del navegador web
      • el protocolo y código fuente están disponibles (Perl Artistic)

      Hablemos de SEX

      F*EX tiene un acompañante: Stream EXchange (SEX).

      Puede imaginar SEX como si fueran tubería de UNIX a través de la red con un relay en medio. Esto puede ser útil para entubar datos del usuario A a otro B, donde A y B no pueden establecer una conexión directa, per ambos puede conectar por HTTP a servidor SEX. Las herramientas del shell sexsend y sexget permiten integrarlo fácilmente entre el conjunto de herramientas de UNIX.

      La autenticación es igual que en F*EX.

      ¿Todavía tiene más preguntas?

      Vea la FAQ

      contacto: Administrador de F*EX
      fex-20160919/locale/spanish/htdocs/FAQ.html0000644000174700017470000002237612435373512016417 0ustar fexfex

      Este documento está obsoleto. Por favor, use FAQ en inglés.

      Meta preguntas:
      ===============
      
      P: ¿Por qué el nombre de F*EX y no uno más corto?
      
      R: En el momento de la publicación había ya un programa llamado "FEX" activo 
         (más viejo) freshmeat.net.
      
      
      P: ¿Por qué no emplear un servicio comercial
         DropLoad, ALLPeers, YouSendIt, etc?
         
      R: Tienen un límite de 2GB incluso ó menos.
         Su estado de privacidad y seguridad es desconocido.
         No están basados en software abierto.
         No existe ningún cliente UNIX (CLI) para ellos.
         Necesitan java, active-X, flash u otros plugins endemeniados.
         Se desconoce cuanto durarán - DropLoad y ALLPeers
         ha finalizado sus asuntos.
      
      
      P: ¿Por qu el camello como logo?
      
      R: El logo fue inspirado por el camello de Perl, pero est basado en un Steiff
         el camello de peluche, que correo con con nosotros on nuestro tamdem de 
         carrelas.  El logo fue dibujado por Beate.
      
      
      P: ¿Dónde puedo conseguir los fuentes de F*EX?
      
      R: http://fex.rus.uni-stuttgart.de/fex.html
      
      
      P: ¿Que hace falta para instalar F*EX?
      
      R: Un servidor UNIX con una entrega DNS y smtp para correo saliendo.
         Y hace falta estar root en este ordenador.
      
      
      P: ¿Que es DNS y smtp?
      
      R: Que no instale F*EX. Es allende de su horizonte.
      
      
      P: ¿Quién es el autor?
      
      A: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
      
      
      P: ¿Qué licencia tiene F*EX?
      
      R: Software libre Perl Artistic, vea http://fex.rus.uni-stuttgart.de/doc/Licence
      
      
      P: ¿Hay una lista de correo de F*EX?
      
      A: https://listserv.uni-stuttgart.de/mailman/listinfo/fex
      
      
      P: ¿Dónde puede conseguir apoyo comercial para F*EX?
      
      R: Contacte con fex@nepustil.net http://www.nepustil.net/
      
      
      P: ¡Tengo más/otras preguntas de las que aparecen en este documento!
      
      R: Pregunte al autor <framstag@rus.uni-stuttgart.de>
      
      
      Preguntas de los usuarios:
      ==========================
      
      P: ¿Qué es el "auth-ID"?
      
      R: El auth-ID es una identificación interna que autentica al usuario.
         La primera vez es generado por el administrador o por el proceso de registro
         automático y pude modificarlo más tarde. Piense en él como
         una especie de clave poco segura.
      
      
      P: ¿Puedo usar un proxy HTTP?
      
      R: Sí
      
      
      P: He subido un fichero ENORME pero me he confundido al escribir la dirección 
         de correo electrónico del destinatario.
         Acabo de recibir un correo de error de rebote. 
         ¿Tengo que volver a subir el fichero ENORME?
      
      R: No, no es necesario. Puede redirigir el fichero con
         http://$HTTP_HOST$/rup
      
      
      P: He subido un fichero ENORME pero olvidé poner a un destinatario.
         ¿Tengo que volver a subir el fichero ENORME?
      
      R: No, no es necesario. Puede reenviar una copia del fichero con
         http://$HTTP_HOST$/foc
      
      
      P: ¿¡No puede subir ficheros > 2 GB con mi navegador web!?
      
      R: Todos los navegadores web que conozco tienen errores en su implementación
         de HTML-FORM. El límite en la mayoría es de 2 GB, algunas veces 4 GB.
         Tiene que usar un cliente especial de F*EX para subir ficheros > 2 GB, vea
         http://$HTTP_HOST$/tools.html
      
      
      P: Mi descarga abortó antes de que acabara. ¿Puedo continuar la descarga?
      
      R: F*EX soporta la continuación de la descarga, pero su cliente debe soportar
         también esta característica. Firefox, por ejemplo, no tiene esta 
         característica HTTP, necesita otro cliente como opera, wget o fexget
      
      
      P: Mi subida abortó antes de que finalizara. ¿Puedo continuar la subida?
      
      R: F*EX soporta la continuación de la subida, pero su cliente también debe 
         soportarla. Ningún navegador web tiene esta característica, necesita un 
         cliente de F*EX especial como fexsend, schwuppdiwupp o F*IX
         Vea http://$HTTP_HOST$/tools.html
      
      
      P: Cuando pulso [ESC] en firefox la subida se cancela. ¿Por qué?
      
      R: Esta es una característica de firefox: ESC finaliza la operación en curso.
         Solución sencilla: no pulse ESC en Firefox
         Solución compleja: pida a los desarrolladores de Firefox que añadan una 
                            configuración del teclado
      
      
      P: Enviar como usario F*EX es fácil, pero ¿como pueden recibirse fichero de 
         otros desde fuera?
      
      R: Registrelos como su subusuarios o cre un grupo F*EX
      
      
      P: A veces puedo descargar un fichero más de una vez, especialmente cuando
         lo repito rápidamente. ¿Tiene errores la caracter de autoborrado?
      
      R: El servidor F*EX tiene un tiempo de gracia de 1 minuto tras la primera
         descarga con exito durante el cual el fichero está disponible todavía.  
         Este es necesario porque algunos "administradores de descargas" estúpidos 
         solicitan el fichero varias al mismo tiempo.  De otra manera, informan al 
         usuario de un error.
      
      R: Su fexmaster ha establecido AUTODELETE=DELAY por defecto, lo que significa 
         que el proceso de limpieza del autoborrado se ejecuta una vez al día
      
      R: Los usuario normales (use los fuentes, Luke!) pueden establecer una bandera
         de "no borrar tras la descarga"
      
      
      P: El tiempo por defecto para mantener el fichero en el sistema es desmasiado 
         corto para mí, necesito más. ¿Cómo puedo cambiarlo?
      
      R: Use fexsend, pregunte a su fexmaster o lea el código fuente
      
      
      P: No puede descargar ficheros con Internet Explorer, me dice "No puedo
         abrir el sistio de Internet". ¿Qué debería hacer?
      
      R: Use Firefox o cualquier otro navegador web compatible con Internet, puesto 
         que Internet Explorer no lo es. Este es uno de los muchos errores de 
         Internet Explorer.
      
      
      Preguntas del administrador:
      ============================
      
      P: No puedo instalar un servidor web como fexsrv, porque no tengo permisos
         de root. ¿Existe una versión CGI pura de F*EX que funcione con un
         servidor web apache?
      
      R: F*EX está íntimamente unido a fexsrv por varias razones (prestaciones,
         limitación en el tamaño del fichero, el concepto de sesión, etc.) y no 
         puede ejecutarse como CGI desde apache.
         Pero puede echar un vistazo a
         
         http://gpl.univ-avignon.fr/filez/
         http://freshmeat.net/projects/eventh/
      
         que implementa un intercambio de ficheros con CGIs puros, pero ambos están 
         limitados a 2 GB.
         
      
      P: ¡F*EX no funciona en absoluto! 
         ¡No puedo conectarme a él con mi navegador web!
      
      R: Compruebe el encaminamiento, los filtros IP y la configuración del 
         cortafuegos. Compruebe también si su xinetd está enlazado con tcp-wrapper 
         y configúrelo correctamente (hosts.allow).
      
         F*EX necesita el puerto 80/tcp (HTTP) y opcionalmente el puerto 443/tcp
         (HTTPS).
      
      
      P: ¡F*EX es muy complicado! Necesito algo más sencillo.
      
      R: Pruebe http://www.home.unix-ag.org/simon/woof.html
      
      
      P: ¿Como puedo integrar F*EX la administración de usuario existente de mi 
         sitio?
      
      R: F*EX tiene varios módulos de autenticación:
         local, RADIUS, LDAP, mailman y POP
         Para los últimos 4 póngase en contacto con el autor por favor.
         
      
      P: Quiero que todos mis usuarios locales use F*EX automáticamente. 
         ¿Cómo puedo hacerlo?
      
      R: Déjelos autoregistrarse.
         Tiene que editar el fichero lib/fex.ph y establecer (ejemplo):
      
         @local_hosts = qw(127.0.0.1 10.10.100.0-10.10.255.255);
         @local_domains = qw(flupp.org ulm.sub.net);
      
         ¡Desde luego tiene que añadir su hosts/redes locales reales!
      
      
      P: ¡Necesito más seguridad! ¿Cómo activo HTTPS?
      
      R: Lea doc/SSL y mire busque también "fop_auth" e doc/concept
      
      
      P: ¡Necesito que tenga una imagen corporativa. ¿Como configuro F*EX para que 
         la tenga?
      
      R: Vea la variable @H1_extra en fex.ph y puede añadir htdocs/header.html
      
      R: Vea fup_template.html, modifíquela según sus necesidades y usela como 
         página de inicio
      
      
      Otras preguntas:
      ================
      
      P: ¡F*EX es estupendo! ¿Puedo unirme al equipo de desarrollo? 
         ¿Qué hay que hacer?
      
      R: Contacte con el autor
      
         Características no presente:
      
         - otro cliente de subida que se integre mejor en Windows
           arrastrar y soltar, libro de direcciones de Outlook, etc.
      
      fex-20160919/locale/spanish/htdocs/FAQ/0000750000174700017470000000000012770010166015505 5ustar fexfexfex-20160919/locale/spanish/htdocs/FAQ/FAQ.html0000644000174700017470000000035512770010166017012 0ustar fexfex F*EX FAQ ## << do "./xx.pl" or print $! >> ## << $_ = `pwd` >> ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      << do "./faq.pl" or print $! >> fex-20160919/locale/spanish/lang.html0000644000174700017470000000001711725126335015431 0ustar fexfexespañol fex-20160919/locale/french/0000755000174700017470000000000012654503773013433 5ustar fexfexfex-20160919/locale/french/lib/0000755000174700017470000000000012770010166014165 5ustar fexfexfex-20160919/locale/french/lib/fup.pl0000644000174700017470000000246512624117324015325 0ustar fexfex# config for F*EX CGI fup use utf8; $info_1 = $info_login = <

      F*EX (File EXchange) est un service pour envoyer des fichiers très volumineux (grand, énorme, géant, ...).

      L'expéditeur (vous) upload le fichier vers un serveur F*EX et le destinataire reçoit automatiquement un message de notification par mail avec l'URL de téléchargement.
      Après un téléchargement ou après $keep_default jours, le serveur efface le fichier. F*EX n'est pas un système d'archivage!

      Voir les questions & réponses.


      $ENV{SERVER_ADMIN}
      EOD $info_2 = <

      Après soumission de votre fichier pour l'upload, vous verrez une barre de progression (si vous avez javascript activé et que les popups sont autorisés)

      REMARQUE: La plupart des navigateurs ne peuvent pas uploader des fichiers > 2 GB!
      Si votre fichier est plus gros, vous devez utiliser un client F*EX spécial.
      Vous devez aussi en utiliser un pour la reprise d'upload interrompu. Votre navigateur ne peut pas le faire.

      Pour les utilisateurs de Firefox : ne pas appuyer sur [ESC] parce que cela stoppera l'upload !

      Voir aussi la FAQ. EOD fex-20160919/locale/french/lib/reactivation.txt0000644000174700017470000000006011713446544017423 0ustar fexfexVotre compte F*EX a été activé avec succès. fex-20160919/locale/french/htdocs/0000755000174700017470000000000012654503773014717 5ustar fexfexfex-20160919/locale/french/htdocs/index.html0000644000174700017470000001334712216247741016716 0ustar fexfex F*EX - File EXchange

      F*EX - Frams' Fast File EXchange

      F*EX (Frams' Fast File EXchange) est un service pour envoyer des fichiers volumineux d'un utilisateur A à un utilisateur B.

      L'expéditeur upload le fichier au serveur F*EX en utilisant un formulaire WWW et le destinataire reçoit automatiquement une notification.

      Vous vous dîtes:

      Pourquoi aurais -je besoin d'un autre service de transfert de fichier ?!
      J'ai déja l'e-mail, le ftp, ssh et même sendfile !

      Je réponds:

      Vous avez toujours besoin de F*EX :-)

      Par exemple, vous voulez envoyer à vos amis la dernière vidéo de vos vacances (1 GB). Vous avez les possibilités suivantes (et les problèmes):

      • envoyer un DVD par la voie postale

        Hors de question - nous vivons en <> après l'invention d'Internet. C'est pour les grand-pères.

      • utiliser l'e-mail

        La plupart des serveurs e-mail ont une limite de 10 MB par message et très souvent un quota d'utilisation de quelques centaines de méga-octets.

      • uucp

        Et pourquoi pas du marbre et un burin ?

      • ssh

        Vous avez le mot de passe de vos amis ou bien vous êtes prêts à leur donne le votre, juste pour un transfert de fichier ?

      • ftp

        • Quel serveur ?
        • Quel compte, quel mot de passe ?
        • Vous ne vous souciez pas d'envoyer des mots de passes non chiffrés et des fichiers sur un Internet non sécurisé ?
        • Est-ce que votre proxy support le ftp passif ?
        • Dans le cas d'un ftp anonyme :
          • Est-ce qu'il permet des uploads de 1GB ?
          • Est-ce qu'il permet de supprimer le fichier uploadé ?
          • Qui peut télécharger votre fichier ?
          • Qui peut supprimer votre fichier ?
          • Vous devez envoyer à votre ami l'URL de téléchargement, il doit vous informer que le download s'est bien passé et vous devez supprimer le fichier .
            C'est plutôt pénible.

      • http

        • Pas d'upload par défaut et de gestion des utilisateurs. Cela doit être programmé
        • Pas de notification automatique
        • Pas d'effacement automatique
        • Peu de serveur http peuvent gérer des fichiers de plus de 2GB

      • sendfile

        • Vous utilisez UNIX et sendfile est installé ?
        • Votre destinataire utilise UNIX et a sendfile d'installé ?
        • Ni vous ou votre destinataire n'a le port 487 bloqué par un firewall ?

      • Des services commerciaux comme DropLoad, ALLPeers, YouSendIt, etc

        • Quel limite ont-ils (le plupart: < 2 GB)?
        • Quid de la sécurité et de la confidentialité : est-ce vos fichiers seront entre de bonnes mains ?
        • Est-ce qu'ils sont opensource ou propriétaire ?
        • Est-ce qu'ils sont accessibles avec n'importe quel navigateur ou bien avez-vous besoin de java, active-X, flash ou d'autres plugins ésotériques ?
        • Est-ce qu'ils vont encore exister d'ici quelques mois?
          (DropLoad, ALLPeers et drop.io ont déja mis la clé sous la porte)

      Si vous avez répondu "non" à une seule de ces questions, alors vous avez besoin de F*EX

      Principales fonctionnalités de F*EX

      • transfert de fichier de taille virtuellement infini
      • le destinataire et l'expéditeur ont uniquement besoin d'un e-mail et d'un navigateur web, ils n'ont pas besoin d'installer de logiciels.
      • reprise d'upload et de téléchargement en cas de défaillance
      • notification automatique du destinataire
      • suppression automatique après un téléchargement
      • suppression automatique après un délai ajustable (par défaut: 5 jours)
      • les utilisateurs F*EX peuvent créer des URLs d'upload à usage unique pour des utilisateurs extérieurs
      • les utilisateurs F*EX peuvent créer des sous-utilisateurs qui ne pourront envoyer des fichiers uniquement à cet utilisateur
      • les utilisateurs F*EX peuvent créer des groupes, similaire à des listes de diffusions, mais pour des fichiers
      • maintenance réduite au minimum : pas d'interventations de l'administrateur nécessaires mise à part la création de nouveaux utilisateurs
      • l'envoi à plusieurs destinataires ne nécessite pas le stockage d'autant de fichiers sur le serveur
      • F*EX est un service web HTTP qui ne nécessite pas de contourner les parre-feux.
      • support des flux
      • pour les vrais utilisateurs UNIX, il existe les programmes shell fexsend et fexget afin d'éviter l'utilisation ennuyeuse de l'interface web
      • protocole et code source librement disponible (Perl Artistic)

      Parlons de SEX

      F*EX a un ami : Stream EXchange (SEX).

      Vous pouvez imager SEX comme un tube UNIX réseau s'appuyant sur un relais. Cela peut s'avérer utile pour envoyer des données d'un utilisateur A à un utilisateur B lorsque A et B ne peuvent établir une connexion directe, mais que chacun peut accéder en HTTP au serveur SEX. Pour une intégration sans peine avec les outils UNIX, il y a les commandes shell sexsend et sexget.

      L'authentifaction est la même qu'avec F*EX

      Encore des questions?

      Voir la FAQ

      contact: fexmaster
      fex-20160919/locale/french/htdocs/FAQ/0000755000174700017470000000000012770010166015312 5ustar fexfexfex-20160919/locale/french/htdocs/FAQ/index.html0000777000174700017470000000000012213333311021110 2meta.htmlustar fexfexfex-20160919/locale/french/htdocs/FAQ/FAQ.html0000644000174700017470000000035512770010166016612 0ustar fexfex F*EX FAQ ## << do "./xx.pl" or print $! >> ## << $_ = `pwd` >> ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      << do "./faq.pl" or print $! >> fex-20160919/locale/french/htdocs/FAQ/admin.faq0000600000174700017470000000516411777535152017106 0ustar fexfex
      
      Q: Je ne peux pas installer un serveur web comme fexsrv parce que je n'ai pas les permissions root. Est-ce qu'il existe une version pure CGI de F*EX qui puisse tourner avec un server Apache ?
      A: F*EX est fortement lié à fexsrv pour plusieurs raisons (performance, limite de la taille des fichiers, session, etc...) et ne peut pas tourner comme un CGI sous Apache. Mais vous pouvez jeter un oeil à 
      
      • http://gpl.univ-avignon.fr/filez/
      • http://freshmeat.net/projects/eventh/
      • http://www.schaarwaechter.de/sp/projekte/dateiaustausch.html (en Allemand)
      qui implementent le transfert de fichier avec des CGIs pures, mais avec une limite de 2GB. Q: F*EX ne fonctionne pas du tout ! Je ne peux pas m'y connecter avec mon navigateur web ! A: Vérifier votre routage, ipfilters et la configuration de votre pare-feux. Vérifier également si votre xinetd est linké à tcp-wrapper et configuré convenablement (hosts.allow). F*EX a besoin du port 80/tcp pour HTTP et optionnellement du port 443/tcp pour HTTPS. Q: F*EX est trop complexe ! J'ai besoin de quelque chose encore plus simple. A: Essayez http://www.home.unix-ag.org/simon/woof.html Q: Comment puis-je intégrer F*EX à un système d'annuaire ou de gestion d'identité ? A: F*EX a plusieurs modules d'authentification: local, RADIUS, LDAP, mailman et POP. Pour les quatre derniers, contacter framstag@rus.uni-stuttgart.de Q: Je veux que tous mes utilisateurs locaux puissent utiliser F*EX. Comment je fais ? A: Ils doivent s'enregistrer eux-mêmes avec http://$HTTP_HOST$/fur

      Il faut éditer lib/fex.ph et configurer (exemple):

       @local_hosts = qw(127.0.0.1 10.10.100.0-10.10.255.255);
       @local_domains = qw(flupp.org ulm.sub.net);
      
      (Bien entendu, vous devez utiliser les paramètres propres à votre réseau !) Q: J'ai besoin de plus de sécurité ! Comment activer HTTPS ? A: Lisez doc/SSL and jetez un oeil à "fop_auth" dans doc/concept Q: J'ai besoin d'un look adapté à mon image. Comment puis-je configurer F*EX en ce sens ? A: Voir la variable @H1_extra dans fex.ph et aussi l'ajout possible de code HTML à htdocs/header.html

      Voir htdocs/fup_template.html, le modifier selon vos besoins et l'utiliser comme page de démarrage. Q: F*EX est trop compliqué pour mes utilisateurs. J'ai besoin d'un formulaire d'upload simplifié. A: Voir htdocs/fup_template.html Q: Je veux que les mails Bcc destinés à F*EX (utilisateur admin) soient envoyés à une autre adresse. A: Positionnez la variable $bcc dans fex.ph Q: Puis-je avoir une version localisé dans ma langue ? A: Avec votre aide, oui. Merci de contacter framstag@rus.uni-stuttgart.de fex-20160919/locale/french/htdocs/FAQ/admin.html0000644000174700017470000000056212645025756017307 0ustar fexfex F*EX FAQ ##

      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      Ce document est périmé. Merci de consulter la FAQ anglaise

      << require "./faq.pl" or print $! >> fex-20160919/locale/french/htdocs/FAQ/all.html0000644000174700017470000000056212645025756016767 0ustar fexfex F*EX FAQ ##

      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      Ce document est périmé. Merci de consulter la FAQ anglaise

      << require "./faq.pl" or print $! >> fex-20160919/locale/french/htdocs/FAQ/faq.pl0000644000174700017470000000632012624155641016425 0ustar fexfexuse utf8; package FAQ; my ($faq,$var,$env,$q,$a,$c,$s,$t,$n); my (@faq,%Q,%A,@s); my @sections = qw'Meta User Admin Misc'; @faq = ($faq) = $ENV{PATH_INFO} =~ /(\w+).html/; @faq = map {lc} @sections if $faq eq 'all'; print "\n"; print '

      F*EX '; printf "Frequently Asked Questions: %s

      \n",ucfirst($faq); if ($faq ne 'local') { print "

      Sections: "; foreach $s (@sections,'All') { if ($s =~ /$faq/i) { print "$s\n"; } else { printf "[%s]\n",lc($s),$s; } } print "

      \n"; } print "


      \n"; print "\n"; foreach my $faq (@faq) { open $faq,"$faq.faq" or next; local $/ = "Q:"; local $_ = <$faq>; while (<$faq>) { chomp; while (/\$([\w_]+)\$/) { $var = $1; $env = $ENV{$var} || ''; # s/\$$var\$/$env<\/code>/g; s/\$$var\$/$env/g; }; ($q,$a) = split /A:\s*/; $q =~ s/[\s\n]+$//; $q =~ s/^\s+//; $q =~ s! (/\w[\S]+/[\S]+)! $1!g; $a =~ s/[\s\n]+$/\n/; $a =~ s/^\s+//; while ($a =~ s/^(\s*)\*/$1
        \n$1
      • /m) { while ($a =~ s/(
      • .*\n\s*)\*/$1
      • /g) {} $a =~ s:(.*\n)(\s*)(
      • [^\n]+\n):$1$2$3$2
      \n:s } $a =~ s/\n\n/\n

      \n/g; $a =~ s/([^>\n\\])\n/$1
      \n/g; $a =~ s/

      (.+?)<\/pre>/pre($1)/ges;
          $a =~ s/\\\n/\n/g;
      #    $a =~ s/^\s*
      \s*//mg; $a =~ s/<([^\s<>\@]+\@[\w.-]+)>/<$1><\/a>/g; $a =~ s! (/\w[\S]+/[\S]+)! $1!g; $a =~ s!(https?://[\w-]+\.[^\s<>()]+)![$1]!g or $a =~ s!(https?://[^\s<>()]+)!$1!g; push @{$Q{$faq}},$q; push @{$A{$faq}},$a; } close $faq; } print "
      \n"; foreach $s (sections($faq)) { $c = lc $s; $s = '' if $s eq 'Local'; $t = ''; $t = $s if $faq eq 'all'; for ($n = 0; $n < scalar(@{$Q{$c}}); $n++) { $q = ${Q{$c}[$n]}; $qa = anchor($q); printf ''."\n", $t,$n+1,$s,$n+1,$qa,$q; } } print "
      '. ''. '%s Q%d:'. '%s
      \n"; print "


      \n"; foreach $s (sections($faq)) { $c = lc $s; $s = '' if $s eq 'Local'; $t = ''; $t = $s if $faq eq 'all'; for ($n = 0; $n < scalar(@{$Q{$c}}); $n++) { $q = ${Q{$c}[$n]}; $qa = anchor($q); print "

      \n"; print "\n"; printf "\n", $t,$n+1,$s,$n+1,$qa,$q; printf "\n", $s,$n+1,${A{$c}[$n]}; print "
      ". "%s Q%d:". "". "%s
      %s A%d:\n%s
      \n"; print "[↑ Questions]\n"; } } print "

      \n";
      print "\n" x 99;
      print "
      \n"; sub sections { my $faq = shift; if ($faq eq 'all') { return @sections; } else { return ucfirst($faq); } } sub pre { local $_ = shift; s/
      //g; s/\s+$//; return "
      $_
      \n"; } sub anchor { local $_ = shift; s/<.+?>//g; s/\(.+?\)//g; s/\W/_/g; s/_+$//; return $_; } fex-20160919/locale/french/htdocs/FAQ/local.faq0000600000174700017470000000031712223027102017055 0ustar fexfexQ: Comment puis-je utiliser ma propre FAQ ? A: Placer votre FAQ dans le fichier /home/fex/htdocs/FAQ/local.faq et exécuter : cd /home/fex/htdocs/FAQ ln -sf local.html index.html fex-20160919/locale/french/htdocs/FAQ/local.html0000644000174700017470000000056212645025756017311 0ustar fexfex F*EX FAQ ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      Ce document est périmé. Merci de consulter la FAQ anglaise

      << require "./faq.pl" or print $! >> fex-20160919/locale/french/htdocs/FAQ/meta.faq0000600000174700017470000000376512645025707016744 0ustar fexfex

      
      Q: Pourquoi "F*EX" comme nom et pas simplement "FEX"
      A: À l'époque de l'annonce du logiciel, il existait déja un programme (plus ancien) nommé "FEX" sur 
         freshmeat.net.
      
      Q: Pourquoi ne pas utiliser un service commercial comme DropLoad, ALLPeers, YouSendIt, etc ?
      A: 
      • Ils ont une limite de 2GB ou moins.
      • Leur politique de sécurité et de confidentialité est inconnue.
      • Ils ne sont pas opensource.
      • Il n'y a pas d'interface en ligne de commande (CLI) UNIX.
      • Ils ont besoin de java, active-X, flash ou d'autres plugins esotériques.
      • On ne sait pas combien de temps ils vont exister - DropLoad and ALLPeers ont déja cessé leur activité.
      Q: Pourquoi un chameau comme logo ? A: Le logo est inspiré du chameau de Perl, mais il est basé sur un chameau "Steiff plush" qui courent avec nous lors de nos courses de tandem. Le logo a été dessiné par mon "chauffeur" Beate. http://fex.rus.uni-stuttgart.de/Vortrag/tosa.html Q: Où puis-je récupérer les sources de F*EX ? A: http://fex.rus.uni-stuttgart.de/fex.html Q: Perl n'est-il pas trop lent pour faire tout ça ? A: fex.rus.uni-stuttgart.de tourne sur un ordinateur de bureau et est capable de gérer des uploads à plus de 300 MB/s. Essayer donc ça avec un serveur web généraliste comme Apache ! Q: De quoi ai-je besoin pour installer F*EX ? A: D'une machine UNIX avec une entrée DNS et un service smtp fonctionnel. Vous devez être root sur la machine. Q: Qu'est-ce que DNS et smtp ? A: N'installez pas F*EX. Ce n'est pas fait pour vous. Q: Qui est l'auteur ? A: Ulli Horlacher framstag@rus.uni-stuttgart.de Q: Quelle est la licence de F*EX ? A: Perl Artistic free software Q: Est-ce qu'il y a une mailing list F*EX ? A: https://listserv.uni-stuttgart.de/mailman/listinfo/fex Q: Où puis-je avoir un support commercial pour F*EX ? A: Contacter fex@nepustil.net http://www.nepustil.net/ Q: J'ai encore des questions ! A: Demandez directement à l'auteur framstag@rus.uni-stuttgart.de fex-20160919/locale/french/htdocs/FAQ/meta.html0000644000174700017470000000056212645025756017145 0ustar fexfex F*EX FAQ ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      Ce document est périmé. Merci de consulter la FAQ anglaise

      << require "./faq.pl" or print $! >> fex-20160919/locale/french/htdocs/FAQ/misc.faq0000600000174700017470000000065611713227453016742 0ustar fexfex

      
      Q: F*EX est un très bon logiciel ! Est-ce que je peux rejoindre l'équipe de développement ? Qu'est-ce qu'il y a à faire ?
      A: Contacter l'auteur

      Les fonctionnalités souhaitées sont :

      • des testeurs pour MacOS, AIX et les autres UNIX
      • un nouveau mainteneur pour le client Java F*EX
      • un plugin F*EX pour thunderbird ou outlook
      • plus de langages supportés (japonais, klingon ...)
      fex-20160919/locale/french/htdocs/FAQ/misc.html0000644000174700017470000000056212645025756017152 0ustar fexfex F*EX FAQ ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      Ce document est périmé. Merci de consulter la FAQ anglaise

      << require "./faq.pl" or print $! >> fex-20160919/locale/french/htdocs/FAQ/user.faq0000600000174700017470000001176311777534634017002 0ustar fexfex

      
      Q: Qu'est-ce que l'auth-ID ?
      A: L'auth-ID est un moyen d'authentification interne qui permet d'authentifier l'utilisateur. Il sera d'abord généré par l'admin ou le processus d'enregistrement automatique et pourra être modifié plus tard par vous, l'utilisateur. Vous pouvez y penser comme à un mot de passe à faible sécurité.
      
      Q: Puis-je utiliser un proxy HTTP ?
      A: Oui, mais attention:
         Certain proxy http comme HTTP introduise un délai dans l'affichage de la barre de progression lors d'un upload !
         Vous pouvez essayer de désactiver le proxy pour $SERVER_NAME si vous rencontrez ce problème.
      
      Q: J'ai uploadé un fichier très volumineux mais j'ai fait une faute dans l'adresse du destinataire. J'ai reçu un message d'erreur par mail. Dois-je uploader à nouveau ce fichier ?
      A: Non, cela n'est pas nécessaire. Vous pouvez rediriger un fichier via le menu "Configuration utilisateur & Gestion"
      
      Q: Mon destinataire a perdu son e-mail de notification avec l'URL de téléchargement. Que puis-je faire ?
      A: Vous pouvez vous faire suivre une nouvelle copie du fichier via le menu "Configuration utilisateur & Gestion".
         Vous recevrez un nouveau message de notification que vous pourrez envoyer à votre destinataire par la poste ou un fax :-)
      
      Q: Je ne peux pas uploader de fichiers > 2 GB avec mon navigateur internet !?
      A: Tous les navigateurs web que je connais ont des bugs dans leur implémentation de HTML-FORM. La plupart du temps, la limite est de 2 GB, parfois 4 GB.
         Vous devez utiliser un client F*EX spécial pour uploader des fichiers > 2 GB, voir http://$HTTP_HOST$/tools.html
         Firefox 7 (et suivant) est une exception : F*EX contourne des failles dans l'implémentation de l'upload afin de pouvoir uploader des fichiers de n'importe quelle taille.
      
      Q: Mon téléchargement a été interrompu avant la fin. Puis-je reprendre le téléchargement là où il s'est arrêté ?
      A: F*EX support la reprise de téléchargement, mais votre client doit aussi le supporter.
         Firefox ne possède pas cette capacité HTTP, vous devez utiliser une autre client comme opera, wget ou fexget.
      
      Q: Mon upload a été interrompu avant la fin. Puis-je reprendre l'upload là où il s'est arrêté ?
      A: F*EX supporte la reprise d'upload, mais votre client doit aussi le supporter.
         Aucun navigateur web n'a cette capacité, vous devez utiliser un autre client comme fexsend, schwuppdiwupp ou F*IX,
         voir http://$HTTP_HOST$/tools.html
      
      Q: Mon nvaigateur web ne peut pas démarrer le client java F*IX, avec comme message d'erreur : "found no java runtime environment, cannot start F*IX upload applet"
      A: un plugin java pour votre navigateur est manquant. Sur Debian et Ubuntu, vous pouvez l'installer avec :
         sudo aptitude install sun-java6-plugin
      
      Q: Lorsque j'appuie sur [ESC] dans firefox, l'upload est annulé. Pourquoi ?
      A: C'est une fonctionnalité intégré à Firefox. ESC termine l'opération courante.
         Solution simple: ne pas appuyer sur ESC dans Firefox.
         Solution complexe: demander aux développeurs de Firefox d'ajouter la configuration du clavier.
      
      Q: Firefox 3 se bloque lors de l'upload d'un fichier et je ne vois pas la barre de progression ?
      A: C'est un bug connu dans Firefox 3.6.23. Solution: passer à Firefox 7.
      
      Q: Envoyer un fichier en tant qu'utilisateur F*EX est facile, mais comment recevoir des fichiers de personnes extérieures ?
      A: Vous pouvez les enregistrer comme sous-utilisateurs ou créer un group F*EX via le menu "Configuration utilisateur & Gestion"
      
      Q: Parfois je peux télécharger un fichier plus d'une fois, surtout lorsque je le fais rapidement. Est-ce que la fonction de suppression automatique est défectueuse ?
      A: Le serveur F*EX a un délai d'une minute après le premier téléchargement réussi pendant lequel le fichier reste disponible. Cela est nécessaire
      car certains "gestionnaires de téléchargements" lancent plusieurs téléchargements du même fichier à la fois. Sinon, ils afficheraient une erreur à l'utilisateur. Votre administrateur F*EX a laissé AUTODELETE=DELAY par défaut, ce qui signifie que le nettoyage automatique est appelé une fois par jour.

      Les utilisateurs avancés (use the source, Luke !) peuvent activer l'option "ne pas supprimer après téléchargement". Q: La rétentation par défaut est trop courte pour moi, j'ai besoin de plus. Comment puis-je l'augmenter ? A: Utilisez fexsend, demandez à votre fexmaster ou bien lisez le code source :-) Q: J'ai envoyé un second fichier avec le même nom, mais le destinataire n'a pas reçu deuxième message de confirmation. Pourquoi ? A: Un fichier avec le même nom et le même destinataire écrase le premier si il est toujours présent, un deuxième e-mail de notification pour un même fichier n'a pas tellement de sens. Q: Je ne peux pas télécharger des fichiers avec Internet Explorer, il me dit : "Cannot open Internet site". Que dois-je faire ? A: Utilisez Firefox ou tout autre navigateur compatible Internet, ce qui n'est pas le cas d'Internet Explorer. Cela fait parti des nombreux bugs d'Internet Explorer. fex-20160919/locale/french/htdocs/FAQ/user.html0000644000174700017470000000056212645025756017175 0ustar fexfex F*EX FAQ ##

      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      Ce document est périmé. Merci de consulter la FAQ anglaise

      << require "./faq.pl" or print $! >> fex-20160919/locale/french/lang.html0000644000174700017470000000002011713455631015224 0ustar fexfexfrançais fex-20160919/htdocs/0000755000174700017470000000000012770010176012200 5ustar fexfexfex-20160919/htdocs/download/0000755000174700017470000000000012770010176014007 5ustar fexfexfex-20160919/htdocs/download/fexsend0000755000174700017470000000000012770010173021175 1fex-20160919/bin/fexsendustar fexfexfex-20160919/htdocs/download/fexget0000755000174700017470000000000012770010173020651 1fex-20160919/bin/fexgetustar fexfexfex-20160919/htdocs/download/sexsend0000755000174700017470000000000012657123636021244 1fex-20160919/bin/sexsendustar fexfexfex-20160919/htdocs/download/sexget0000777000174700017470000000000012770010176020712 1fex-20160919/bin/sexgetustar fexfexfex-20160919/htdocs/download/sex.stream0000777000174700017470000000000012770010176021112 2:sexsend:sexget:ustar fexfexfex-20160919/htdocs/index.html0000644000174700017470000001222512770010175014176 0ustar fexfex F*EX - File EXchange

      F*EX - Frams' Fast File EXchange

      F*EX (Frams' Fast File EXchange) is a service to send big (large, huge, giant, ...) files from a user A to a user B.

      The sender uploads the file to the F*EX server using a WWW upload form and the recipient automatically gets a notification e-mail with a download-URL.

      You say:

      Why do I need another service for file transfer?!
      I have e-mail, ftp, ssh and even sendfile!

      I say:

      You still need F*EX :-)

      For example, you want to send your friend your last holiday video (1 GB). You have the following possibilities (and problems):

      • sending a DVD by postal service

        Out of the question - we live in the year <> after invention of the internet! Sending media (hardware) is for grandpas.

      • using e-mail

        Most e-mail servers have a limit of 10 MB per e-mail and a storage-quota of a few 100 MB per user or even less.

      • uucp

        Why not cuneiform writing on stone plates?

      • ssh

        You have your friends password or you are willing to give him yours - just for a file transfer?

      • ftp

        • Using which ftp server?
        • Using which account, which password?
        • You do not mind sending unencrypted passwords and files over the insecure internet?
        • Your proxy supports passive-ftp?
        • In case of anonymous ftp:
          • Does it allow 1 GB uploads?
          • Does it allow to delete the upload afterwards?
          • Who else can download your file?
          • Who else can delete your file?
          • You have to send your friend the download-URL, he has to inform you about the successful download, you have to delete it afterwards.
            All in all: a pain in the ass.

      • http

        • No default upload and user management - must be programmed
        • No auto-notification
        • No auto-deletion
        • Very few http servers can handle files greater than 2 GB

      • sendfile

        • You run UNIX and have sendfile installed?
        • Your recipient runs UNIX and has sendfile installed?
        • Neither you nor your recipient has a firewall blocking port 487?

      • commercial services like DropLoad, ALLPeers, YouSendIt, etc

        • What limit do they have (most: < 2 GB)?
        • What about security and privacy: will your files be save and secure?
        • Are they open source based or closed proprietary?
        • Are they accessible with any browser or do you need java, active-X, flash or other evil plugins?
        • Will they exist longer than a few months?
          (DropLoad, ALLPeers and drop.io already have terminated their business)

      If you have answered only once "no" to the questions above, then you need F*EX.

      Main features of F*EX

      • file transfer of virtually unlimited file size
      • recipient and sender only need an e-mail program and a web browser - of any kind, they do not have to install any software
      • RESEND and REGET for resuming after link failures at last sent byte
      • auto-notification of recipient
      • auto-deletion after download
      • auto-deletion after expiration date (default: <<$keep>> days)
      • full-users can create one time upload URLs for foreign users
      • full-users can create sub-users, who can send only to this full-user
      • full-users can create groups, an analogy to mailing lists, but for files
      • maintenance-free: no admin interaction necessary besides creating new F*EX accounts
      • Sending to multiple recipients needs storage on the server only once
      • F*EX is a HTTP web-service and needs no firewall-tunnels
      • support for streams, too
      • for real UNIX users, there are the shell programs fexsend and fexget to avoid annoying web browser usage
      • protocol and source-code free available

      Let's talk about SEX

      F*EX has a companion: Stream EXchange (SEX).

      You can imagine SEX as network wide UNIX pipes with a relay between. This can be useful for piping data from user A to user B where A and B cannot establish a direct connection, but both can connect by HTTP to the SEX server. For seamless integration into the UNIX tool chain, there are the shell-tools sexsend and sexget.

      Authentication is the same as with F*EX.

      Still questions?

      See the full feature list, the FAQ and the use cases.

      contact: fexmaster
      fex-20160919/htdocs/robots.txt0000644000174700017470000000003211602077055014246 0ustar fexfexUser-agent: * Disallow: / fex-20160919/htdocs/logo.jpg0000644000174700017470000003364010777060530013654 0ustar fexfexJFIFMCreated with GIMP CREATOR: XV Version 3.10af Quality = 75, Smoothing = 0 C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222@" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?( ( ( ( ( (+_ǧYIu2G2d@I*>/Z~(r{pE|j濘v=t|){s/fۀ~v g=}:sǹѮmu7 "G-s7τL5oY98=G=yVj2IuytZ-M^ b1T^߼_-kmcC p{^sy&˫mG TzƼOLo2  rRuvUjse\Kiw Mhw^I>jkK.RpȭM/cԠkf̱Мrq{u]uݵfK[@v}2>*;40xx~~4+J |rn GPO,N7b$:RF@7^N{JU/en:m6TUb0CyUHmaY3Z  Ѿ?X`_CVPӮ)NXZћ7P..q+xVml,v&Au'ߟ\")fc&ZlNB. =P= \QEyQEQEQEQEQEQEQEQEQEQEdY=vK)0&{ k׎]uo*~^g|K|; /Ya%E A8*H8kW?5QWܓ%G]Fs׌sa^\qRvЭII_SKӡt謠gh O$z4"JY*i '$=+sz*Vm3G_V+մ[jE{(pHKhaK }Ts_/kƠKwI+E2IiaG%$".qT+Ƭn~Ũ[]lʲm33Wm;4KBSH:##= :O2X_wFN=2;W]iGxeuÁ~x={·e?`s~rq]41{V}_R Wtz7?iwrA c8b3V`/E+/ij.6E|oCDk3ZfA:>zok8zcj̳k(8B(((((((((( Z&~ O>$o)-$ 2$!o ɻ>>8[s],U9#9HّԆVSA_5o*;PRUa`50b/'Z^dn3ٮyI!lᑾa3GlWK^aO[ܷ]Nނp2jZ, >Jd:X>O?v3CqzW+wҵ5n }{iq$7P>Rhz`y+۴B?zH VsdBq0Wc9˩{sܐCIg!^/;Q-!Oy={6HAש·%V:>쵉A + $QDE ~+#B!MIc#q_A1UJEF22xʜp[q[ӨlU`NVf\jRC ":$U5?N&%?5pe\?{+5XntdH*99;ɞjhwٕ] vݗqU#X58+%YFr֠hAq;]W-<[@iƛ䅹VPqON9]qA޾X[ ,D<=qN:tog pw nT׼pՠӼÑ_WV+[ICF9$AR[裊Lpߧ{]D,F!(!@=O5c/ֹkIKqbt&Y['=o?IJxg^ԡnW˹(Xd=!\ @~VyrcpXӯnԓi5f}-yiiCʛ?cڸ9}=+P_٘Io39ϯ]鿽/ qw|)xqZ: +eja3o&$0yNzV|=Է25I;erOsӯ^QrŬIs|3ݹq$V0ަ]EsZXnN1?isLV0st'9Ǖ:*+<%ˌ\fܭ0GɒM}H,/RIIDP_Qz(/1DZӏߴr=>^~%uSYe1- a7M^H1Ǽgʠ8 n36=Iǧfě`~nltj\ܥ ^@^,y8sҟ#+?t#/9=s=sA#$p独HE,rT)$O+{LYumf 8*@ֽƊDxc_?41s}i׋V<}Mv9W^E$y*폮*'J1w4VRVGhrɺks. OkT.@r=*d|N;GvҤ<%Swcx̹=p<agF•lu=;zz%ASj’ҢL@ʀ:~iwڪ nf'8}1@G =eC󘱹=?҅`Aܚ7Yj+8#$g3OpyU.Cv<haydE zz_C TP-j../z7ڕ;H mџBpByӾj٦K0\q/^:vUP] ^ 06[946`IdOYwqIcGwnA*]N ᅰ[S!\m$?cwi*FQ@UP0:qn[QTHQEQEQEQEW(G+c,G;sM&Bm-Yb{ ZOjN4( Z2ۉӧ. -2`1r$s=)F)b/=cmz.1ZȊ$nlnaڋm:XGĀd>W(1IKvQAZs((L -QEQEQEQEQ\_ٯSvwokiqϯNs55nơ}2uҰYfu&aA$cԅIaA,1i&i3*AgS;D`@6?tH%]Uƹj|5o[CC^HmUo/n9V;\s߷gR+oԆ@ՂW q#a s~:K&r>b]OEZ޿R;u` d8<#NV2NrFm1:v1-oNpFqm7A[MNP[*@mf@JAHNO pչE> 0G8@R6zGzi>t2\2˟8ڹy XGiʣ}?#I5{TZv8|tߐ. mH=OsۥeoZ{7M1M#/n:Wo3Y٬W釙1b]PɌzxY.i;^/R劽FVQm4r[#0uIzslįeDn m_kU?[#BW#$]pw24i"dJ!)3!ʻNn\’//c79g] #5w7okW ko"Ҭ_>.=r*Zqvպ!V 1>|c}snLן\$>bYFy s]ax<;f =8y>_*%"Fuprpx8y&j5~!V"gvK0zon:K#$hD?<K뫈ۓyۀ XIbz{[BяDJ+g1iѯ&CnW-.bI;H;w$.䕵 ±q6f'`}Ol84{3KH `HlYvx$|ư/`R$'bJw1Sߡ n{[X&1a 2I/vM{-.EԄ[pC(q8=TMJ >[Un|@wO][q:Uwst0@G88O< մ1dX,6H`H%'ߍcc_"yP`%PT }}kGH,!5,* ajK,W(#]̍2,k `݂T\w8| z3%r(u8A%R4KN"4HꋼS NsKڊ(((((((|Qq #n^ =+zC[ vO)` җ,3h4ej)6,NAAq(m7`Ӥ1.w\}p~-[>+xǝl猞̧#:FE1e.O.[t|,۞W3t7es_7A,P>`6wdG# =2E-CLY%cTx^ q⮲AuhK픕iN^̪GX$SY U%',rF<<}*φ-AOU9GCz7$n#&t-~)T?08$$5$fRDt/bP'9p÷OZr} 73"kt-М(-Cp41W5ô/<[!k{ɭd,w,e%V'$1##B.o\Y1 48;>TM d]Kgy/Ѯ0J&өgt50^xW$,emrUyᘁ>PƗ]CѯP1V(s``_Xa IFv10K<8ͻ>XzE1Rߟ~c\]Iogy<+\FQ vA ]jۆ4JQ+hij`z1nkB+K7[~-RRcwcIck~2Vp*m/ސ nlg<&اֻ:#DXTE UJuWQEQEQEQEQEQTu uMkz*8)(⺸ʐG4¹k`xc?Yµf^>s#{>gڰuv?W]g'c ={x3kW]g'c ?uv?K_>s"֥h:ϻ1O_ݾ1AwQ\a"W'3&jzGea dT-6:ȍnP}ⲂHG͑צ4PVm}̜{{MG ) n@,SeupiXa'3̠wPǬkQoi$Z'GGAuA8ZycׇWQRH}[rKf2[BNsRkx k$X=:fTXce}cW:p1QuQ^6ROH5-BԳ5OlgW@KK =TO3N3X(GunΤ=1q"DTctugvbjZPN4V#)SsA{55Tf[y?d<=|XJB+֯gj,GBN}/Hڮhh\V~^meү\8`83G?uv?W]g'c $_1Jqo_\NMwrH隩47F!#Yo,  0\g.K& r.۞x s*z\zV=w8kJKC!uyc%T10y9GNߝM&{u,utsK3Ex$bcsJ]rZlM<7\" G:[ 7Sk7mɎEv:PÚGyc`nv 'X`6zo\N9=k%a/%Qw=$ Rd?w!8uvo˿.~wy#4 Y'9f v!ze `tP;zm,Rn^M7aVDҌvG\ =[ (5 ( ( ( ( (21{=?m'yS9,Bh% bȝ8DZSUkAMWE֪1թv_ j?? >WԻ! 4kAMWE}jթvC-)@h2&(_R(eeo=LHը5oC]1cQI*?k=gVO A(j:9VE?LE%^كM o j?(^.e5_MZSUEZ>KmAMWG! 4QG֪R[SU]}OT>WԻռmyvtE ~QPT}JTit(2R =nun*E-(0((((((fex-20160919/htdocs/fex.png0000644000174700017470000001602412633530541013474 0ustar fexfexPNG  IHDRcRgAMA aPLTE_P0oHuV3hWCE,t='X0{B'g7%wdp?,H2]/|D.uC+p9$uD1l;#k@+k;)Q+`6"g2"o9)٬{gZ\EgQW0!g7 p?'~K2^6'V){lc3ۈQ:j4x@+M1H-b3"s;!]/R+pF3pxaxN:zL1Q+h@0H#{C!zwX<Ŭx[u<|fl^ԹlP}~xļfHE$mWrcS& MA6^(W(hpxhmMubA]W6~uŪ}ZNoL@gv|ǂϚngfv\V\>5fNK}nlȕaC<^rq^^xot攺ܖ塀íؙɌᚓ֩pj`formekК~ya~}bs\derYP[IDATh[_W&qDJ&d0X 65a"Ĭ&'B$H)քkVJYjtn{m׺{L‹U],p˙3'9@_^!ШPY Uj, ƨX ,̨~kY2-Phznt& _Nrs XJ$rTR<U #qBђ˄L^AqPT(48VI0rFDѫX1 ,ZJJm@l9Ae`eRY(ZBrkFBR UDY@»l dV9>\|, d:\ȫEH&hje adURL-EZ8aܤd Mr YsBaH1$ZA`z!{ цZnYȕ< 31ˆLMW<)_& QIIgE.`)| ~Τ)< E^E!o2$QR0's8 6˧BP0%*Mg$2%R4 lrerB,%EX Ȗјts/ /o|^', =h75PIir&g0(v~Ϧ~0%Ewbj#3`m~+Q5RQ8AGR1N -ٽ"Hf݆q*l8-J8>Gt+b5R$C0z1an-[~hEմN[M8_U5J*=ƒգ(i --(mm;tL5a[͘ʺ󋢟w4Ei5 4Т?݋.hm۶=RZmݸ~'pe_hFH5=->*f4dڸ2QTHܤg]Ց_HvwڃV>䋿tc&Bb+X3h*Rlpp0׶8}q& ,i jTp]yNwVyn}o,HfC}j/:jQ+/osA.b*[0AJ 'PcX[6}ZAnߗʥٻyic.wԻs&}mm|t * >oA𱀫:pkWL>ɧ&rW06[x[~1HGVgLz~1RmolxuϮ^WUQG<>/U\ۑHrwI@FڸqQ1d{mH  Dl66[E-F‘:xBDhŨ5{v몯CfMżc!BlQu |.3t Ns:O}ؚgKW_I'3|k0 zn]lrF<{ j۽7Kf{u;y>bmSjN^WElP<"jU(<.' a/Π&uۛnͦ7ևy\|/3|.L_8i6۝rB".\Zg ܢAN}?qxA P9A=Fޮ_oտvvvԛ|%[+z{{Z{9=X2L6MwdҙQW"U켣6jtFD㮍 FG4T+T ΘvM6]omZni~\EĨ8ؾ~}Ho&;{:\k|V[Bp7mۛڽb[}zsȮd'd|2 &OfREz}5*Mv^ u /Q&Y(B:f$nuRQg>)Y2f _>V &Z"5? E"᪪q~$b쥃];2@hG6 Zr 9tnGex.WLyAzj}~mE_\&J?:ZGGZzO'yt>BnFjk,9'`n{<Gu gQ'S[dS2 l MuQd@=k=jgJ՘ y6B1<1Op B}wopN0H&DK: ]`luun|li}^Pg`9랎$T Hi me`@W6yh8܎uQo#F<ѝE0?rXg`TR& I%O>)rzֺZw7K<\]O9; #:#Ke=z~$gG> صasut)#5:pe/^H̫KҜrѵelρM*?{m\;5yb#9D( {}832282bb)Wa f>V =ȏ2bRf㸱^;w\W(,!gz/>qh/ <76HAIh)|1}:-3NgA잝pllrm_o[u?~~polktgGq΀J BAA9 "\ka/npfSq_\v1[Τ_ٱn$2cYʒ{͜go8BeҮTS+ҥ*" =_77JH'37?6sg{Ivn{ 2 *~{֟;gOqyۓgGݦ+\bYOCGo-e N5;4tC'wep\zL.` (iȫw/ j=`/|hͽ{?(z N?t𭁱##'g/g򒗀1>=t5GzthxpdXw̤Z Q@_wP_NgdFX=7p284tXS_} /)ּz,385ס+SC'W?`>3cI^8m[޵O65s_MY)rphpz3)p7rh a 龽xЭ? DkBpJ~O.W,z(n]8;7Na9#K7W?!]# ߽z[¬4ccS᛺IՕú-#{>N*d<|qa`׮GEb ʜgi͖:=>8S˶qA`l<9ީ%ĉsa_I_ҴX/#Uȩ>przcּF> k [;X[ 0>cst :[~1=:vbIHmfLoKpFь88Ae☾ iKnn?0POFIχ{@1 =vuӜJxxNsqUUk>oH2J{x٘$ɮǿd܋#>Xz^iqhtbZ|];c+!ۀ9_|p8Ǡ\8VUeW5Ƨ*Q[xXMׇ;5bl̋ "1+MsӃGx#5a%Yv>Tr.nwOAz%$ӠXdvKuU u‘eFnRrxATS,2W g9O֪SrVb% 6O.}ow$SA*|1FR qh>.SS. {d$ 89?5 Op.7_W]p#5$˴r}8_SPBQ7.8`e8Hu;_Xi#VVٞC6y8dߎ vK+{ؼM=Kqёb2@-G57r^9z8`@8 w$Sh pXs9<V\ltWIw뺰X OlЄAݸ>+"!Ohv8c7Wr\,ܪ7Gq:` frNzwQEnbG4Kki9hg(^1J)=R4x$9dGs4F9?Lžl傌9vp푚Ҷ,,fnB4[,ŁrT``!b = */.b}B1Z\4Hpzv◳c_m ^Q>n8Ay88|CF [lm@|R :+O>u1p38lHWA[F?+1n&[rX{|" F~i 1,Y7rDŃ9}ޛ8/`z]՛ݜ3|TɥEр-١BOlm<3#鹉 {tJ)O4Š($*ز$(MYp39: Bw^>u)wa7es]M=ݐ\ X3۔IRG˃ξl$#lc8!r˖X =/H$trғ):Uk-sF (I#hZ+ģi3ۅ2&f͑`̹ r1#I'$s![rvg~YT4oᘁw] ~9)%B7et\y'yNSX\:? ksd#tsT/GGS*IH`{@`;tn` 'Cz4-g$F?|>CFpx!l8utC3}2LmA $2rhF#o l%İH} \mPH3]Kqw1i*Aۜl.ZIm յr7Mm0<ōPF@jABqiy,,[/+I@`ep>L$ֽed1g~>prcH%柧Gkm C}'g$O$i77pӜ~5,fj\%76.X$! Քs{T+erlg( ŷ 9{f ]ZD7-S U9^Hy q3Dj8+rrkc)MGɄ[*ZHmdmvTwWi4'$:t $mO;n #'ɬtޭqsu,yrfq!ܥ _-@!X B,`In^U)rBVF"Ɗ uW)QEQESDK!U9%dEQ{MKQEi-H-7/G#o.?*_**>HG\TU:?$XĄ~EqFDQ)>^FٝqRTQB{#o.?*_*G\TUS.HGt,?*_*[F!b?ڕ(KPov!*$Lڠf͝ `) ((fex-20160919/htdocs/action-fex-camel.gif0000644000174700017470000010160211406365450016006 0ustar fexfexGIF89a@,?"J&S,V*X+X,S-^/[2\2$a2e0!a3 g1h3$e6#b8#j6g7k5 P?6c8*h8&l;#p9$k;)o9)u<t@Ȁ@ !@1|[cC&,!03})_μУ3GHu'Im   4`\~ꌙOel@&W!` 0hP",>9h(,3d 4  8؀#!`PwtSL>Xf\vXs 4,d@ 0 X1ϗF Ё0d@ ,&PidGhh 7Tx{ЃHHy80 Whrh.Ё l`K8 xQchPB T+D@eH }HҐ40As1P_* {uRƈ0B PЀ@&<`!JL` : ;@|ޮF }<f, *00  @ 0 HWD/D$DHDBVPq"tGZØ@0`P 4L pMHT?QѼ N@D1& 0Mt #L:M@' 4/y -xH'@c& B C,bhr E ]zhFoAZ D z) _&D*P Q5Qč.fpl3t-SM7 읁|;Q4H1"0&{PhgN%obD\+ HsՄ( Hu31Fc0@ik8'$q1@P L]:/@A:wt [ 9Ў @M`ⵀlT& u; "np#! A qy2H+;ɞ \_Pw1Ёה 4`N`HbJ!!62q04:d!0.|.B ПA1htd7Q=K5QnnzȴCK7YdVpI< ]k }d/9oE6"|~sr F RH6,UA2h( @'746H'p-]+2[Vo^u[h\ pm sKMp UqS@3(3pL_nE`u7hv^1@#2c&sJ%`e((0JGb{4c^ vssxQa#)2>'0 #p3P'6bW"@5`k5h1e!Ƕ#C8Zm2OP*'7c@dIVaV hUd%B M`gxsb͐cO4 P€ X(p yUmq ^Q`  ȅQ)*h$ @ &PnYw*p^ `HHL"0 uY^$[~1*Jos^7Pu 0^ ]a`Q n`WxyBz* @WVa7' js(uQus/q&WK1 ryi ]M&){@ 5P:t3RwXAiS/#$d2PX*#MTxR2U'bbapiK0ay`^p9` 2rx0qiq ψyx a'Qcq`(`^`0UE&W%W]0NdsJ`-2]j_1]vڥ!zgR|]DB-M&&}bG XT &Ԅ$&cA"' M8 22 7nq`eB0 D"W4hV^i)Qpu`Pas@ag\tgɞvW0@[+'{E73d)0Bu P5B-`B2B"ÁGU/,`!bJ!:R pV2КVBVp14r{*2+G${V@jMM J2 zs_JQayyfaisd~gY8`|*]ߑta @+ (R7H'28cdraW𴢿Wep%, VWǤ[H"/" 0  7047: iV٦ @Wm4Yq3p^&4  }huRU'?f@; fkfW'6G5P5 ]|+3b+P5 GU¿ۃpHjmd%6`4\(BagyVw>avyajqy7>h}5W(`pp2(YSRPpk `) 0* s"JQE`*3sS¿\La3;4__Ǵi9pQɞesQ`s~kHmQ@p 1G6$f"2]Db+A$42 6 u|1J0 +gt3B$pLlne2ĒK=Qsg@zJqfs`ENG2l9xSv@&δ8 ,|  'aS7= g@QTa>ax28, n'W&5&a01`=Vur'Lud J QFh%Ȟ_ڻs2߹jIEW;wM2*P{uPM&#(3`7de @V+aMj L18pE]s_7疽sys v\}\sn~c"@o 'q/_U#7!@q#UlP s|`Kafz\KՖQmv\J p(o iE2Xzy23 *xC` Ь\pEky' Kp\:mK\QhdV\UAy$@8:O!'@0 `Yv&`g3g > p m<'Wэ :s=wgjO jiթ x@"#:RY ,eT(&#{b!0c\La1lY)x^Y  s9o% nmQp\y ( )0)0>ħ4Ĝ ϻ]L<,.APk}| p 0 ɀ KrQyȞNacsa]#| ` = _b# q|L܃F@! @ @ 뛐 `a\JQy ` <6DS .8;X0`bo0|z=Kqΰ ` SHp @ } p  0쩆 Mm6o @ (? } ~@T@kdpF6`qJd@ p@4plpl[]Q ِ Y `Q0wQS]p n  P P z`ZA=ӦC"C 1=  O 0 p  ` nmuԝ'Wn1HҠAŠRTBŮ);f R IoL3?R0R<-~\cR˙-cΔy_~:glSPEk3:Ԝ{3gnZdd"GO)^ТI&*ݖtII .@( I]1hl,yd -\pI& R ΠI*N[L[QFmS:uƒG-AT1D[ӼJc l-6 RH<6&Ls ٭K +PTŐ1[kFB%bzqj(p6 /$ QsQR?cL.9o*&lBc[1QDO&$O$4P6d]chh>6 gYi{|Z[ >iCM<1TegqpǜV(aUxc9@^qSiLeGV*eKDKV#V;ŠAxJPƍ4jihd,ؐ#3X!)~q{`gm9I;:[ [@5GuV(1cL C! %a@UF\41-_DH<1а"8" _Xqc/A$dEJ(GyRGoi]}3> %:6j'sqb!U\h&^DaZKD&I)dIe8 1@8Bcd,dP>D6#YrA? pq!rC_&" tЉB{!ў]1ǟ|t)g*mgLl@NiNdB$4 3fBC&"-bL7Ic.%*sNsvaYQEpIzP9q] 6v' _AE) mxE1 1x/Z" Q!`*`,!:\Gmc*@oP"F w8ChT8m<hɠf\kVj^6کwt>arPpoJ8^\b@ 2 !7kC2p +erH@*@> yН< Vx蠅6%QuE)gCNMZayc6<4D.<ޑ6A p)/N1MaH2 >j/i!C!p8X`D(aL@W(2P(B2qvt,9bP*j Y@I;a-1, mp06Ce! a6'o]4a"PEj&}`C% fe |M8&ԏu` d B,76Dgtax1Y{@F/Q~_Ss4PPV_1{7rpT1JBP/=cFT]#9r%X%Qg=c|{xF\hdmpP<SGl*́FM8>INs\i<fM܅:Dm@qp(KBp?A r1!s;<ԓ!h/JaDDa3XF%/2 )nSC,a I@7TEqCA\}r1Am4e8'X~؄iiւGзmCiK+ ɰ&0xG¡jb0 P t $Na<p,?` f'3h뵁q$= eX(luZB֡)7馦68هN'ZH'JNariЅPP*GpN(lSOhMN=(B0lo0,6|D/Ry~xd0M8e^HA8P`ށDuȜP"#@ZZl؄g`SqЄadP> HhdOPTkK_`MPJPgxbX  Ǔ4ɹzЦ4c6B;jJ[0ONx{`C&jЄb؆d=n.L[Kf@_XKpSL;CIP?Xg$@bx,<{J1Oo+{HH[}HiJTHOoxrh@G Rp{,bbN`L`g`J`n:M]Hg)\QN\SL;lJc` *bC{Gd I9v]e?(QHgȆ{px>b{~ԟmX6vYn]0;?AIMO؄TmcFHIjkLA,`5 - Pć&v;ucPSOp0IKZS8k`~z *gm Qr yptmV,r^`]8I=[^N@?\fnJeہ؅5j)D=|k@dr]0Cxi<C!QP4bk#| }p8qp؇V6ʛQAxf\IM̠wuzhHH>(d%`*X@}uVl &g.AF0S&k ӖҸkVhvniІZ]p3dd0S0 gy2ЂR:u&(WW]? Y9`x={ܷdXaON^(lXM&J&bl:hJp]qK(u+[]NE>(GcȖȸDsGri(Sp \EUІ\z|gVg Y:ͦ/eU1bPMҦ]ywX{:pmheE 7Y)k2i9p0 3CFpJ@UHeOBj x o:YHA#r]𐝸 sK&} m+꥜TMW%cڅp/XtrMUM8# رЉb9wȖ*V؅rU}\d%)34$ vb;I zt!fE6u17~ЇfR|T0-y2{a43bЮckiU9ǂ r?nZ`zrRPNpЃ2kg\qkgh*cm2op+n #maYp&Y'qyjyhck  %pXx dh%wb"ONN|/7c`&xp0ߝphspچ24m +k`ޡҠpg`. `uVo 7Zoyށgc| aG1~7?g'V鷐! ,"/ H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝ+7fҥGwjEC2Ȑ D euZJ &JL@PD !DXi>@Ȁ@ !@1|[cC&,!03})_μУ3GHu'Im   4`\~ꌙOel@&W!` 0hP",>9h(,3d 4  8؀#!`PwtSL>Xf\vXs 4,d@ 0 X1ϗF Ё0d@ ,&PidGhh 7Tx{ЃHHy80 Whrh.Ё l`K8 xQchPB T+D@eH }HҐ40As1P_* {uRƈ0B PЀ@&<`!JL` : ;@|ޮF }<f, *00  @ 0 HWD/D$DHDBVPq"tGZØ@0`P 4L pMHT?QѼ N@D1& 0Mt #L:M@' 4/y -xH'@c& B C,bhr E ]zhFoAZ D z) _&D*P Q5Qč.fpl3t-SM7 읁|;Q4H1"0&{PhgN%obD\+ HsՄ( Hu31Fc0@ik8'$q1@P L]:/@A:wt [ 9Ў @M`ⵀlT& u; "np#! A qy2H+;ɞ \_Pw1Ёה 4`N`HbJ!!62q04:d!0.|.B ПA1htd7Q=K5QnnzȴCK7YdVpI< ]k }d/9oE6"|~sr F RH6,UA2h( @'746H'p-]+2[Vo^u[h\ pm sKMp UqS@3(3pL_nE`u7hv^1@#2c&sJ%`e((0JGb{4c^ vssxQa#)2>'0 #p3P'6bW"@5`k5h1e!Ƕ#C8Zm2OP*'7c@dIVaV hUd%B M`gxsb͐cO4 P€ X(p yUmq ^Q`  ȅQ)*h$ @ &PnYw*p^ `HHL"0 uY^$[~1*Jos^7Pu 0^ ]a`Q n`WxyBz* @WVa7' js(uQus/q&WK1 ryi ]M&){@ 5P:t3RwXAiS/#$d2PX*#MTxR2U'bbapiK0ay`^p9` 2rx0qiq ψyx a'Qcq`(`^`0UE&W%W]0NdsJ`-2]j_1]vڥ!zgR|]DB-M&&}bG XT &Ԅ$&cA"' M8 22 7nq`eB0 D"W4hV^i)Qpu`Pas@ag\tgɞvW0@[+'{E73d)0Bu P5B-`B2B"ÁGU/,`!bJ!:R pV2КVBVp14r{*2+G${V@jMM J2 zs_JQayyfaisd~gY8`|*]ߑta @+ (R7H'28cdraW𴢿Wep%, VWǤ[H"/" 0  7047: iV٦ @Wm4Yq3p^&4  }huRU'?f@; fkfW'6G5P5 ]|+3b+P5 GU¿ۃpHjmd%6`4\(BagyVw>avyajqy7>h}5W(`pp2(YSRPpk `) 0* s"JQE`*3sS¿\La3;4__Ǵi9pQɞesQ`s~kHmQ@p 1G6$f"2]Db+A$42 6 u|1J0 +gt3B$pLlne2ĒK=Qsg@zJqfs`ENG2l9xSv@&δ8 ,|  'aS7= g@QTa>ax28, n'W&5&a01`=Vur'Lud J QFh%Ȟ_ڻs2߹jIEW;wM2*P{uPM&#(3`7de @V+aMj L18pE]s_7疽sys v\}\sn~c"@o 'q/_U#7!@q#UlP s|`Kafz\KՖQmv\J p(o iE2Xzy23 *xC` Ь\pEky' Kp\:mK\QhdV\UAy$@8:O!'@0 `Yv&`g3g wKEQэ :s=wgjO jiթ x@"#:RY ,eT(&#{b!0c\La1h@P  0 P p s9o% nmQp\y A%[D2 NMeT˳2 @ [r 0 p Ȁ 0  ŎȞNacsa]#,W p+ZlUKOb# q|L܃F>@ڠ | P P rw6gF~a yPIks 0 m<FR@RPZ+= [dbo0|z=e p ` ` P S `|OkQۚVٚ 0 k@TpdtA)Jb@ @<)` p 0 P xQ=QJ;s)Wu p 0 i ,Y>H0y@kʓ-"A I4eK'93ʙ=}gP#i<|)S7QpS$]H%KR IWM^hHު$I%_.5ĈQ[+4hɒb$BĵCFCoEYfϕ8_%h֭KO:{Z>s™&ٯ_Ȑ=6XSNխ+T IuFҔ7;ر4F` d' *dhe ,URUãn^&Ղb#tB m*(uܡ] u!'oiG(D.$\f\LJOFSLHD DM<$L$HH8pK FĈ" 19K2R/Q4[" +Ұ4Q-+6AƗI% c >დ3X=yF@@@V9ԧ4TPB) *{~xoMwIDF%Z2A8PN%a$DNQeO0C 4"(ru4BID ET`B$ÒKÑ?i| ywXjx]Uz'pq6zgcn!S aI4idIn#1 4 ;$`#0 2lAK.QDQ%j@"Yhb|C;s0]XͥrsԦJU>&{f_sW}d&i ƔCIzO$aIFI4 »d(a iVXBR'Ȑ0LX)rQ[B2@2`u˰=AOJJd( .t=H$L#_p%}k-| \$(5t! 9er):F\BWPȘ%AB0R=aJ"f`BAЀ2m<01Ї?pf4(jnbO rI$;?,Pe$# %ԡnېF8F4@P1It ~B؅.ljE 80a  d 9w7p( І^a-NVE1ltb<@gxDiZr]a (!а7xx g0ІC$P,DHCrv!VDp2ܡ 9Aci5A ccI|KT-xbzD;XA{l=Z;ꤠlmk1 PB2*7 pC.G8a sp:p9 -.h]``,;C"9b xFG'я{hi1 hc+n^؅Za5ރo +(k'0%z5qԺ mJ>|3,uɀf>́F:v<]ڇ6ъUcDD=aH% |XX$,q@SI0E(( tlC 8a|lsқq)F7> ?>lAĩ+ c۸p'|\㡎qF4qsTD4r@ P#D=ᎦrsD}8RPbC0iP0,? ᐇ? r@k2ݕ(> */>b؆3N$F!JdG;:I%6 6$L%Vn.NP; ӘF2p BЄ0A ztT;ԑ{4$}dz]L2j@-yy@)dq GF*6#lE%04X"ġ KdXF$6l@+%|'j9rXCFjggb;Xqo1zO+>~h#l ?z0 MM5|-bl @x(E97i,YڧBU 8<#K-*jaID"T>HaJ |Np~| #†`UJQȄBQ` z8'{bJ8K0}pZH/(nQG`MHh[MFkNpOh0K>0gH:g92HH{x0xsr`N qmh~hvȆMeЅJkmzwyr cD+p8i(#eЄQli_>`DOce8LNd9^x$ c ؁CY#s0{9ob؅p] ~p؆}`*n?XBsEx,{ k~'EGNV0kV8SX/TcSTFxIbMȅOhF'i]g>Bc g{k? qqpca9G`_0E}0>gGsǫ9]76c SgSqa@_>8QAZiI0I@U_I:RІ<pCig |pN`>J1o ]0cSЅM_`b7}wPy'g4B>ϸ.~`zɹbhЄ`h?Ȇ@0\@U@[@KH\A^pSG0Bx-r.46#~36l T@C~Pf@P@X؄”CFzhl.bL ̶z cmapiKnHdPNc8iTXHjٴ_Z@heLDP9nڹlfN {2FxST@Q Cty0l (x{i臽L<`TpYTxJ\!L>2cOhiY-Yxtw>x{o$q?(<"Ļy9g0*x Am"DBgFu'VHѤU`MI`ZiTJ`,Ei l@J`I(:XdH:o0R{Xzهbp|5|`2Kt]U m(7vgKm|gԵSp}مipzkOc;RJf i2rh}g`t>d(>X\L| uh~(w؆ac@iS?8Aa`jz4g0aGs0iעs|g:k8qwix?[0rKPk]mІ!g5ZP73yDwq0J˯]XXNK?PalHs1@Jv'b91Zq ڂ:%݇pgцmc{Hnbv?Kryou]xpJІt5ZwCnji Kan_LZ Ն\*DUDP2jVݨ^Hu>KAhL~]xO0zc؇82g ӔdO MNpz_OU@IeW夛p|(+|_$O݅Շ̚Nh}z]Wpx~ʼ$ |0?E(d>0A<;PP@PSȆ {P+o8~RF3aEyWzD+d%pg  #%+qU$(J_-p 48hK`iTr4|% `070XSV&H)@u-j}cbp} M7^5PDhdپ|n`@}4s D0m}KS^{# ZF!wئ{x]}y1p_jN +,pf@\PM`q8A}rm d>sq{0es6ڟZ&Wk/脇rm05o ,o G;;Ь`%_(Q<1?q416⚴xxUjg=k0i9[~v ~I複Egt'&^peהIH?dmZXlre >D":# ~1K!s˒ЍϠmspi{CPlXiA82jQB_p-[m=nMl| 4BečեsЗC2Fye=r+^@XmdЅHI[HlkxI^=f.Z~hYm:}pzh5 J^lJ_X,J0l&i{mCpgz8Wa&ps5|:+Q|Xi>' )r5,: _KVz\Loƥ?˰9s}k~=&?sxVb =&F쬺q:}rBo'@O,XOɃfRug8NpeEs@yD9wfWM]u ,oȗw{7agFܛ3ngX>hg*WRpVcW{z%WJMGd`V\G{qFa1p'<&5 u@;q7;I7ہ$~^ڨ^GsT:JkJ4Hy8=ᓠ a${ p|!L7m }mh+J> Y|Wgb@mQ!{ ^b`x VH.)YmNZ6-Jwӳ8Au='{nz/{W*[ءMIwVhgcXڳ{ntvbP)X4r:ɧʷ̏?hN|ɏ'7 |cVJP@Ȁ@ !@1|[cC&,!03})_μУ3GHu'Im   4`\~ꌙOel@&W!` 0hP",>9h(,3d 4  8؀#!`PwtSL>Xf\vXs 4,d@ 0 X1ϗF Ё0d@ ,&PidGhh 7Tx{ЃHHy80 Whrh.Ё l`K8 xQchPB T+D@eH }HҐ40As1P_* {uRƈ0B PЀ@&<`!JL` : ;@|ޮF }<f, *00  @ 0 HWD/D$DHDBVPq"tGZØ@0`P 4L pMHT?QѼ N@D1& 0Mt #L:M@' 4/y -xH'@c& B C,bhr E ]zhFoAZ D z) _&D*P Q5Qč.fpl3t-SM7 읁|;Q4H1"0&{PhgN%obD\+ HsՄ( Hu31Fc0@ik8'$q1@P L]:/@A:wt [ 9Ў @M`ⵀlT& u; "np#! A qy2H+;ɞ \_Pw1Ёה 4`N`HbJ!!62q04:d!0.|.B ПA1htd7Q=K5QnnzȴCK7YdVpI< ]k }d/9oE6"|~sr F RH6,UA2h( @'746H'p-]+2[Vo^u[h\ pm sKMp UqS@3(3pL_nE`u7hv^1@#2c&sJ%`e((0JGb{4c^ vssxQa#)2>'0 #p3P'6bW"@5`k5h1e!Ƕ#C8Zm2OP*'7c@dIVaV hUd%B M`gxsb͐cO4 P€ X(p yUmq ^Q`  ȅQ)*h$ @ &PnYw*p^ `HHL"0 uY^$[~1*Jos^7Pu 0^ ]a`Q n`WxyBz* @WVa7' js(uQus/q&WK1 ryi ]M&){@ 5P:t3RwXAiS/#$d2PX*#MTxR2U'bbapiK0ay`^p9` 2rx0qiq ψyx a'Qcq`(`^`0UE&W%W]0NdsJ`-2]j_1]vڥ!zgR|]DB-M&&}bG XT &Ԅ$&cA"' M8 22 7nq`eB0 D"W4hV^i)Qpu`Pas@ag\tgɞvW0@[+'{E73d)0Bu P5B-`B2B"ÁGU/,`!bJ!:R pV2КVBVp14r{*2+G${V@jMM J2 zs_JQayyfaisd~gY8`|*]ߑta @+ (R7H'28cdraW𴢿Wep%, VWǤ[H"/" 0  7047: iV٦ @Wm4Yq3p^&4  }huRU'?f@; fkfW'6G5P5 ]|+3b+P5 GU¿ۃpHjmd%6`4\(BagyVw>avyajqy7>h}5W(`pp2(YSRPpk `) 0* s"JQE`*3sS¿\La3;4__Ǵi9pQɞesQ`s~kHmQ@p 1G6$f"2]Db+A$42 6 u|1J0 +gt3B$pLlne2ĒK=Qsg@zJqfs`ENG2l9xSv@&δ8 ,|  'aS7= g@QTa>ax28, n'W&5&a01`=Vur'Lud J QFh%Ȟ_ڻs2߹jIEW;wM2*P{uPM&#(3`7de @V+aMj L18pE]s_7疽sys v\}\sn~c"@o 'q/_U#7!@q#UlP s|`Kafz\KՖQmv\J p(o iE2Xzy23 *xC` Ь\pEky' Kp\:mK\QhdV\UAy$@8:O!'@0 `Yv&`g3g wKEQэ :s=wgjO jiթ x@"#:RY ,eT(&#{b!0c\La1h L U0ǝSV% yjǝWA MTC|N+P!NMeT˳2>URGn ǵ+zQ x)6?U=‡`BTA_b# q|L܃FBfp P лdXm1刬3n. c`@+p ~@P ̒ac8Q|NkQۚ&Zf "@=3bJdJ K} lQ` P P;suS]ruQ k@R*`+Pz I@w{mj>4 BP[V 0Cjq W2p ~ ԉVGyu`U- =7~ 0 L? k@6_ N sF^3.ij6?`"@ PNž  p 0 ~H$M$ I$I $(AM$AThP@2eJ%ɓ%SA٦K#*P!%di?~;ӧ?EIthQ@6=4QU^5 t)|3l*0u_ϞIFX.Qr4 PH F0R_O-.TPR b}NFIBzA3؄@> TpfSLIEJ8Dk!'5+" +Ұ.9P6|YI%؂%&vGCopyɷݞʪPQ7}@\Q`^"d%Nd)Q QF1i$K*S&ADL +#,hB>3EQP8ڐ"vh{om D w[7Fw}̹5 I> eA!CSBFQSR@&YHL(8B &+HJ(Z$)e,zHŒB`C8s|!sf|M6.4jpS47E%UL/ qpPD-a[>!-T@C'D }0= u@N-vQ5wHUK^.7(mgG=6q 6a]T$fZXt yG }8#i01_Eه iy = {<0gK:",&Q ftq~ @pc@?A|<Û .Vhp|$X؅;Tq4P)6a# .jf؃J)?'`i5F;͎XF/Rq NL"4e3;AuPGʪdc ]82pл>Rȭ38E &j@3"GR! }R)S C(f٫=bB~H$, T BňF*|QET8< b܃hڕq4UCUG!0"Т>z.ݓ6 hP5oX`G+,kvoVˡN6M lEv=gPƸhLb}(R[Ѓ 4x0Mp; P>$t?Z}lc8*Pq_c&2QmP:Jc/>x(/4MQVTiNsG S¹n!>M?a HʃO4=2jN'@Z(aܴ+.C?;AkΚpچ0}rqchP@Ybl?Pr0Bh-/ 3YJY>EmL[dKKf*r]?`'fm(O!uD~Rxmz0| 9kEw@NOQ \Tw{,-}І׋zȶmH)Yhck\F]%^HT]Q_(HJgp`c8آ]G :?[q1.wpm}pcGrJI`Z@Zan-B*Kp h)pdX>@^Oi8F``T(a8HxF0IWPPm܅L(VT=Vx *J[6svgkhcXBf@$Wd$~ H:.SYЀ50, gZbIOhN,\X@ShB؁d!pb؅wyD".gzhyVs͢+qJJhxAʤKˤ,p? PR($pIbxIL8AzH0z0|sGz}G8룆+0>6Z,3hvRP\9?A#.qa{h0p8R&4Ju/V;=c ~@3Ȃx6PFS\O}$rنn SmNxjg&?_J@2*{A6r Թzن~(1rX J"qddgXK8yh|cqr!㉡vH>0ZXQH8mnmlKDDmpbU)Ђ堁):Ѐoحz%{37A$zJ6L:oZ@m@_f`e[G8k8R!ħ'κ6̢xHw8p}pV$ko,> ̓ NOL22{p Dza\Є@0n?c-sXH=ۀPb0vx᪩~`m@+6x$g؅Nyy(1ٷn"JM";KƝޅp9x,Ȃ7xCNƤ"Ko\pLp؅~Uo0`L?(Tw =hbluh?nyQw?o&| qEoȓNĤq=uBJcp:qG2s)Lb>qA骋&W=Z,.4b@.,׻Ҵ&wV5`HbߖM_ 5o7S3:Sc]H_w:nm913)%H~]HWJ;6;7i3!cxp(iyBAr0i3ni$9!mP5bhk.sv6Xu?bwL0=60=.i8RKA2R]e# >!y |)z(x0M5$ }`g}=&mic9C Ö*cZL_(pp$R)fp(`JG` wclmv3fɒ7GytI],pJ`"4)B(C $HtVHg)v v=Ϭpv)61Fu?'7'?؅N؅g R` `p P$G''~{J{wjNHbJiZ3؝D|Y'mJ؅Xh^_cXרX_Zg!J*‹G!ԯ,ԙw und?|+/GA^bM+~Vwr50X'~G͢m jM~k ܶ-^?#Jh"ƌ7r쨑:cƈ,9$ʔ*Wcrd? .zXB #` (LF\:S+bĞ tΜ;zfex
      and create some users with fac, example:
           /home/fex/bin/fac -u memyselfandi@my.do.main secret-auth-id
         
      Then log in using the web interface: http://YOURFEXSERVER/ ... and join the F*EX mailing list! ☺ https://listserv.uni-stuttgart.de/mailman/listinfo/fex Q: What is /home/fex/bin/fac and /home/fex/cgi-bin/fac ? A: fac stands for F*EX Admin Control /home/fex/bin/fac is the (full) CLI version /home/fex/cgi-bin/fac is the (restricted) web version. You have to call it with your webbrowser: http://YOURFEXSERVER/fac Q: F*EX is not working at all! I cannot connect to it with my web browser! A: Check your routing, ipfilters and firewall setup. Also check if xinetd is running. If it is linked with tcp-wrapper, configure it correctly (hosts.allow). /etc/xinetd.d/fex should not contain a line "only_from" F*EX needs port 80/tcp for HTTP and optionally port 443/tcp for HTTPS. Test the connection with: telnet YOURFEXSERVER 80 Q: What is the difference between all these user types (full, sub, group, external, ...)? A: See http://fex.rus.uni-stuttgart.de/users.html Q: How can I integrate F*EX in the existing user management at my site? A: F*EX has several authentification modules: local, RADIUS, LDAP, mailman and POP. For the last 4 please contact Q: Can I make an alias address for an user? A: F*EX users are defined by a directory in the spool. Therefore execute: cd /home/fex/spool ln -s user@do.main alias@other.address Now the user is known as user@do.main and alias@other.address Q: I want that all my local users can use F*EX. How? A: Let them register themselves with http://YOURFEXSERVER/fur You have to edit /home/fex/lib/fex.ph and set (example):
           @local_hosts = qw(127.0.0.1 10.10.100.0-10.10.255.255);
           @local_domains = qw(flupp.org ulm.sub.net);
         
      Or you can allow anonymous upload for your LAN users with fex.ph variable @anonymous_upload Example:
           @anonymous_upload = qw(10.10.100.0-10.10.200.255 129.69.1.11);
         
      (Of course you have to use your real local hosts/networks!) Q: I want that external users can fex to my local users. How? A: Let them register themselves with http://YOURFEXSERVER/fur You have to edit /home/fex/lib/fex.ph and set (example):
           # your local receiving domains
           @local_rdomains = qw(flupp.org *.flupp.org);
      
           # your local receiving hosts
           @local_rhosts = qw(127.0.0.1 129.69.0.0-129.69.255.255 176.9.84.26);
         
      Or you can manually create a restricted external user with (example):
           /home/fex/bin/fac -u framstag@rus.uni-stuttgart.de hoppla
           /home/fex/bin/fac -R framstag@rus.uni-stuttgart.de
         
      Q: How can I change user settings like quota, restrictions or keep time? A: Use /home/fex/bin/fac Q: How can I delete or temporarly disable a user? A: Use /home/fex/bin/fac Q: I have BIG files already on the fexserver host. Can I upload just a link instead of the whole file? A: Set in fex.ph: @file_link_dirs = qw(/directory/with/big/files);

      and use:

      fexsend -/ /directory/with/big/files/BIG.file recipient@wherever Q: I want the Bcc mails to fex (admin user) to be sent to another address. A: Set variable $bcc in /home/fex/lib/fex.ph Q: My users want to fex to mailing lists, but after first download the file is no more available!? A: Add the mailing list address to @mailing_list in /home/fex/lib/fex.ph This allows multiple downloads. Q: I need more security! How can I enable (https) encryption? A: Read doc/SSL and also look for "fop_auth" in doc/concept (doc is a local directory in your installation or online http://fex.belwue.de/doc/) For email encryption see http://fex.belwue.de/gpg.html Q: I need a corporate identity look. How can I configure F*EX in this way? A: * See variable @H1_extra in /home/fex/lib/fex.ph and you can add HTML code to /home/fex/htdocs/header.html * See /home/fex/htdocs/fup_template.html, modify it to your needs and use it as your start-page. * Contact http://www.nepustil.net/ if you need more customization. Q: F*EX is too complicated for my tie users. I need a simplified upload form. A: See /home/fex/htdocs/fup_template.html and /home/fex/htdocs/sup.html or use public upload, see http://fex.belwue.de/usecases/foreign.html Q: F*EX is still too complicated! I need something more simplified. A: Try http://fex.belwue.de/fstools/woos.html or use F*EX mail (see next question). Q: Can I integrate F*EX in my users MUAs (thunderbird, outlook, etc)? A: See http://fex.belwue.de/usecases/BIGMAIL.html Q: Can I get a localized version in my native languange? A: With your help, yes. Please contact Q: I need ACLs for group access, versioning, a file browser and integration in my local file system. A: This is beyond the scope of F*EX, which is designed for efficient file transfer only. Q: Feature/design XY is missing. A: Contact the author Q: How can I get fup as start page? A: Execute: cd /home/fex/cgi-bin ln -s fup login Q: How can I use my own local FAQ? A: Put your FAQ into file /home/fex/htdocs/FAQ/local.faq and execute: cd /home/fex/htdocs/FAQ ln -sf local.html index.html fex-20160919/htdocs/FAQ/admin.html0000644000174700017470000000035512770001121014556 0ustar fexfex F*EX FAQ ## << do "./xx.pl" or print $! >> ## << $_ = `pwd` >> ##

      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      << do "./faq.pl" or print $! >> fex-20160919/htdocs/FAQ/all.html0000644000174700017470000000035512770001121014236 0ustar fexfex F*EX FAQ ## << do "./xx.pl" or print $! >> ## << $_ = `pwd` >> ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      << do "./faq.pl" or print $! >> fex-20160919/htdocs/FAQ/faq.pl0000644000174700017470000000631312770005376013724 0ustar fexfexpackage FAQ; my ($faq,$var,$env,$q,$a,$c,$s,$t,$n); my (@faq,%Q,%A,@s); my @sections = qw'Meta User Admin Misc'; @faq = ($faq) = $ENV{PATH_INFO} =~ /(\w+).html/; @faq = map {lc} @sections if $faq eq 'all'; print "\n"; print '

      F*EX '; printf "Frequently Asked Questions: %s

      \n",ucfirst($faq); if ($faq ne 'local') { print "

      Sections: "; foreach $s (@sections,'All') { if ($s =~ /$faq/i) { print "$s\n"; } else { printf "[%s]\n",lc($s),$s; } } print "

      \n"; } print "


      \n"; print "\n"; foreach my $faq (@faq) { open $faq,"$faq.faq" or next; local $/ = "Q:"; local $_ = <$faq>; while (<$faq>) { chomp; while (/\$([\w_]+)\$/) { $var = $1; $env = $ENV{$var} || ''; # s/\$$var\$/$env<\/code>/g; s/\$$var\$/$env/g; }; ($q,$a) = split /A:\s*/; $q =~ s/[\s\n]+$//; $q =~ s/^\s+//; $q =~ s! (/\w[\S]+/[\S]+)! $1!g; $a =~ s/[\s\n]+$/\n/; $a =~ s/^\s+//; while ($a =~ s/^(\s*)\*/$1
        \n$1
      • /m) { while ($a =~ s/(
      • .*\n\s*)\*/$1
      • /g) {} $a =~ s:(.*\n)(\s*)(
      • [^\n]+\n):$1$2$3$2
      \n:s } $a =~ s/\n\n/\n

      \n/g; $a =~ s/([^>\n\\])\n/$1
      \n/g; $a =~ s/

      (.+?)<\/pre>/pre($1)/ges;
          $a =~ s/\\\n/\n/g;
      #    $a =~ s/^\s*
      \s*//mg; $a =~ s/<([^\s<>\@]+\@[\w.-]+)>/<$1><\/a>/g; $a =~ s! (/\w[\S]+/[\S]+)! $1!g; $a =~ s!(https?://[\w-]+\.[^\s<>()]+)![$1]!g or $a =~ s!(https?://[^\s<>()]+)!$1!g; push @{$Q{$faq}},$q; push @{$A{$faq}},$a; } close $faq; } print "
      \n"; foreach $s (sections($faq)) { $c = lc $s; $s = '' if $s eq 'Local'; $t = ''; $t = $s if $faq eq 'all'; for ($n = 0; $n < scalar(@{$Q{$c}}); $n++) { $q = ${Q{$c}[$n]}; $qa = anchor($q); printf ''."\n", $t,$n+1,$s,$n+1,$qa,$q; } } print "
      '. ''. '%s Q%d:'. '%s
      \n"; print "


      \n"; foreach $s (sections($faq)) { $c = lc $s; $s = '' if $s eq 'Local'; $t = ''; $t = $s if $faq eq 'all'; for ($n = 0; $n < scalar(@{$Q{$c}}); $n++) { $q = ${Q{$c}[$n]}; $qa = anchor($q); print "

      \n"; print "\n"; printf "\n", $t,$n+1,$s,$n+1,$qa,$q; printf "\n", $s,$n+1,${A{$c}[$n]}; print "
      ". "%s Q%d:". "". "%s
      %s A%d:\n%s
      \n"; print "[↑ Questions]\n"; } } print "

      \n";
      print "\n" x 99;
      print "
      \n"; sub sections { my $faq = shift; if ($faq eq 'all') { return @sections; } else { return ucfirst($faq); } } sub pre { local $_ = shift; s/
      //g; s/\s+$//; return "
      $_
      \n"; } sub anchor { local $_ = shift; s/<.+?>//g; s/\(.+?\)//g; s/\W/_/g; s/_+$//; return $_; } ' '; fex-20160919/htdocs/FAQ/local.faq0000644000174700017470000000027212213334560014371 0ustar fexfexQ: How can I use my own local FAQ? A: Put your FAQ into file /home/fex/htdocs/FAQ/local.faq and execute: cd /home/fex/htdocs/FAQ ln -sf local.html index.html fex-20160919/htdocs/FAQ/local.html0000644000174700017470000000035512770001121014560 0ustar fexfex F*EX FAQ ## << do "./xx.pl" or print $! >> ## << $_ = `pwd` >> ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      << do "./faq.pl" or print $! >> fex-20160919/htdocs/FAQ/meta.faq0000644000174700017470000001020012701040512014206 0ustar fexfexQ: What is so special about F*EX? A: See feature list http://fex.rus.uni-stuttgart.de/features.html and use cases http://fex.rus.uni-stuttgart.de/usecases/ Q: Why not use one of the commercial services like DropLoad, ALLPeers, YouSendIt, etc? A: * They have a file size limit of 2 GB or even less. * Their security and privacy status is unknown (ever heard of "Snowden & NSA"?). * They are not open source based. * There are no UNIX (CLI) clients for them. * They need java, active-X, flash or other evil plugins. * It is unknown how long they will exist - DropLoad and ALLPeers already have terminated their business. Q: Why name "F*EX" and not shortly "FEX"? A: At publication time there was already a program named "FEX" listed on freshmeat.net. Q: Who is the author? A: The main author is Ulli Horlacher
      But there are also a lot of contributors all around the world. Q: Why a camel as the logo? A: The logo was inspired by the Perl camel, but it is based on a Steiff plush camel, which rides with us on our racing tandem. The logo was drawn by my stoker Beate. http://fex.rus.uni-stuttgart.de/Vortrag/tosa.html Q: What do I need to install a F*EX server? A: A UNIX or Windows server with a DNS entry, smtp for outgoing email and one open and free incoming tcp port. You must have administrative rights (UNIX: root) on this server and a basic understanding of UNIX and networking. Q: What means DNS and smtp? What is a tcp port? A: Do not install F*EX. It is beyond your horizon. Q: Does F*EX support IPv6 and SSL/TLS? A: Yes. Q: Can I run F*EX on Windows? A: On client side all operating systems are supported, even Windows. If you want to run a F*EX server on Windows, then see http://fex.belwue.de/fexwix.html Q: Where can I get the F*EX sources? A: F*EX server for UNIX: http://fex.belwue.de/fex.html Q: I do not want to install a F*EX server of my own, but where can I use it? A: Contact http://www.nepustil.net/ for F*EX hosting. Q: The F*EX server is all in Perl?! Isn't Perl too slow for this job? A: F*EX is able to handle uploads with more than 300 MB/s on an office PC. Try this with an ordinary webserver like Apache! Q: Which licence does F*EX have? And why? A: Perl Artistic free software with a special anti-military clause: http://fex.belwue.de/doc/Licence "I want peace on earth and goodwill towards men" https://www.youtube.com/watch?v=JHU0HinVhYc https://en.wikipedia.org/wiki/Sneakers_%281992_film%29 Q: Is there a F*EX mailing list? A: https://listserv.uni-stuttgart.de/mailman/listinfo/fex Q: Where can I get commercial support for F*EX? A: Contact http://www.nepustil.net/ Q: How big is F*EX? A: Server: 400 kB, 11000 lines of code Clients: 180 kB, 5500 lines of code Documentation: 130 kB Localizations: 250 kB Q: Who else is using F*EX? A: For example: * German Aerospace Center http://fex.dlr.de * European Commission Institute for Energy and Transport http://fex.jrc.nl * High Performance Computing Center Stuttgart http://fex.hlrs.de * Swiss National Supercomputing Centre http://fex.cscs.ch * Centre National de la Recherche Scientifique http://bigfiles.cnrs-gif.fr * Institut Pasteur http://dl.pasteur.fr * Justus Liebig University http://fex.hrz.uni-giessen.de * Fiat Chrysler https://fex.fiatitem.com/ * Palo Alto Research Center (Xerox PARC) http://parcftp.parc.com * Baden-Wrttembergs extended LAN http://fex.belwue.de * Deutsche Kinemathek Museum für Film und Fernsehen http://upload.deutsche-kinemathek.de Q: Is F*EX secure? A: F*EX is written in Perl which does not have common security problems with buffer overruns, segmentation faults, heap and stack corruption. F*EX does not use an extra web server or a (SQL) database, so no typical web attacks are possible. F*EX was analysed by security company revshell.com and labeled as "secure". F*EX comes with source code, so everybody can verify it. Q: Feature/design XY is missing. A: Contact the author Q: I have more/other questions than in this document! A: Ask the author fex-20160919/htdocs/FAQ/meta.html0000644000174700017470000000035512770001121014414 0ustar fexfex F*EX FAQ ## << do "./xx.pl" or print $! >> ## << $_ = `pwd` >> ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      << do "./faq.pl" or print $! >> fex-20160919/htdocs/FAQ/misc.faq0000644000174700017470000000134212672204756014245 0ustar fexfexQ: F*EX is great! Can I join the developing team? What needs to be done? A: Contact the author Requested features are:
      • testers for MacOS, AIX and other UNIXes
      • an Android or iOS client
      • HTML5/websocket support
      • a F*EX plugin for thunderbird or outlook see thunderbird's filelink https://support.mozillamessaging.com/en-US/kb/filelink-large-attachments https://developer.mozilla.org/en/Thunderbird/Filelink_Providers
      • more (other) languange support (japanese, bavarian, klingon ...)
      Q: Can I donate something for F*EX? A: If you have a pet animal, fex a cute video of it to the author fex-20160919/htdocs/FAQ/misc.html0000644000174700017470000000035512770001121014421 0ustar fexfex F*EX FAQ ## << do "./xx.pl" or print $! >> ## << $_ = `pwd` >> ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      << do "./faq.pl" or print $! >> fex-20160919/htdocs/FAQ/user.faq0000644000174700017470000002140412672204756014271 0ustar fexfexQ: What is the "auth-ID"? A: The auth-ID is an internal identification which authentificates the user. It will be first generated by the admin or the automatic registration process and can later be modified by you, the user. Think of some kind of a low security password. Q: What is the difference between all these user types (full, sub, group, external, ...)? A: See http://fex.rus.uni-stuttgart.de/users.html Q: I have uploaded a HUGE file but misspelled my recipient's address. Now I have got an error bounce email. Must I re-upload the HUGE file? A: No, it is not necessary. You can redirect the file with "user config & operation control" Q: I have uploaded a HUGE file but forgot another recipient. Must I re-upload the HUGE file? A: No, it is not necessary. You can forward-copy the file with "user config & operation control" Q: Can I use an HTTP proxy? A: Yes, but pay attention: Some HTTP proxies like privoxy delay the upload progress bar! You may want to disable proxying $SERVER_NAME$ if you run into this problem. Q: My recipient has lost the notification email with the download-URL. What can I do? A: You can resend the notification email via "user config & operation control" Q: Why should I use a special F*EX client? A: When you are using F*EX with your webbrowser, you are limited to its restrictions. With a special F*EX client http://$HTTP_HOST$/tools.html you can * resume an aborted transfer * send several files or even whole directory trees at once * stream files * transfer files via command line * use an Internet clipboard http://fex.belwue.de/usecases/xx.html * do much more :-) Q: How can I upload several files at once? A: Put your files in an archive file (ZIP). Your web browser cannot do that. Or you can use a F*EX client, see http://$HTTP_HOST$/tools.html Q: I cannot upload files > 2 GB with my web browser!? A: Many web browsers have bugs in their HTML-FORM implementation. The limit mostly is 2 GB, sometimes 4 GB. Firefox and Google Chrome have no limitation. But remember: No web browser is able to resume an interrupted upload. You need a special F*EX client like fexsend or schwuppdiwupp for resuming, see http://$HTTP_HOST$/tools.html Q: I need to send a file bigger than my quota allows. What can I do? A: Simply ask $SERVER_ADMIN$ to raise your quota. If you want to send a REALLY big file, you also have to tell the recipient's address because his quota also has to be raised. Q: Why is the upload status window empty and I cannot see the progress bar? A: Most probably you are using a (enforced) web proxy, which cannot handle dynamic HTML pages. A workaround is using Google Chrome, which shows the upload status by itself. Q: My download was aborted before it was finished. Can I resume the download? A: F*EX supports resuming at download, but your client also has to support this feature. Firefox e.g. is missing this HTTP feature, you need an other client like opera, wget or fexget. Q: My upload was aborted before it was finished. Can I resume the upload? A: F*EX supports resuming at upload, but your client also has to support it. No web browser has this feature, you need a special F*EX client like fexsend or schwuppdiwupp, see http://$HTTP_HOST$/tools.html Q: Can I integrate F*EX in my mail program (thunderbird, outlook, etc)? A: Yes, if your mail admin has set up a "fexmail" smtp relay. http://fex.belwue.de/usecases/BIGMAIL.html Q: Can I use a download manager/accelerator? A: Generally, no, because they suck: they are not RFC compliant and produce a LOT of unnecessary server load. But there is one exception: axel http://axel.alioth.debian.org/ Q: Why is there an error "FILE has already been downloaded"? A: Either you or someone else have already downloaded this file. Now it is gone. Downloads are limited to a specific recipient. One cannot share it. Perhaps the sender has fexed it to a mailing list (which is a bad idea!)? Q: Can I fex to a mailing list? A: Generally: no, because the first download makes the file no more available for others. Contact $SERVER_ADMIN$, he can allow multiple downloads for specific addresses. Q: Sending as a F*EX user is easy, but how to receive files from others, outside? A: Register them as your subusers, create a F*EX group or a one-time upload key with "user config & operation control" See also http://fex.belwue.de/usecases/foreign.html Q: What is a F*EX group? A: F*EX group is similar to a mailing list, but for files: When a member fexes a file to this list, then all other members will receive it. Any full user can create a F*EX group and add or delete members. See "user config & operation control" → "Manage your subusers and groups" Q: I am not a user of your site. How can I send a file to a registered user? A: See question above: you must ask a regular user to register you as his subuser. You will then get a specific upload URL from him. Q: Sometimes I can download a file more than once, especially when I repeat it quickly. Is the autodelete feature buggy? A: The F*EX server has a grace time of 1 minute after first sucessfully download in which the file is still available. This is necessary because of some stupid "download managers" which request the file several times at once. Otherwise they would report an error to the user. Your fexmaster has set AUTODELETE=DELAY as default, which means that the autodelete cleanup process is called once a day. Power users (use the source, Luke!) can set a "do not delete after download" flag. Q: I have uploaded a file to a list of recipients. Will the file be deleted after the first recipient has dowloaded it? A: No. Every recipient gets his own copy of the file which is independant from the others. Q: The default keep time is too short for me (sender), I need more. How can I set it? A: Use fexsend, ask $SERVER_ADMIN$ or read the source code :-) Q: The default keep time is too short for me (recipient), I need more. How can I set it? A: Ask $SERVER_ADMIN$ to raise your default KEEP value. Q: I forgot to download a file. Now it is expired. How can I obtain it nevertheless? A: An expired file is definitively deleted. Even the admin cannot restore it. You must re-request it from the sender. Q: When I try to download a file again, I get the error message: "file has been autodeleted after download". Can you restore it? A: No. You must re-request it from the sender. Q: I have sent a second file with the same name, but the recpient has not received a second notification email. Why? A: A file with the same name to the same recpient overwrites the first one if it is still there (no download so far). A second notification email of the same file(name) is not suggestive. Q: How can I sent a more compact notification email? A: Let your comment start with "!.!", then the notification email will contain only download-URL, size and comment. Q: How can I suppress the automatic notification email? A: Use "!#!" as comment, then no notification email will be sent. Of course you then have to inform the recipient manually. Q: Can I delete a file without downloading? A: Add "?DELETE" to your download URL. Q: Can I get a copy of the notification email? A: Add "!bcc!" to the comment field on upload. Q: Can I get a notification email on download? A: No. Such a feature is in conflict with German and European privacy laws and will not be implemented. With email you also have no acknowledgement of receipt. Q: Can I have encrypted emails? A: See http://fex.belwue.de/gpg.html Q: I need ACLs for group access, versioning, a file browser and integration in my local file system. A: This is beyond the scope of F*EX, which is designed for efficient file transfer only. Q: I cannot download files with Internet Explorer, it tells me "Cannot open Internet site". What shall I do? A: Use Firefox or any other Internet-compatible web browser, that Internet Explorer is not. This is one of the many bugs of Internet Explorer. See also http://support.microsoft.com/kb/323308 Q: I cannot login with Internet Explorer, it tells me "This page can't be displayed". What shall I do? A: Use Firefox or any other Internet-compatible web browser, that Internet Explorer is not. This is one of the many bugs of Internet Explorer. Q: I have recived a "file.7z". How can I extract it on my Mac? A: For example with "Stuffit Expander": https://itunes.apple.com/us/app/stuffit-expander/id405580712?mt=12 http://my.smithmicro.com/stuffit-expander-mac-download.html Q: How can I prevent the fexsend error SSL3_GET_SERVER_CERTIFICATE:certificate verify failed? A: Set the environment variable SSLVERIFY=0 Rationale: Your openssl library cannot resolve the SSL certification path. With SSLVERIFY=0 you tell openssl to ignore certification verification. Yes, this is a crude workaround :-} fex-20160919/htdocs/FAQ/user.html0000644000174700017470000000035512770001121014444 0ustar fexfex F*EX FAQ ## << do "./xx.pl" or print $! >> ## << $_ = `pwd` >> ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      << do "./faq.pl" or print $! >> fex-20160919/htdocs/FAQ/xx.html0000644000174700017470000000034612770006727014146 0ustar fexfex F*EX FAQ ## << do "./xx.pl" or print $! >> ## << $_ = `pwd` >> ##
      ## << while (($v,$vv) = each %ENV) { print "$v = $vv\n" } >>
      ## 
      << require "./xx.pl"; >> fex-20160919/htdocs/FAQ/xx.pl0000755000174700017470000000010112770006136013577 0ustar fexfexpackage FAQ; print "abc\n"; printf "1 2 3\n"; print "___\n"; 1; fex-20160919/htdocs/FAQ/zz.pl0000644000174700017470000000000312770005742013603 0ustar fexfex0; fex-20160919/htdocs/users.html0000644000174700017470000000421512407061344014231 0ustar fexfex F*EX users types

      F*EX users types

      This is a short overview over the different F*EX user types.
      • regular (full) user

        • created by the fexmaster or self registration
        • can send to anybody
        • can change his settings (user configuration)
        • can edit address book
        • can use all F*EX clients
        • can create sub users
        • can create groups and group users
        • can create one-time upload keys
      • sub user

        • created by a regular user (= main user)
        • can send only to his main user
        • cannot change his settings (user configuration)
        • cannot create other users
      • group user

        • created by a regular user (= main user)
        • can send only to his group
        • cannot change his settings (user configuration)
        • cannot create other users
      • restricted user

        • created by the fexmaster
        • can send only to recipients defined by the fexmaster
        • can change some of his settings (user configuration)
        • can have upload or download restrictions
        • cannot create other users
      • external user

        • is a restricted user created by self registration
      • anonymous user

        • created by the fexmaster
        • authentificated by his IP
        • cannot change his settings (user configuration)
        • can send only to himself, but forward the download URL to anybody
        • cannot create other users
      • public user

        • created by the fexmaster
        • is only a recipient, anybody can send to him wihout registration
        • cannot change his settings (user configuration)
        • can be an extension of a regular user
      • captive user

        • created by the fexmaster
        • is a super-restricted user
        • cannot change his settings (user configuration)
        • cannot create other users
      • demo user

        • sub type of the full user with limited quota and account life time
        • suitable only for testing
      fex-20160919/htdocs/tools.html0000644000174700017470000000416612770010176014235 0ustar fexfex F*EX tools

      F*EX tools

      <<$ENV{TA} = 'http://fex.belwue.de';'';>> #if $ENV{AKEY} To use one of the following F*EX clients you must configure them. See user config for your account data.

      #endif

      UNIX:

      fexsend client for sending files (with many additional features)
      fexget client for receiving files (with many additional features)
      sexsend, sexget clients for sending and receiving streams

      Windows:

      fexit client for sending and receiving files

      Macintosh:

      fexsend.command client for sending files and directories

      In opposite to many web browsers all these clients can handle files or directories greater than 2 GB and are able to resume interrupted up/downloads.

      Hint for UNIX users:

        wget -qO- http://$HTTP_HOST$/xx.tar | tar xvf -
      installs fexsend, fexget and xx.
        wget -qO- http://$HTTP_HOST$/afs.tar | tar xvf -
      also installs the client programs for Stream EXchange and << my $a = "/usecases/anonymous.html"; print "anonymous usage"; >> ##
      ##
      ## <<
      ##  #while (($v,$vv) = each %ENV) { printf "%s = %s\n",$v,$vv if $vv !~ /\n/ }
      ##  #foreach $v (qw'AKEY USER ID') { printf "$v = %s\n",$ENV{$v} }
      ##  '';
      ## >>
      ## 
      fex-20160919/htdocs/fexit.html0000644000174700017470000000502212770010175014203 0ustar fexfex fexit <<<$ENV{FEXIT} = 'http://fex.belwue.de/download/fexit.exe'>>>

      fexit for Windows

      ##<<>> #if $ENV{ID} <> #endif

      fexit is a F*EX client for sending files of any size to any e-mail address.
      fexit can also send directories or download files and resume the upload or download after link failures.
      Your webbrowser cannot do this.

      You can start fexit via Windows explorer (double-click fexit icon) or via command console (cmd.exe).
      You can also drag files or directories to the fexit icon with the Windows explorer.

      With fexit you also have access to the F*EX internet clipboard to exchange files between your Windows or UNIX accounts.

      #if $ENV{ID}


      When you run fexit for the first time and you are asked for the "F*EX server URL" you can enter your personal URL:

      <<"$ENV{PROTO}://$ENV{HTTP_HOST}/fup/".::b64("from=$ENV{USER}&id=$ENV{ID}")>>

      (use your mouse for copy+paste) #endif ##

      <>


      command line usage

      upload usage: fexit [-c "comment"] [-a archive] file(s) recipient[,...]
      example: fexit flupp.avi framstag@rus.uni-stuttgart.de
      example: fexit -c "lab research" -a data *.png x1@flupp.org,x2@flupp.org
      
      download usage: fexit FEX-download-URL
      example: fexit http://fex.rus.uni-stuttgart.de/fop/jHn34yp7/flupp.avi
      
      additional options:
        -v                               # HTTP verbose output
        -u fexserver/user@domain:auth-ID # use this server & user
        -o                               # overwrite file
        -d                               # delete file
        -x [files]                       # F*EX clipboard read/write
        -s [files]                       # SEX read/write yourself
        -m kBs                           # max kBs throuput
        -T up-MBs[:down-MBs]             # test internet speed
        -X "parameter"                   # additional URI parameter
        -X?                              # show recipients parameter
      
      fex-20160919/htdocs/fexit.png0000644000174700017470000005626112653633030014037 0ustar fexfexPNG  IHDReȜgAMA atEXtSoftwareXV Version 3.10aficK IDATxw$Eۻ=2Hpt,9+IJQ@Q^1"ĀD AAqpLBW陝ٝ~<ٞꚞ~T;LLLb"bfX4 7B%6=8M&"b6RE0hB.BD_P RV8ǀ " } *VXAZ(90 0 0%HHJB)2Pv DlFB !IɀHP$ b "n=6 aR{HH!$"$H!bU dXqq;`ox BĒU +$BCk*qXcUʀU52B ))EY!"" *&C8rXUZUUX0dU$BAd4APAEVdP(T@ 2 p@Upol$I !FJtFQ2JFIVyCڒߩNux`au6 B*$=7AbI+̪ʸ ߝ_[}ʙ_=>MDIB|Y*t:[1 NffY'9UqQ\3p=ehm ̍<9lOF" "D("#,; u 7HW]sNhaםvq߾ #Dӟ|Yی(2 ]{@ QBV5U.Nmɻ]p{< )ۛ^"7aM_6T )q/j a5f}-&)Sy KsV;fRwUgb"ۛJH8u3fkfc0&B*&vDu#tJqK,R_6؅ ] _ %&HG^t"ylH(mWT)DB?ݢKmzY /T:Ǐh|%ʻauߟy(""DH 2HߙHc& 2Bs7h;ܳ'o.}VdA3! U¥K-ϣ킋6f{W*ʼ |[x'⏻̿>_.e6%ԫYspX KkK|cGWvk5v)V95Ωe8nT8Dv׵3 ]b=ߑ]Vښvl_Ndh!JyL<~ɽ4++̥1S՚.SJV̬d!SB"lIp>,[e)lq`x8(](H|Ӎu,q{1.b㨙Mo9s8*21"gUdU!~渊Rs-ߋjO 5Qi(*_.'&ȡ"RB13+d$Q!C AĕNݎwɄQ8[@Zk[WB{ F&uoB1$pQskI [ɩߓjŁmG2QjucC-TaZO!;x'ߝG6ٳ瞱 A0RU ~7B"E _2wە'!dd 2PDY&ETTJo,)^+[i`U%d @VŐƵUE',4 aBDK,$$mRsϔy~̔9+b'yf_BQg2e7f9 8QCz y,WPWjIr,/PsX1@zYMH8~ +,t%Ɖ6JsO&խ%EiX b[A}{!CWlIa_.hjfԧr!bZ-VJ6o+H| ðyi8O|'RIGrEp$A@1SJnk{x<߀=?OtUq\` %\pZR\R@09 U(*#eՊ"1Y i uzLP8{W_*^-ouHISG} һ--3-UFkyb!WW7i6-Ixվj}ߓBBIXIb9n+l9éuZwLDrVS_Dڇ()/_.63O\n ZU DXcUҭ5֋q,| ^vQE) B)#ePZN"&0!9\-k쪘L- p/s<~o@S^Ql\;Z 3ܿZ(Bj!5dRpv)Y6wPu) 4v()h"n]QBZmgw Okn : 3@ϋp fݧ | i!*aViԑvU[~brvYPq-T)BՔB1 RkBo /"[^'mLY
ް|ua*W9&=6}q|=vPa$"1)0ŐD5B" CRZ˰}Ys7\«0R*aOΒжz32{=y+u!o萣*LRӉc BfRC?bXdf8 )0}t+̼~Q"BEF R?޺Ɏ30+hq^\N: w39*Ǒtsi^m 9klss?_3y\O ".,L| 'JYz7 UNL d}SjJqeVJQTMP8*)H ]ŦBICrt * 0(I(nEK'iiR}48>S Nw$EL>8nN)7O7z HS.,+LL|{=+J"L/澈p{a}7 āB"HU LǭJWtY9^~}׈jL)$&1~¢TvT+4ʚ$ѩ{og-u^""I}h񍝦Z>v;?9O3xn5?vMqޟ.z)j?}}[wͧ$"{?( .|O~.qb*?l!lǾD{?t |'߻h[ϧm=o[7beĪߜw򕛎9ϽUhqWO^|[LnOM'pف<]AJz =uKY*&f)y! )H Šs2(I)e`fpg,85vY 1 I@ĺ⒘)V -TB sYFdr} nZk5_ }.;BrODR0TJ՜jx.?)u oK$ !܄ZagFxŷqY\sN҅;.z&cǟ"* =YP[SW7ɬjh1.AD_GG.fvX;M~{r*MϾمVUHn|_WV98E:uCO?/r4Ѱd4R(9s?GL񿟘0%x𩟽l>u}g[[dt~c2|UUtvr ts u>g_;j5MqG]L;g"Zk>YV/?%)"fXLb!YH@ʐIJ(› :(>NK yE kBcL:Hc%J2 S)m ؍FobffҬ&]Ct+n!`"o 3 F~F͗_zF"gH5tnpKKHH/0Ɵ_]~:ϸTg}g~ƥ$Ď݋uNHd:JKC`f! &Ue"Z~u经-=}OEDg;~Lׅ"~w-?1ާj-[x/DXy .Yks:A֩:%BdILXNZQrklv#{v!~ݦ{NݏOOx]n2* |O- NYm=oy3kZ0 S]ҫ:A,%G5&u%˭HإOd4Q ݧA1II*iD ~Ŏ 9h"Xwb:O_OvquDܨg=[s¬bbmoA6eG?c21)e"e]1@;Z YRI)2W F 4iQ"RTRchl1]+;Zvn1f,+4{L.:ϸ#չqxE_~C6f7uw4f,uNJG˱.1Kvw.U!}kN*:Fo%3+\ >Z]/Yka,ՇON'AOLBU;;bMN|#fEv-xO-w{ w:vn?mC'fH_}OyDD'愻w7$hC;f}񳷛F4_fTt_o1uZ/tɿ#:O&=Moso=s~ N㷟Zo}}{=k[۔sdM`?{?t1do3t5h-X/x?̟}Ltlm/=Wn4=zwl|(]^"-.}-N\[q3;^dzwqߍn:KutZ=Zm3{o~qЯ,qլ+'1&z_Z'9rNҙ=#W\\ mOݦ[h 2ݖZ.lJYϠQb~,Duhg{2=;;0A2h@p| n KSgY J0*rZ0z/vAAM09sM@DŞ2/͂ǯjJ|} (%FU aDzbR$.ǏBExI$@Rqk##e%m{ƛx%מ5czLj{|_֏!¹O.N$!$n(2A7GXZQ ^g^6s|_uκDtN>z5]_{Oil37gDf}~ ]}߯&v,ݼY|-i=.ق\pOMW7;gh^ꦷ<3so}~|l:eW}_KJcOD 9^wOqO6_\/xƗu/_h2+??Y#?}ɞ~{gMX 9B?'nu"i_{o;k7oqm[Na?>o vio~uW|tYx0, F FuAꂼE3YvШ8`kH0.";T^F4!vbLQtUSgl;zNUJWĊ\qݙiw"+Jꪌ'Š$T!JR$QҒ]iظ]i.K9"Uj,+D5SF$RM$JE.763T upo?6a?_0S'MXZt̟?jo~so4M)OxZ~̽a/w7wLD/>rU h"''m?:~>n32MZNzgEtGo.݄ٿ}O&1>` Xw~N'}T<8{6Vc~~DG ZMuVw}!ш¹9'/f/o}MiE~銏hCY9ߗ;Lw˿~Aـ=?r-yxu{ww ?X#']Χ3λg=R/tx6 褌2&l0hv0.H8n쉲/(yZD90δsGSBzz'-[;" ǾW~QucQQʨJP=z6L5FtaIJH *p' ]Nci#JEJVDtS˯0~؅yĞ,iP%B"E5QPGn_΢*DaQ"a8LK?1D HD߾g\wߎi2sn~)DT IDAT1wAAuDtuO[X'v?}.' qDS6m#n~cgo7w9]M~uy!9irT5tcƚmWl⌝v̭s6\XoqϿ{1[Y|yҬ/꧶[w zpɳ̪kGߘE4Er}sPmkn>ﶖ~Y+P~GsB]| {m's-RPUCw:c)uN:(&te(s~ "y&KM:pnoW䮉U!ꉋF#ޖ ͖ќEzΝ~**z*)绺**bdJ"oc*ѣdWW׸I$%?@X$$)̂~-5"")Y(-%3UՈ*A%=v*kc ?mȈ>1s D- Řgт;)^W= gm5(Ԣ]v1 &=&}$nWOs>&n}{ώo}8b4"zѯqL{nmOw6w>ÕsqefqFsOA4u;_O<{4c0<û977'C?;@Ċ(d"9Իk-FXqiG8TDBB"9⭾Ɠor8j^k۟ њGk|2wD&:7?Š]$sJqH9q?^ᆪV!Zص?3.X¹Dw[ =N{]\Wex5o'x =vw5߼ӏqݻ\9[-xOz[n{<~~˷?ǫz}k n}ָ >r>0!wXe02ʀ ǍWLPᰃz‽哝pN,HG } uW>O^Zډ*uݣ>^sUoifML"iRvr ۽,DmZ{?HS?]꼞5cƜ=ƗZu%'>l9G$KZ5ҧx_딞/yN`Ӌ뭞5b k_'~ح]з?fݿV6EɬLh +*QYH" ŁI>yDIā{ 8p} BOb$=oque}'?s(=K1?yQG')rM{DW YV$B f'Dn$6q˭ކgzKo$%>7audqKΙ]/=Ox)MvO2o'y7wnw|]řD%7HRzҬM?wyS;fx$Zq/ >ӯOy9WD6@&ptD '>^;ϙ9]T[H_tٳϪƷ~-fe1$ekPUC*T5T:VC\ $+f8W3f q+|+2B5vVMŊy)hoFl>$% bL6OV$@ ym7罗Yӧorm5nb{|{\5&=6=üWjϾWydq]am<|؏ RW'&v'z(Z\xҾVnߊj3q!g?}ڴHΣDm6jշh+_̩ HB5dbTQhھ?(LAдӚ'be$X EI4 f t% D ve!ρZDٟ@9+̘LҬnd?F '$XxůYU/5PznR?hLsmo4DaZ|Rfo:f#\bLbݥ|q< d7yŁ~Ks= 2K}A3{, &aRl FQLI*hG6ƔA\TReQ<} p!$5[omF 2dRR DM/sKBq[N5cGkU^٩%]B#%Ͻ5 4{S =~ALQbwGYtUqv]j;7AEzA-4Nh-Uʼ10 2h=iДXDge.urzyD _ OAE$I>;-)tIs [-JAI[xu鶿NTZIej 3D̬N2IyF "H ,B>)h H; b dKl<+e۠Ͷb53St4?'_82{_A"QTdd4sAWJ7N2z6f{eۡ@EnOQjڸHd)qP[6kA`ā6br#v3֧f0*Ucg}Abă\bL`o#gv(y<sUeٴ2ȧY`Q$"sdgߥ13<]15 Mkm3tLĭvcEhkc}Go=y@;\j.W؝X $R،Aqd- غv n,pd@Fp5tDgݏvP[ OvabchDs0r Zx@Ze@D:pC*"BԆ&3e;hXdd%=lof[/FBƳSϨƊ_q`Waxќnsܐ;/Ra#ky*3+nsndA&X DH$QvG='&-II`}'ABDmS04iV[Gٴ^O.bAgj"A]N0EI@hŁk,ȥAbgvahJS `@n;1m`\S J)J?ʀRQ73 Ȃ&0aj%w-Ry%;؅F%| pO(m8MȚEd&x+D * o>ӂf̨K_ݩwa47lʠ+@PFB8 6 7'WeX8) #VPm@́L,)Wqzo$uDʀu;ëAm )Rޭċ9L S Yx 5}**+b<čo3K10s< ZN6QCeAdY8~$܅ٍzXHo5":SQ^<6:]3ESm$/DD~iNCC Jri`H8hvm?4J r)ٻn`)(}}}sέT*]]]RJ.R]B!D__ߎ>2ʠ`ŔK Q`xpcef(402H+ٲ )rA  9Fz LYI@(DRJT2<ʣњ`RA/ $ _1cwq-QE Dk 7p 6e]6d+2 {20C ਣ:O>q1c;찃RE;6V@'7ޘ/u,a{"4lw;ꃞH:0ttL3tʔgVDkoWPv>unCiCHŏ؛̷)+L<~x'j.2i;!a~%{,sӒZOx 8?X&{(".h/Tm10<(q,2KnbN'vA|U[ޟo\2Zxv_2)ntyZ@xb*NA$́G7OSLL7ooW4j;Sn"ty\=yRkԮd*;J(OrSWY&]>?*7e&[ĜyQOOO9/)NϤ{6Q2 eB$j= $/*]oyc )@&oٳϟg"L0a^yɓˠhYiQPbÐXbѪ"5rha7R&QDy:ٳjI&z___RĬ9 wY+Բ-ZNJ ?mi\)h5AKKӆ+y}sku|G0s0 RaYVjZ-_t +tA;vW}[O`V۰kJJkL0zl0zl0HR${キtҼ,^P$ 2څr]v^oNCkV`Ï&byrFlN8Q7n3c6dsdHč& wНK|w"$ z}oUt;3ex,p]lSCs(ى`Z7*rm9-Yp#| @H@'B40S -sO⡗u 'a~)X|u :t<& +nuf4nB+hce .:w}6Z~cǦ a̷)rdt JӾ2e?.A1&  B0tRŋŏQS+ 1033} ݮIbX%k֠{-񁋌.`$j0 bTM Pr|E QΌ􆌐2qwygRJ"رaR&KP匴AgV{衇/_m MFf\`lhA]K^Љ rFq )+ꫯ%tBfBG^;?ZΨUZA$U0IO&)X ʎV@ Hؙ :C ᅷM ɤ0lD8-`xa\0A$dnoȡ3cf"b`x! 24ʢ`9hc,,A)69m H~赍JO r'ŒU d40E1NhFCzzzC. uFa^9_zg2E_ɌBJ "$Jex =4zy]WM5(5 "MD}ZNsMA~#/ ;+yk8ZD'B nZ0e.p#37K_\S[(@^N|3)NeϋWou˓?Nj_`B|݉ R )EPOpJUc.)ϨgׁO53}?22~䕳92Fz((OA$3~^xA=g~/yh9>Ei#H݉ a>\~  %M.Zt U|_y9OLje꧉r<Uy5!(aA` LzJBN=k; sH/^ɗu}i"}?2P9*O|=7>`E Qz=w[%)4E!IJ!E #Zu_G kiGM'4 QԚ=Bo@RbsVK/tyOW{╹.{֊y }jA EnF ; u³weiF.gD®_Twr(dvU&:.0QRZ -@aJ!útx#Wi[< (3d(5q)LAwC%*popaAQreBݼ򆭁4Z]0Z߼߯j4>,g$E匈 A8ZҪnm[Za ΢ZmU:c-0CrFhy(9k+sxC xMZp+_򗼯XLS{zUhOR!mH69H̷hlArFf7!m)K_ͥ;3Kt H8[ܷdyJjl)Oo{^)(OUPy~ONr&7/<OH:nIDATt"; xAn_eN]^@6DmdVSJjɼon^+Y=suuUK&Nt%I4Ёoaݮܙ0+$ͺR5Q֧JMq6$d&K oG;;<~1Dy.4J+!= >̰=v!eݏPg Ef-w9P˥L: /߁ <D.ڔ~k˓h%Sk>^FChfߠ9 ? o̍J+M]~̬itOټtʓ~gRx7gVAx^S13 P*H$qy4^2)JC?`4a}DF HN5'^y3{?{"825 h+Mʂne>EDB:eܴYӉ`f"@J=ABòk*Й :2_9ڔ7>Vk6D bPVv{̂0꫆'3ie{Kku,m=} <"rN)Ŋϖ} ZHLl(W},xoso-t Wɋn!333<RkABf5CY44Сm{ffR `E!e m"v c2șJ3:eMr-zy T 6lm:s\Y@J8֖G1R-{=PԃPW\Fj^< gCPb>@(bz";A G5'xN&-~^z ٌf,ށ~, qB"! ;rV9dJj{jxQz `πI 3ꐈUa!^߁dDh=JYtU~H"6M z (*_Zͺ)3 7̔===! Ċ rD !Nr!s F:چ{$ `ce3oO^7ov Wnсc Be'  )g˫ SyFV0afEB~ʡu38}ynNPTR3`ȡqx*0^XXD.\#'A/Q@ + NcqT{1[k ׈y@[1Ѐ ĐC%;1Lrr:g.eV  #-JK'ٹ&&܍4K!7qrfi8\hKC'k(Ǻ+ȤȂ&A3Qyg'lL^(y)mQ$W?WM<Po&(RFL;h$4xOFy˳Tm9m)ap,3`BbE[% ŅoI߾Uځ%DDi3:ٻooSK0ÿ%+P&L5M'qlK/sI73ą執I2䟪[ygC7wJ%eԪBn?D׷a^|E?"9E&37]n Mtt ʂo }1;dN(3`HhZ\R"Gn=3G.~LѢ'/U&^L BpS匔MpA$:vjHՌC=o9#rShˠ%#̾pT>^{%r9퀉FxjaL2l@D,R>fkixiZ[ yF}畼[t"YH*q1h&^U Ԇ5@uJjH4:QLK+To=,yugM '1o] OӃ5uD , p=Y16X}ّ6=Hg7Z33Db_#]&(ŏ')P"U?C6o_}e $AuD n?Z*p7]#utL#!NJ hM-~/KM>9%oǹ^?O 3VЋÜ~B.g&)ctS#2 _o:4 Ly4]B$A{"<葄&8n>=zSN־۝>4'…\xϙp}nfePg9#G^J$}`DДu 6Ր@0v,) |C #PA43ߒޗA+TTx-2(Ӊ%`8e[~zxВjZKz9 |:uTa}b]ȂP$|훌}LO L˼6~qj4ͻtxsV\ZDd[U#b?~& Nmŏ]ayMH|˔ďg .i﫡,!Oj & PJ3볉@.~|\ss#f9ʂx/ &:"@D!`pMvtCȤоZ,;I2MʂF dlA,2{gmk%)|tpX9|́|zCGl ӱyc)Po0)+ hvW?=鹅eMgߕILx4~(OD( -˼>y2͏Y7߼Ýy ʏ$Kە8QtQ1H=o:2{g 5${"4 P~3@[ , Z'BbAҌN&2i,uQC;ʍ !-y L eZ`g@ AKO &#g0hS 7i2(>nGyF;ڽ65D3jwC }M,CYd 0@Yd 0@Yd 04Uuaߙhy] ߚ0bh[ଣ6cev7vN7S͚tX} &a@ a{Zչ[V\:% Y'&"@KhYks!/~^|=2EmIoC,4릟G4-Aà m-LGvu,Ӱ,[ieШmaw,-O-0ڲnA7Jo<(O @K>3V-t˙*`l؂/>Ug>6Liph9i@#eH d0R@VI0@Yd 0@Yd 0@Yd 0@Yd 0@Yd 0@Yd F4`$#D`S^@Y|J: e2XV ebeYd 0@Yd 0@Yd 0@Yd 0fr`)@D,Xv-2Ju"@[CYY0i[edЉd 0@Yd 0@Yd 0@Yd 0Th  H+RM' Y ? vm}}O,-0|ᇏ:ꨱcǮJnJ+[Oc GaxӦMx]w] 0HlFpA\PÝby К@TJ !k/-twc aCRJ껩.1M6$4 !y R6dk+X̘B*W%Zo*i%K*)$ @'¢%խܲU@y6э^V[.Z_'RPҳ}s;{7Z,?\  {Q1B~?c 83"EMŞ>HZ@0J $"=*EK#c"!HH"a@Ȁd`O( e!d+HN)o~V(0S}r8:l 0ѝ DP܇dۘ-D F|J!RIϝ:.`s~MStwΩ:雯Z=A<#-nȟ8#6֦~}4$d (8{߾4{S̞WҧGydp\ܾq=^F  X5UNfos~Qe$snBDZDMáDH$ P"M{,buO9[1&A(2C->Q M`Ţp*ֳXJo:BmiB"s96uNIbaKB P!3+!H JɽI`6DaOw|9sKkѷ,@#%RPJ(}{17TtIME ([J6 IENDB`fex-20160919/htdocs/fexitinstaller0000644000174700017470000000204412665572337015177 0ustar fexfex#!/usr/bin/perl -w $user = $ENV{USER}; $authid = $ENV{ID}; $url = "$ENV{PROTO}://$ENV{HTTP_HOST}"; $fi = 'fexitinstaller.cmd'; $id = '%USERPROFILE%\\fex\\id'; $fe = 'http://fex.belwue.de/download/fexit.exe'; $fx = '%USERPROFILE%\\Desktop\\fexit.exe'; $ps = '%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe'; $cmd = <"$id" echo $user>>"$id" echo $authid>>"$id" ) $ps -command "& { (New-Object Net.WebClient).DownloadFile('$fe','$fx') }" setx PATH "%PATH%;%USERPROFILE%\\Desktop" \@echo. \@set /p x="See fexit on Desktop." EOD # \@explorer "%USERPROFILE%\\Desktop" $cmd =~ s/^ //gm; $cmd =~ s/\n/\r\n/g; if (chdir "$::spooldir/$user" and open $fi,'>',$fi) { print {$fi} $cmd; close $fi; system "$::FEXHOME/bin/fexsend ". "-oKq -C 'fexit for your Windows desktop' $fi $user >/dev/null 2>&1"; if ($? == 0) { print "

      \n"; print "

      A fexit installer has been sent to you. Check your email.

      \n"; } unlink $fi; } return ''; fex-20160919/htdocs/macfexsend.html0000644000174700017470000000324612770010176015210 0ustar fexfex fexsend for Mac

      fexsend for Apple Macintosh OS X

      fexsend is a F*EX client for sending files of any size to any e-mail address.
      fexsend can also send directories and resume the upload after a link failure, which your webbrowser cannot do.

      To install fexsend:

      1. start a "Terminal":
        go to Finder, press ⇧⌘U to open the Utility Application folder and double-click Terminal.app with left mouse button

      2. copy this code into the Terminal window:
        curl http://fex.belwue.de/download/fexsend.command|bash
        Do not forget to enter [RETURN]

        You can use your mouse for copying:

        1. move your mouse cursor with hold left mouse button over the code obove (the code will be marked)
        2. press ⌘C
        3. move your mouse cursor into the Terminal window
        4. click left mouse button
        5. press ⌘V

      To run fexsend:

      1. in Finder click Desktop with left mouse button
      2. double-click fexsend.command with left mouse button

      << if ($ENV{ID}) { my $url = "$ENV{PROTO}://$ENV{HTTP_HOST}/fup/" . ::b64("from=$ENV{USER}&id=$ENV{ID}"); qq( When asked for "F*EX server URL" enter:

      $url

      (again, use your mouse for copy+paste) ); } >> fex-20160919/htdocs/SEX.html0000644000174700017470000000362512770010175013532 0ustar fexfex Stream EXchange

      Stream EXchange (SEX)

      You can imagine SEX as network wide UNIX pipes with a relay between or as network based FIFOs.
      This can be useful for piping data from A to B where A and B cannot establish a direct connection, but both can connect to the SEX-server by HTTP.
      SEX is a synchronous service in conjuction to F*EX which is asynchronous.

      For seamless integration into the UNIX tool chain, there are the shell-tools sexsend and sexget.

      Using web browsers for sexing will not work, because they cannot handle streams in a pipe. So far, there are only the UNIX clients. Feel free to implement other clients for other operating systems :-)

      Authentication is the same as with F*EX.

      Example:

        root@lanldap:/var/log: tail -f syslog | sexsend framstag@rus.uni-stuttgart.de
      
        framstag@blubb:/tmp: sexget | grep ldap
      

      If you need encryption, then use the standard UNIX toolbox and add an appropriate program to the pipe, for example: openssl bf

      public SEX

      The recipient of regular SEX must be a registered F*EX user.
      But you can also offer streams to non-registered user.
      This is called "public SEX", example:

        framstag@flupp: cal | sexsend public
        http://fex.rus.uni-stuttgart.de/sex?user=framstag@rus.uni-stuttgart.de&ID=public
        http://fex.rus.uni-stuttgart.de/sex?dXNlcj1mcmFtc3RhZ0BydXMudW5pLXN0dXR0Z2FydC5kZSZJRD1wdWJsaWM=
      

      sexsend then displays two URLs onder which one can get the stream.

      SEX - all inclusive

      To transfer files by streaming you can use xx-rated SEX:

        root@vms2:/data/VM# sexxx flupp
        streaming:
        flupp/
        flupp/vmware.log
        flupp/flupp.nvram
        flupp/flupp.vmxf
        flupp/flupp.vmx
        flupp/flupp.vmdk
        4976 MB 11640 kB/s
      
      fex-20160919/htdocs/fup_template.html0000644000174700017470000000336212770010175015556 0ustar fexfex F*EX upload template

      F*EX upload template


      sender: (e-mail address)
      auth-ID:
      recipient(s):(e-mail address)
      comment: (optional)
      file name:


      After "submit" you will see an upload progress bar (if you have javascript enabled and popups allowed).

      NOTE: Most web browsers cannot upload files > 2 GB!
      If your file is greater you have to use a special F*EX client.
      You also need one for resuming interrupted uploads. Your web browser cannot do this.


      Contact: fexmaster
      fex-20160919/htdocs/sup.html0000644000174700017470000000333312770010176013677 0ustar fexfex F*EX simple upload

      F*EX simple upload


      your e-mail address:
      your auth-ID(*):
      your file:


      After "submit" you will see an upload progress bar (if you have javascript enabled and popups allowed).
      After the end a download URL will be shown.

      You can also use the regular upload form (with more features).

      NOTE: Only Firefox or Google Chrome can upload files > 2 GB!


      (*) Please register yourself if you do not have an auth-ID yet.


      Contact: fexmaster
      fex-20160919/htdocs/dynamic.html0000644000174700017470000000067612113611056014516 0ustar fexfex
      • <>
      • <<$y+1>>
      • <>

      <<`date +"%Y-%m-%d %H:%M:%S"`>>
      

      #if $y>2

      xxx

      #elseif 0

      000

      #elseif 4>3

      ###############

      #else

      zzz

      #endif


      $PATH=$PATH$
      URL parameter=$QUERY_STRING$
      


      <<`env`>>
      


      see >">sourcecode fex-20160919/htdocs/FAQ.html0000777000174700017470000000000012770010176016076 2FAQ/index.htmlustar fexfexfex-20160919/htdocs/Licence0000644000174700017470000000000012351111777017203 1fex-20160919/doc/Licenceustar fexfexfex-20160919/htdocs/version0000644000174700017470000000000012770010176017445 1fex-20160919/doc/versionustar fexfexfex-20160919/README0000644000174700017470000000243312770010167011576 0ustar fexfexF*EX (File EXchange) is a service to send big (large, huge, giant, ...) files from sender user A to recipient user B by HTTP. Sender and recipient user must have an e-mail-address and a web-browser, that is all (for them). The sender uploads the file to the F*EX-server and the recipient automatically gets a notification e-mail with a download-URL. The sender must have a valid auth-ID, given by the F*EX administrator. This F*EX distribution contains the F*EX server and the optional client programs fexsend, fexget, sexsend, sexget, xx and zz which run on UNIX. Simply run "./install", which installs all files into /home/fex/ Then edit /home/fex/lib/fex.ph and set your local config. Afterwards you can add F*EX users with /home/fex/bin/fac If you want to upgrade from a previous F*EX version, you also can run "./install" which is save, because it will not overwrite: /home/fex/lib/fex.ph /home/fex/lib/fup.pl /home/fex/lib/reactivation.txt /home/fex/htdocs/index.html but will create *_new versions of these files which you then can copy manually if you want. See directory doc for more information. If you have comments, suggestions, requests, etc, send me an e-mail: framstag@rus.uni-stuttgart.de Or fex some nice, funny, interesting videos (eg cute pets) to this address :-) fex-20160919/install0000755000174700017470000003561112761311256012321 0ustar fexfex#!/usr/bin/perl -w use 5.006; use Getopt::Std; use File::Basename; use Socket; use IO::Socket::INET; use Digest::MD5 'md5_hex'; our (@local_rdomains,@local_rhosts); $ENV{PATH} .= ':/sbin:/usr/sbin'; $usage = "usage: $0 [-p port] [IP-address]\n"; $xinetd = '/etc/xinetd.d/fex'; umask 022; if ($<) { die "you must be root to install F*EX\n"; } $fex = 'fex.rus.uni-stuttgart.de'; if (system("host $fex >/dev/null") != 0) { die "host $fex is not resolvable - check /etc/resolv.conf\n"; } # $fexupdate = '/root/bin/fexupdate'; # die "found $fexupdate\n" if -x $fexupdate; $opt_p = 80; if (open $xinetd,$xinetd) { while (<$xinetd>) { if (/^\s*port\s*=\s*(\d+)/) { $opt_p = $fexport = $1; } if (/^\s*bind\s*=\s*([\d.]+)$/) { $fexip = $ip = $1; } } close $xinetd; } goto INSTALL if $0 =~ /upgrade$/; if (`uname` =~ /^SunOS/) { die "Solaris is currently not supported. " ."Please contact framstag\@rus.uni-stuttgart.de for details.\n"; } getopts('p:') or die $usage; $arg = shift; if ($arg and -f "locale/$arg/lib/fup.pl") { exec 'locale/translate',$arg; } else { $ip = $arg || $fexip || 0; } # if (not $ip and open P,"ifconfig 2>/dev/null |") { if (not $ip and open P,'host $(hostname)|') { $guessed_ip = 0; while (

      ) { if (/(\d+\.\d+\.\d+\.\d+)/) { $guessed_ip = $1; last; } } close P; unless (-f $xinetd) { print "Your IP [$guessed_ip] : "; chomp($ip = ); } $ip ||= $guessed_ip; } ($hostname) = gethostbyaddr(gethostbyname($ip),AF_INET); die "cannot find hostname for IP $ip\n" unless $hostname; print "checking prerequisites\n"; if (`which xinetd` =~ m{^/}) { print "found xinetd\n"; } else { print "xinetd executable NOT found\n"; $premiss++; } foreach (qw'/usr/lib/sendmail /usr/sbin/sendmail') { if (-x) { $sendmail = $_; print "found $sendmail\n"; last; } } unless ($sendmail) { print "sendmail NOT found\n"; $premiss++; } if ($premiss) { print "installation aborted, nothing has been touched yet\n"; print "what now? ==> see doc/installation\n"; exit 1; } unless ($fexport) { $SH = IO::Socket::INET->new( PeerAddr => $ip, PeerPort => $opt_p, Proto => 'tcp', ); if ($SH) { print "There is already a tcp-service running on $ip:$opt_p !\n"; print "Select another port for F*EX by running $0 -p OTHERPORT $ip\n"; print "or an alternative IP-address by running $0 OTHERADDRESS\n"; exit 5; } } print "prerequisites checked, ok\n"; unless (getpwnam('fex')) { print "creating user fex\n"; system 'groupadd --system fex 2>/dev/null || groupadd fex'; my @g = getgrnam('fex') or die "$0: cannot groupadd fex\n"; my $gid = $g[2]; if (getpwuid($gid)) { system "useradd -s /bin/bash -c 'File EXchange' -g $gid -m fex" } else { system "useradd -s /bin/bash -c 'File EXchange' -u $gid -g $gid -m fex" } exit $? if $?; } if (open F,'/etc/passwd') { while () { $fexbash = $_ if /^fex:.*\/bash/; } close F; } unless ($fexbash) { die "no bash login shell for user fex\n"; } INSTALL: umask 077; @FEX = getpwnam('fex') or die "no user fex\n"; $FEXHOME = $FEX[7]; $ENV{HOME} = $FEXHOME; # needed for later eval fex.ph die "no HOME directory for user fex\n" unless -d $FEXHOME; if ($FEXHOME !~ /fex/) { print "HOME=$FEXHOME for user fex does not contain \"fex\"\n"; print "REALLY continue?! "; $_ = ; exit unless /^y/i; } # old bug fix if (-d "$FEXHOME/htdocs/locale") { chmod 0755,"$FEXHOME/htdocs/locale"; chmod 0755,grep { -d $_ } glob("$FEXHOME/locale/*/htdocs"); } print "Installing:\n"; $pecl = "$FEXHOME/perl/Encode/ConfigLocal.pm"; unless (-f $pecl) { mkdir "$FEXHOME/perl"; mkdir "$FEXHOME/perl/Encode"; open $pecl,'>',$pecl or die "$0: cannot write $pecl - $!\n"; print {$pecl} "# hack for broken Perl in SuSe and Solaris, used via \@INC in fexsrv\n", "1;\n"; close $pecl; print $pecl,"\n"; chownr('fex:0',"$FEXHOME/perl"); } @save = ( "lib/fex.ph", "lib/fup.pl", "lib/reactivation.txt", "etc/mime.types", "htdocs/index.html", "htdocs/robots.txt", "htdocs/FAQ/local.faq", ); foreach $s (@save) { $f = "$FEXHOME/$s"; if (-e $f) { $fs = $f.'_save'; rename $f,$fs and print "$f --> $fs\n"; } } cpav(qw'bin cgi-bin lib etc htdocs doc',$FEXHOME); unlink "$FEXHOME/doc/License"; unlink "$FEXHOME/htdocs/License"; $hl = "$FEXHOME/htdocs/locale"; unless (-d $hl) { mkdir $hl or die "$0: cannot mkdir $hl - $!\n" } foreach $s (@save) { $f = "$FEXHOME/$s"; $fs = $f.'_save'; $fn = $f.'_new'; if (-e $fs) { unlink $fn; rename $f,$fn and print "$f --> $fn\n"; rename $fs,$f and print "$fs --> $f\n"; } } if (-d "$FEXHOME/spool") { warn "checking $FEXHOME/spool ...\n"; &convert_spool; } else { $newinstall = $FEXHOME; chmod 0700,$FEXHOME; mkdir "$FEXHOME/spool",0700 or die "cannot mkdir $FEXHOME/spool - $!\n"; mkdir "$FEXHOME/spool/.error",0700; } foreach my $dir (qw'.dkeys .ukeys .akeys .skeys .gkeys .xkeys .locks') { mkdir "$FEXHOME/spool/$dir",0700; } chownr('fex',"$FEXHOME/spool/."); # fex-VM? if (open my $setup,'/root/bin/setup') { while (<$setup>) { exit if /#.*X-VM/; } close $setup; } system(qw'perl -p -i -e', 's:href="/?FAQ.html":href="/FAQ/FAQ.html":', "$FEXHOME/lib/fup.pl" ); $fph = "$FEXHOME/lib/fex.ph"; open $fph,$fph or die "cannot read $fph - $!\n"; while (<$fph>) { s/'MYHOSTNAME.MYDOMAIN'/'$hostname'/; $conf .= $_; } close $fph; eval $conf; # die "no \$spooldir in $fph\n" unless $spooldir; $spooldir ||= '/home/fex/spool'; die "\$spooldir=$spooldir is not a directory, see $fph\n" unless -d $spooldir; symlink $spooldir,"$FEXHOME/spool" unless -e "$FEXHOME/spool"; @sds1 = stat "$spooldir/."; @sds2 = stat "$FEXHOME/spool/."; if ("@sds1" ne "@sds2") { die "$FEXHOME/spool is not a symbolic link to \$spooldir=$spooldir\n"; } $fid = "$FEXHOME/.fex/id"; $aa = "$spooldir/$admin/@"; if ($newinstall or not -s $aa) { print "\n"; for (;;) { print "Server hostname [$hostname] : "; $_ = ; s/\s//g; $hostname = $_ if $_; last if gethostbyname($hostname); print "No DNS for $hostname\n"; } for (;;) { print "F*EX admin [$admin] : "; $_ = ; s/\s//g; $admin = $_ if $_; last if $admin =~ /.\@./; print "admin must be a valid email address!\n"; } $aa = "$spooldir/$admin/@"; while (not $admin_pw) { print "F*EX admin password: "; $admin_pw = ; $admin_pw =~ s/\s//g; } mkfid(); print "(admin password is in $aa)\n"; $conf =~ s/^\s*\$hostname\s*=.*/\$hostname = '$hostname';/m; $conf =~ s/^\s*\$admin\s*=.*/\$admin = '$admin';/m; } else { if ($admin_pw) { print "\nFound old \$admin_pw in $fph !\n"; print "This is no longer supported for security reason.\n"; if (open $aa,$aa) { $_ = <$aa>||''; chomp; close $aa; if ($_ ne $admin_pw) { print "\nYou have to delete \$admin_pw in $fph and run\n"; print "$FEXHOME/bin/fac -u $admin $admin_pw\n"; print "\nThen rerun $0\n"; exit 2; } } mkfid(); print "\$admin_pw is transfered to auth-ID in $aa\n\n"; $conf =~ s/^\s*(\$admin_pw)\s*=.*/# $1 is now auth_ID of user \$admin/m; } } open $fph,">$fph.new" or die "$0: cannot write $fph.new - $!\n"; print {$fph} $conf; close $fph; system "chown fex $fph.new"; rename "$fph.new",$fph or die "$0: cannot rename $fph.new to $fph - $!\n"; do $fph or die "$0: error in new $fph - $!\n"; if (@locales = glob "locale/*/lib/fup.pl") { foreach (@locales) { m{locale/(.+?)/} and $locale = $1; if (-f "$FEXHOME/$_") { system 'locale/translate',$locale; chownr('fex',"$FEXHOME/locale/$locale"); $hl = "$FEXHOME/htdocs/locale/$locale"; symlink "$FEXHOME/locale/$locale/htdocs",$hl unless -l $hl; chownr('fex',"$FEXHOME/htdocs/locale/$locale"); } else { push @nlocales,"./install $1\n"; } } if (@nlocales) { if (glob "$FEXHOME/locale/*/lib/fup.pl") { print "\nTo install another localized version, type:\n"; } else { print "\nTo install a localized version, type:\n"; } print @nlocales; } } $fph = "$FEXHOME/lib/fex.ph"; do $fph; unless (-f $xinetd) { my $xc = '/etc/xinetd.conf'; if (open $xc,$xc) { while (<$xc>) { if (/^\s*only_from/) { print "WARNING: found \"only_from\" in $xc : fexsrv is restricted!\n"; } } close $xc; } if (-d '/etc/xinetd.d') { unless (-f $xinetd) { open $xinetd,">$xinetd" or die "cannot write $xinetd - $!\n"; open F,'etc/xinetd_fex' or die "cannot read etc/xinetd_fex - $!\n"; while () { s/FEXHOME/$FEXHOME/; s/PORT/$opt_p/; s/ADDRESS/$ip/; print {$xinetd} $_; } close F; close $xinetd; system qw'/etc/init.d/xinetd restart'; print "WARNING: cannot restart xinetd\n" if $?; } } else { print "WARNING: No /etc/xinetd.d found.\n"; print "WARNING: You have to install etc/xinetd_fex manually.\n"; } $crontab = `crontab -u fex -l 2>/dev/null`; if ($crontab !~ /fex_cleanup/) { open $crontab,">fex.cron" or die "cannot create fex.cron - $!\n"; print {$crontab} $crontab,"\n"; print {$crontab} " 3 2 * * * exec $FEXHOME/bin/backup\n"; print {$crontab} " 3 3 * * * exec $FEXHOME/bin/fex_cleanup\n"; close $crontab; system qw'crontab -u fex fex.cron'; } chownr('fex:0',$FEXHOME,"$FEXHOME/spool/.","$FEXHOME/htdocs/."); chmodr('go-r',"$FEXHOME/lib","$FEXHOME/cgi-bin","$FEXHOME/spool/."); print "\n"; print "Now check configuration file $FEXHOME/lib/fex.ph and run\n"; print "$FEXHOME/bin/fac for further configuration and user management.\n"; print "(You can do this as user \"fex\")\n"; } else { chmodr('go-r',"$FEXHOME/lib","$FEXHOME/cgi-bin"); print "\n"; print "F*EX update installed.\n"; print "You can inform your users about the new features with:\n"; print "$FEXHOME/bin/fexwall 'new F*EX features on $hostname' ". "< $FEXHOME/doc/newfeatures\n"; } if (@local_rdomains and not @local_rhosts) { print "\nWARNING:\n"; print "In $fph you have \@local_rdomains but not \@local_rhosts!\n"; print "Selfregistrating of external users will not work!\n"; print "See ${fph}_new/\n"; } if (`$sendmail -h 2>&1 /dev/null` !~ /\bfex\b/) { print "\nWARNING:\n"; print "$sendmail is exim\n"; print "You MUST set in your exim4.conf:\n"; print "trusted_users = mail : uucp : fex\n"; } exit; sub mkfid { my $ad = dirname($aa); mkdir $ad; open $aa,'>',$aa or die "$0: cannot create $aa - $!\n"; print {$aa} "$admin_pw\n"; close $aa; my $fd = dirname($fid); mkdir $fd; rename $fid,$fid.'_save'; open $fid,'>',$fid or die "$0: cannot create $fid - $!\n"; print {$fid} "$hostname:$opt_p\n"; print {$fid} "$admin\n"; print {$fid} "$admin_pw\n"; close $fid; chownr('fex',$ad,$fd); chmod 0700,$ad,$fd; } sub chownr { my $user = shift; local $_; foreach (@_) { if (m:^/*(lib|usr|home)?/*$:) { die "ERROR: short path in chownr $user @_\n"; } } system qw'chown -R',$user,@_; } sub chmodr { my $mod = shift; local $_; foreach (@_) { if (m:^/*(lib|usr|home)?/*$:) { die "ERROR: short path in chmodr $mod @_\n"; } } system qw'chmod -R',$mod,@_; } sub convert_spool { my ($f,$d,$to,$from,$link); local $) = $FEX[3]; local $> = $FEX[2]; our ($spooldir,$skeydir,$gkeydir); $ENV{FEXLIB} = $FEXLIB = "$FEXHOME/lib"; require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n"; die "no \$spooldir in $FEXLIB/fex.pp\n" unless $spooldir; die "\$spooldir=$spooldir/" if $spooldir =~ m:^/*(root)?$:; # User --> user@maildomain if ($mdomain) { foreach $f (glob "$spooldir/.dkeys/*") { if ($link = readlink $f) { (undef,$to,$from,$file) = split('/',$link); if ($file) { $to .= '@'.$mdomain if $to !~ /@/; $from .= '@'.$mdomain if $from !~ /@/; if ($link ne "../$to/$from/$file") { symlink "../$to/$from/$file",$f; } } } } } # fix spool layout: FROM and TO must have domains and must be lower case foreach $d ((glob "$spooldir/*/*"),(glob "$spooldir/*")) { if (not -l $d and -d $d and $d =~ m:(.+)/(.+):) { $p = $1; $b = $2; if ($b !~ /^@/ and $b !~ /^[A-Z_-]+$/) { if ($mdomain and $b !~ /@/) { rename $d,sprintf("%s/%s@%s",$p,lc($b),$mdomain); } elsif ($b ne lc($b)) { rename $d,sprintf("%s/%s",$p,lc($b)); } } } } # split auth-ID and subuser file: @ --> @ @SUBUSER foreach my $u (glob "$spooldir/*@*") { next if -f "$u/\@SUBUSER"; open my $idf,"$u/\@" or next; $id = <$idf>; if (defined ($su = <$idf>) and $su =~ /\w/ and open my $suf,">$u/\@SUBUSER") { print {$suf} $su; while (defined ($su = <$idf>)) { print {$suf} $su } close $suf; close $idf; if (open my $idf,">$u/\@") { print {$idf} $id; close $idf; } } } # create new SKEYs foreach my $sf (glob "$spooldir/*/\@SUBUSER") { $user = (split '/',$sf)[-2]; if (open $sf,$sf) { while (<$sf>) { s/#.*//; if (/(.+\@.+):(.+)/) { ($subuser,$id) = ($1,$2); next if $subuser =~ /\*/; $skey = md5_hex("$user:$subuser:$id"); if (open $skey,'>',"$skeydir/$skey") { print {$skey} "from=$subuser\n", "to=$user\n", "id=$id\n"; close $skey; } mkdirp("$spooldir/$subuser/\@MAINUSER"); symlink $skey,"$spooldir/$subuser/\@MAINUSER/$user"; } } } close $sf; } # create new GKEYs foreach my $gf (glob "$spooldir/*/\@GROUP/*") { next unless -f $gf; # normalize group name if ($gf =~ m:(.+)/(.+):) { my $gd = $1; my $g1 = $2; my $g2 = $2; $g2 =~ s/[^\w\*%^+=:,.!-]/_/g; if ($g1 ne $g2) { rename "$gd/$g1","$gd/$g2" and $gf = "$gd/$g2"; } } $group = (split '/',$gf)[-1]; $user = (split '/',$gf)[-3]; if (open $gf,$gf) { while (<$gf>) { s/#.*//; if (/(.+\@.+):(.+)/) { ($gm,$id) = ($1,$2); $gkey = md5_hex("$user:$group:$gm:$id"); if (open $gkey,'>',"$gkeydir/$gkey") { print {$gkey} "from=$gm\n", "to=\@$group\n", "user=$user\n", "id=$id\n"; close $gkey; } mkdirp("$spooldir/$gm/\@GROUP"); symlink "../../$user/\@GROUP/$group","$spooldir/$gm/\@GROUP/$group"; } } } close $gf; } } sub cpav { my $dd = pop @_; local *P; die "cpav: $dd is not a directory" unless -d $dd; open P,"tar cf - @_ | su -c 'cd $dd; umask 022; tar xvf - 2>&1' fex |" or die "cpav: cannot tar - $!\n"; while (

      ) { chomp; print "$_ --> $dd/$_\n" unless /\/$/; } close P; } fex-20160919/upgrade0000777000174700017470000000000012770010176013654 2installustar fexfex