[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#776646: marked as done (unblock: fex/20150120-2)



Your message dated Sun, 22 Feb 2015 10:58:54 +0100
with message-id <20150222095853.GA18399@ugent.be>
and subject line Re: Bug#776646: unblock: fex/20150120-2
has caused the Debian Bug report #776646,
regarding unblock: fex/20150120-2
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
776646: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=776646
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package fex

Version 20150120-2 fixes a security race condition where the cleanup
script would delete a state of a freshly registered user (if
registration is allowed) granting full user privileges instead of
restricted ones (if so configured).

Also the version 20150120-2 fixes that the fex-utils by default don't
connect to SSLv3 any more (and other SSL parameters are configurable).

Attached is the (quite large) diff against the version in testing
(20140917-2) which however has multiple copies of the same update (in
every cli client) and does contain upstreams new copy of the cli tools
in htdocs/download (as well as 3 scripts that upstream needs yet we
don't ship in the deb). Stripping the diff down to what we need gives
more or less this:
 bin/fac                                  |   56 ++
 bin/fbm                                  |   58 ++
 bin/fex_cleanup                          |   55 ++
 bin/fexget                               |  400 +++++++++++++++-----
 bin/fexsend                              |  614 ++++++++++++++++++++++---------
 bin/fexsrv                               |   19 
 bin/fexwall                              |   37 +
 bin/logwatch                             |   67 ++-
 bin/sexget                               |  211 +++++++++-
 bin/sexsend                              |  211 +++++++++-
 bin/sexxx                                |  211 +++++++++-
 bin/xx                                   |  614 ++++++++++++++++++++++---------
 cgi-bin/fac                              |    2 
 cgi-bin/foc                              |   14 
 cgi-bin/fop                              |    6 
 cgi-bin/fuc                              |   35 +
 cgi-bin/fup                              |  347 +++++++++--------
 cgi-bin/fur                              |   29 +
 cgi-bin/rup                              |   38 -
 cgi-bin/sex                              |   16 
 debian/changelog                         |   29 +
 debian/control                           |    6 
 debian/fex.lintian-overrides             |    3 
 debian/fex.postinst                      |    4 
 debian/htdocs.md5/20150120-2             |   26 +
 debian/patches/03_fexget_search_ca.patch |  123 ++++++
 debian/patches/series                    |    1 
 debian/rules                             |    2 
 doc/Changes                              |   47 ++
 doc/Contribs                             |    5 
 doc/SSL                                  |    4 
 doc/concept                              |   45 +-
 doc/installation                         |    7 
 doc/newfeatures                          |   21 +
 doc/version                              |    2 
 htdocs/FAQ/admin.faq                     |   11 
 htdocs/FAQ/faq.pl                        |   31 +
 htdocs/FAQ/meta.faq                      |    4 
 htdocs/FAQ/user.faq                      |   40 +-
 htdocs/features.html                     |    1 
 htdocs/version                           |    2 
 lib/dop                                  |   56 ++
 lib/fex.ph                               |    5 
 lib/fex.pp                               |  112 ++++-
 lib/fup.pl                               |    6 
 locale/czech/htdocs/FAQ.html             |  271 -------------
 locale/german/htdocs/FAQ.html            |    2 
 locale/italian/htdocs/FAQ.html           |    3 
 locale/spanish/htdocs/FAQ.html           |    6 
 locale/translations                      |  255 ++++++++----
 50 files changed, 3001 insertions(+), 1169 deletions(-)

unblock fex/20150120-2

TIA!

Best,
Kilian
diff -Nru fex-20140917/bin/afex fex-20150120/bin/afex
--- fex-20140917/bin/afex	2013-08-29 09:40:16.000000000 +0200
+++ fex-20150120/bin/afex	2014-12-24 01:17:15.000000000 +0100
@@ -4,7 +4,7 @@
 #
 # Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
 #
-# Copyright: Perl Artistic
+# Perl Artistic Licence
 
 $fexserver = '';
 
diff -Nru fex-20140917/bin/asex fex-20150120/bin/asex
--- fex-20140917/bin/asex	2013-08-29 09:40:16.000000000 +0200
+++ fex-20150120/bin/asex	2014-12-24 01:17:15.000000000 +0100
@@ -4,7 +4,7 @@
 #
 # Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
 #
-# Copyright: Perl Artistic
+# Perl Artistic Licence
 
 $fexserver = '';
 
diff -Nru fex-20140917/bin/fac fex-20150120/bin/fac
--- fex-20140917/bin/fac	2014-08-27 18:51:44.000000000 +0200
+++ fex-20150120/bin/fac	2014-12-08 16:02:19.000000000 +0100
@@ -57,8 +57,8 @@
 $EDITOR = $ENV{EDITOR} || $ENV{VISUAL} ||
           (-x '/usr/bin/editor' ? '/usr/bin/editor' : 'vi');
 
-$opt_c = $opt_v = $opt_l = $opt_h = $opt_w = $opt_u = $opt_R = $opt_M = 0;
-$opt_E = 0;
+$opt_c = $opt_v = $opt_l = $opt_L = $opt_h = $opt_w = $opt_u = $opt_R = 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_/'} = '';
@@ -80,9 +80,9 @@
   warn "WARNING: \$spooldir differs from $FEXHOME/spool !\n";
 }
   
-getopts('hcvlwuMRE/q:r:d:a:n:k:m:y:S:C:A:V:D:P:') or usage(2);
-usage(0)  if $opt_h;
-example() if $opt_E;
+getopts('hcvlLwuMRE/q:r:d:a:n:k:m:y:S:C:A:V:D:P:') or usage(2);
+usage(0)   if $opt_h;
+examples() if $opt_E;
 
 if (${'opt_/'}) {
   my $admin = shift;
@@ -155,7 +155,7 @@
   exit;
 }
 
-# resend notification e-mails
+# list files or resend notification e-mails
 if ($opt_M) {
   my ($mtime,$comment,$file,$keep);
   local $_;
@@ -220,12 +220,40 @@
   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";
-  unlink "$spooldir/$opt_d/\@ALLOWED_RECIPIENTS";
+  foreach $rf (glob "$spooldir/$opt_d/\@*") { unlink $rf }
   print "$opt_d deleted\n";
   exit;
 }
@@ -809,6 +837,13 @@
 }
 
 
+sub d3 {
+  local $_ = shift;
+  while (s/(\d)(\d\d\d\b)/$1,$2/) {};
+  return $_;
+}
+
+
 sub usage {
   my $port = '';
   my $proto = 'http';
@@ -839,14 +874,15 @@
 $0 -y user [yn]       # set user "fex yourself" web default (yes,no)
 $0 -S fup             # file upload statistics
 $0 -S fop             # file download statistics
-$0 -A alias:hostname  # add new virtual server
 $0 -v                 # show server config
 $0 -c                 # edit server config
+$0 -w                 # watch fexsrv.log (continously)
 $0 -l                 # list pending files with download URLs
+$0 -L [filter]        # list pending files in detail
 $0 -M                 # list pending files with TO/FROM/FILE
 $0 -M TO/FROM/FILE    # resend notification email
-$0 -w                 # watch fexsrv.log (continously)
 $0 -m "reason"        # enter maintenance mode (reason "exit" to leave)
+$0 -A alias:hostname  # add new virtual server
 $0 -V virtualhost ... # operations on virtualhost (alias or hostname)
 $0 -E                 # show usage examples
 EOD
@@ -856,7 +892,7 @@
   exit shift;
 }
 
-sub example {
+sub examples {
   $0 =~ s:.*/::;
   print <<EOD;
 create new user:
diff -Nru fex-20140917/bin/fbm fex-20150120/bin/fbm
--- fex-20140917/bin/fbm	2013-09-12 18:10:08.000000000 +0200
+++ fex-20150120/bin/fbm	2014-12-02 13:34:20.000000000 +0100
@@ -20,7 +20,7 @@
 
 our ($SH,$windoof,$sigpipe,$useragent);
 our ($FEXSERVER);
-our $version = 20140917;
+our $version = 20150120;
 
 # server defaults
 my $server = 'fex.rus.uni-stuttgart.de';
@@ -150,9 +150,59 @@
   serverconnect($server,$port);
     
   $boundary = randstring(48);
-  $filename = 'test_'.int(time*1000);
+  $P{command} = 'CHECKRECIPIENT';
   
-  # send HTTP POST variables
+  # 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}) {
@@ -164,7 +214,7 @@
     }
   }
   
-  # at last, POST the file
+  # at last, the file
   push @hb,"--$boundary";
   push @hb,"Content-Disposition: form-data; name=\"FILE\"; filename=\"$filename\"";
   push @hb,"Content-Type: application/octet-stream";
diff -Nru fex-20140917/bin/fex_cleanup fex-20150120/bin/fex_cleanup
--- fex-20140917/bin/fex_cleanup	2014-09-14 01:20:17.000000000 +0200
+++ fex-20150120/bin/fex_cleanup	2014-12-19 00:16:27.000000000 +0100
@@ -106,9 +106,24 @@
       }
     }
     closedir TO;
-    @glob = glob "$to/*/* $to/\@MAINUSER/* $to/\@GROUP/*";
-    unless (@glob or -f "$to/\@") {
-      logdel($to,"$to deleted");
+    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("$isodate $user reanimated (login_check)");
+          }
+        } else {
+          rename "$user/@","$user/\@~" unless $opt_d;
+          logv("$user deactivated (login_check)");
+        }
+      }
     }
   }
 }
@@ -173,8 +188,9 @@
   while ($file = readdir D) {
     if (-f $file) {
       $mtime = mtime($file);
-      if ($mtime and $today > 5*$keep_default*DS+$mtime) {
-        logdel($file,".error/$file deleted");
+      if ($mtime and $today > 10*$keep_default*DS+$mtime) {
+        if ($opt_d) { print "unlink .error/$file\n" }
+        else        { logdel($file,".error/$file deleted") }
       }
     }
   }
@@ -328,8 +344,8 @@
       next if -e "$user/\@PERSISTENT";
       next if $user !~ /@/ or -l $user;
       next if $user =~ /^(fexmaster|fexmail)/ or $user eq $admin;
-      next if $login_check and &$login_check(readlink("$user/.login"));
-      
+      next if -l "$user/.login";
+
       if (time > mtime($user)+$expire*DS) {
         # print "$spooldir/$user\n";
         my $locale = readlink "$user/\@LOCALE";
@@ -347,10 +363,11 @@
 # vhosts
 exit if $opt_V;
 if (%vhost) {
-  foreach $vhost (values %vhost) {
-    if (-f "$vhost/lib/fex.ph") {
-      warn "run $0 on $vhost/spool :\n" if -t or $opt_v;
-      my $cmd = "FEXLIB=$vhost/lib $_0 -V @_ARGV";
+  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 }
     }
@@ -508,6 +525,7 @@
       );
       open $notify,'>',$notify;
       close $notify;
+      print "sent reminder for $file\n" if -t or $opt_v;
     }
   }
 }
@@ -540,8 +558,7 @@
     print "$msg\n";
   } else {
     if ($status = rmrf($file)) {
-      print L "$isodate $msg\n";
-      print   "$msg\n" if -t or $opt_v;
+      logv($msg);
     } else {
       print L "$isodate $file DEL FAILED : $!\n";
       warn     "$file DEL FAILED : $!\n" if -t or $opt_v;
@@ -551,12 +568,20 @@
   return $status;
 }
 
+
+sub logv {
+  my $msg = shift;
+  print L "$isodate $msg\n" unless $opt_d;
+  print "$msg\n" if -t or $opt_v;
+}
+
+
 sub verbose {
   local $_;
   if ($opt_v) {
     while ($_ = shift @_) {
-      s/\n//;
-      print "$_\n";
+      s/\n*$/\n/;
+      print;
     }
   }
 }
diff -Nru fex-20140917/bin/fexget fex-20150120/bin/fexget
--- fex-20140917/bin/fexget	2014-08-15 14:31:24.000000000 +0200
+++ fex-20150120/bin/fexget	2015-01-19 13:59:57.000000000 +0100
@@ -6,7 +6,7 @@
 #
 # Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
 #
-# Copyright: Perl Artistic
+# Perl Artistic Licence
 
 use 5.006;
 use strict qw'vars subs';
@@ -14,6 +14,7 @@
 use POSIX;
 use Encode;
 use Getopt::Std;
+use File::Basename;
 use Socket;
 use IO::Handle;
 use IO::Socket::INET;
@@ -23,13 +24,19 @@
 
 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 = 20140917;
+our $version = 20150120;
 our $CTYPE = 'ISO-8859-1';
 our $fexsend = $ENV{FEXSEND} || 'fexsend';
 
+my %SSL = (SSL_version => 'TLSv1');
+my $sigpipe;
+
 # inquire default character set
 # cannot use "use I18N::Langinfo" because of no windows support!
 eval {
@@ -39,8 +46,6 @@
   $CTYPE = langinfo(CODESET());
 };
 
-$version = mtime($0) unless $version;
-
 if ($Config{osname} =~ /^mswin/i) {
   $windoof = $Config{osname};
   $ENV{HOME} = $ENV{USERPROFILE};
@@ -49,6 +54,7 @@
   $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;
 } else {
@@ -62,8 +68,9 @@
   $useragent = "fexget-$version ($_)";
 }
 
-$| = 1;
-
+if (-f ($_ = '/etc/fex/config.pl')) {
+  eval { require } or warn $@;
+}
 
 my $usage = <<EOD;
 usage: $0 [-v] [-m limit] [-s filename] [-o] [-k] [-X] [-P proxy:port] F*EX-URL(s)
@@ -71,21 +78,49 @@
    or: $0 [-v] -f F*EX-URL(s) e-mail-address
    or: $0 [-v] -a
    or: $0 -l [-i tag]
+   or: $0 -H
 options: -v verbose mode
          -m limit kB/s
          -s save to filename (-s- means: write to STDOUT/pipe)
          -o overwrite existing file
   	 -k keep on server after download
-  	 -X do not extract archive files
+  	 -X do not extract archive files or autoview file
   	 -d delete without download
   	 -f forward a file to another recipient
          -a get all files (implies -X)
   	 -l list files on server
          -i tag alternate server/account, see: $fexsend -h
          -P use Proxy for connection to the F*EX server
+         -H show hints and examples
 argument: F*EX-URL may be file number (see: $0 -l)
 EOD
 
+my $hints = <<'EOD';
+When you download a file with extension .jpg .gif .png or .tif an image viewer
+will be started. This can be xv or xdg-open.
+In $HOME/.fex/config.pl you can set your prefered autoview applications:
+
+%autoview = (
+  '\.(gif|jpg|png|tiff?)' => '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\"";
@@ -100,12 +135,13 @@
 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);
+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 = 0;
+$opt_V = $opt_X = $opt_f = $opt_L = $opt_H = 0;
 ${'opt_+'} = 0;
 $opt_s = $opt_k = $opt_i = $opt_P = '';
-getopts('hvVlLdkzoaXf+m:s:i:K:P:') or die $usage;
+$_ = "$fexhome/config.pl"; require if -f;
+getopts('hvVHlLdkzoaXf+m:s:i:K:P:') or die $usage;
 $opt_k = '?KEEP' if $opt_k;
 
 if ($opt_m =~ /(\d+)/) {
@@ -116,6 +152,53 @@
 
 print "Version: $version\n" if $opt_V;
 die $usage                  if $opt_h;
+if ($opt_H) {
+  print $hints;
+  exit;
+}
+
+# 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;
+    }
+  }
+}
 
 my $ffl = "$tmpdir/fexget"; 		# F*EX files list (cache)
 
@@ -203,7 +286,7 @@
   }
 }
 
-foreach my $url (@ARGV) {
+URL: foreach my $url (@ARGV) {
 
   # do not overrun server
   sleep 1 if $fop;
@@ -303,16 +386,38 @@
     }
   }
 
-  if (not $opt_X and $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";
+  unless ($opt_X) {
+    
+    foreach my $a (keys %autoview) {
+      if ($download =~ /$a$/i and $autoview{$a}) {
+        printf "run \"%s %s\" [Yn] ? ",$autoview{$a},basename($download);
+        $_ = <STDIN>||'';
+        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
+      if (my $xv = $xv || pathsearch('xv') || pathsearch('xdg-open')) {
+        printf "run \"%s %s\" [Yn] ? ",basename($xv),basename($download);
+        $_ = <STDIN>||'';
+        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";
+      }
     }
   }
 
@@ -716,29 +821,6 @@
 }
 
 
-# set up tcp/ip connection
-sub tcpconnect {
-  my ($server,$port) = @_;
-
-  if ($port == 443) {
-    eval "use IO::Socket::SSL";
-    $SH = IO::Socket::SSL->new(
-      PeerAddr => $server,
-      PeerPort => $port,
-      Proto    => 'tcp',
-    );
-  } 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;
-}
-
-
 sub locale {
   my $string = shift;
 
@@ -756,21 +838,59 @@
 }
 
 
-sub sendheader {
-  my $sp = shift;
-  my @head = @_;
-  my $head;
-
-  push @head,"Host: $sp";
-
-  foreach $head (@head) {
-    warn "--> $head\n" if $opt_v;
-    print {$SH} $head,"\r\n";
+sub pathsearch {
+  my $prg = shift;
+  
+  foreach my $dir (split(':',$ENV{PATH})) {
+    return "$dir/$prg" if -x "$dir/$prg";
   }
-  warn "-->\n" if $opt_v;
-  print {$SH} "\r\n";
 }
 
+    
+sub quote {
+  local $_ = shift;
+  s/([^\w¡-ÿ_%\/=~:.,-])/\\$1/g;
+  return $_;
+}
+
+    
+{
+  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;
+        foreach my $a (split("",$default)) { ioctl($tty,&TIOCSTI,$a) } 
+        chomp($_ = <STDIN>||'');
+      } else {
+        $prompt =~ s/([\?:=]\s*)/ [$default]$1/ or $prompt .= " [$default]";
+        print $prompt;
+        chomp($_ = <STDIN>||'');
+        $_ = $default unless length;
+      }
+    } else {
+      print $prompt;
+      chomp($_ = <STDIN>||'');
+    }
+
+    return $_;
+  }    
+}    
+
+
+### common functions ###
+
 
 sub mtime {
   my @d = localtime((stat shift)[9]);
@@ -784,11 +904,64 @@
   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 ($opt_v and $port == 443 and %SSL) {
+    foreach my $v (keys %SSL) {
+      printf "%s => %s\n",$v,$SSL{$v};
+    }
+  }
+  
   if ($proxy) {
     tcpconnect(split(':',$proxy));
     if ($port == 443) {
@@ -802,23 +975,78 @@
       }
       eval "use IO::Socket::SSL";
       die "$0: cannot load IO::Socket::SSL\n" if $@;
-      $SH = IO::Socket::SSL->start_SSL($SH);
+      $SH = IO::Socket::SSL->start_SSL($SH,%SSL);
     }
   } else {
     tcpconnect($server,$port);
   }
+#  if ($port == 443 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 ($port == 443) {
+    # eval "use IO::Socket::SSL qw(debug3)";
+    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',
+    );
+  }
+  
+  if ($SH) {
+    autoflush $SH 1;
+  } else {
+    die "$0: cannot connect $server:$port - $@\n";
+  }
+  
+  print "TCPCONNECT to $server:$port\n" if $opt_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";
 }
 
-my $sigpipe;
 
 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) {
@@ -826,39 +1054,21 @@
       return 0;
     }
   }
+  
+  return 1;
 }
 
 
-{
-  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;
-        foreach my $a (split("",$default)) { ioctl($tty,&TIOCSTI,$a) } 
-        chomp($_ = <STDIN>||'');
-      } else {
-        $prompt =~ s/([\?:=]\s*)/ [$default]$1/ or $prompt .= " [$default]";
-        print $prompt;
-        chomp($_ = <STDIN>||'');
-        $_ = $default unless length;
-      }
-    } else {
-      print $prompt;
-      chomp($_ = <STDIN>||'');
-    }
-
-    return $_;
-  }    
-}    
+# 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;
+}
diff -Nru fex-20140917/bin/fexsend fex-20150120/bin/fexsend
--- fex-20140917/bin/fexsend	2014-09-05 09:03:47.000000000 +0200
+++ fex-20150120/bin/fexsend	2015-01-16 15:52:53.000000000 +0100
@@ -6,7 +6,7 @@
 #
 # Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
 #
-# Copyright: Perl Artistic
+# Perl Artistic Licence
 
 use 5.006;
 use strict qw'vars subs';
@@ -27,17 +27,23 @@
 
 eval 'use Net::INET6Glue::INET_is_INET6';
 
-our ($SH,$fexhome,$idf,$tmpdir,$windoof,$sigpipe,$useragent,$editor,$nomail);
+&update if "@ARGV" eq 'UPDATE';
+
+$| = 1;
+
+our ($SH,$fexhome,$idf,$tmpdir,$windoof,$useragent,$editor,$nomail);
 our ($anonymous,$public);
-our ($tpid);
+our ($tpid,$frecipient);
 our ($FEXID,$FEXXX,$HOME);
+our (%alias);
 our $chunksize = 0;
-our $version = 20140917;
+our $version = 20150120;
 our $_0 = $0;
 our $DEBUG;
-  
-$version ||= mtime($0);
-  
+
+my %SSL = (SSL_version => 'TLSv1');
+my $sigpipe;
+
 if ($Config{osname} =~ /^mswin/i) {
   $windoof = $Config{osname};
   $HOME = $ENV{USERPROFILE};
@@ -47,6 +53,7 @@
   $editor = $ENV{EDITOR} || 'notepad.exe';
   $useragent = sprintf("fexsend-$version (%s %s)",
                        $Config{osname},$Config{archname});
+  $SSL{SSL_verify_mode} = 0;
 } else {
   $0 =~ s:.*/::;
   $HOME = (getpwuid($<))[7]||$ENV{HOME};
@@ -61,7 +68,9 @@
   chmod 0600,$idf;
 }
 
-$| = 1;
+if (-f ($_ = '/etc/fex/config.pl')) {
+  eval { require } or warn $@;
+}
 
 my $from = '';
 my $to = '';
@@ -79,7 +88,6 @@
 my $timeout = 30; 	# server timeout
 my $fexlist = "$tmpdir/fexlist";
 my ($usage,$hints);
-
 my $xx = $0 =~ /^xx/;
 
 if ($xx) {
@@ -97,7 +105,7 @@
 usage: $0 [options] file(s) [@] recipient(s)
    or: $0 [special options]
    or: $0 -f \# recipient(s)
-   or: $0 -x \# [-C -k -D -K]
+   or: $0 -x \# [-C -k -D -K -S]
 options: -v           verbose mode
          -d           delete file on fex server
          -c           compress file
@@ -114,13 +122,14 @@
          -s stream    read data from pipe and upload it with stream name
 special options: -I      initialize ID file or show ID
                  -I tag  add alternate ID data (secondary logins) to ID file
-                 -l      list sent files numbered (# needed for -f -x -d)
+                 -l      list sent files numbered (# needed for -f -x -d -N)
                  -f \#    forward already uploaded file to another recipient
                  -x \#    modify options -C -k -D -K for already uploaded file
                  -d \#    delete file on fex server
+                 -N \#    resend notification e-mail
                  -Q      check quotas
                  -A      edit server address book (aliases)
-                 -U      show authorized URL
+                 -S      show server/user settings and auth-ID
                  -H      show hints, examples and more options
                  -V      show version
                  (\# is a file number, see output from $0 -l)
@@ -132,7 +141,7 @@
 #         -R FEX mail  self-register your e-mail address at FEX server
 
   $hints = <<EOD;
-$0 Hints and more options:
+$0 hints and more options:
   
 usage: $0 [options] file recipient(s)
 
@@ -167,7 +176,7 @@
 If you want a Bcc of the notification e-mail then add '!bcc!' to the comment:
 fexsend -C '!bcc! for me and you' ...
 
-Special options:
+Additional special options:
 
   -. sends a short instead of a detailed notification e-mail
   -/ does not upload the file, but tells the server to link it
@@ -177,6 +186,7 @@
   -q is quiet mode
   -r ADDRESS sets e-mail Reply-To ADDRESS
   -F activates female mode
+  -U show authorized URL
   -+ is an undocumented feature - test it :-)
     
 To manage your subuser and groups or forward or redirect files, use a 
@@ -204,6 +214,13 @@
 without wasting local disc space.
  
 With option -X you can specify any parameter, e.g.: -X autodelete=yes
+
+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
   
 Partner program xx is an internet clipboard. See: xx -h
   
@@ -218,7 +235,27 @@
   FEXID="FEXSERVER USER AUTHID" $0 file recipient
 Example:
   FEXID="fex.flupp.org gaga\@flupp.org blubb" $0 big.file framstag\@rus.uni-stuttgart.de
-    
+
+You can define aliases (and optional fexsend options) in \$HOME/.fex/config.pl:
+  %alias = (
+    'alias1' => '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
 }
 
@@ -255,22 +292,25 @@
 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_o,$opt_g,$opt_F,$opt_n,$opt_r,$opt_S,$opt_N);
 
 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 {
   $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 = '';
-  getopts('hHvcdognVDKlILUARWMFzZqQ@!+./r:m:k:u:f:a:s:C:i:b:P:x:X:=:#:') 
+  $_ = "$fexhome/config.pl"; require if -f;
+  getopts('hHvcdognVDKlILUARWMFzZqQS@!+./r:m:k:u:f:a:s:C:i:b:P:x:X:N:=:#:') 
     or die $usage;
 
   if ($opt_H) {
@@ -307,16 +347,12 @@
     die "$0: you cannot use both options -I and -R\n";
   }
 
-  if ($opt_R) {
-    &register;
-    exit;
-  }
-
   # $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':
@@ -328,12 +364,21 @@
   $opt_D;
 }
 
+&get_ssl_env;
+
 if ($opt_h) {
   female_mode("show help?") if $opt_F;
   print $usage;
   exit;
 }
 
+
+if ($opt_R) {
+  &register;
+  exit;
+}
+
+
 die $usage if $opt_m and $opt_m !~ /^\d+/;
 
 if ($opt_P) { 
@@ -492,7 +537,7 @@
 
 &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);
+             $opt_f or $opt_x or $opt_N);
 
 if (${'opt_.'}) {
   $opt_C = "!SHORTMAIL! $opt_C";
@@ -503,20 +548,18 @@
 }
 
 unless ($skey or $gkey or $anonymous) {
-  if ($opt_v) {
-    if ($FEXID) {
-      warn "ID data from \$FEXID: $fexcgi $from $id\n";
-    } elsif (-f $idf) {
-      warn "ID data from $idf: $fexcgi $from $id\n";
-    }
-  }
-  warn "Server/User: $fexcgi/$from\n" unless $opt_q;
+  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 } 
@@ -817,7 +860,51 @@
     from	=> $from,
     to		=> $from,
     id		=> $sid,
-    comment	=> $opt_C, 
+    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;
@@ -825,6 +912,18 @@
     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 {
@@ -934,7 +1033,6 @@
 
 sub show_URL {
   printf "%s/fup/%s\n",$fexcgi,encode_b64("from=$from&id=$id");
-  exit;
 }
 
 
@@ -946,7 +1044,7 @@
     from	=> $from,
     to		=> $from,
     id		=> $sid,
-    comment	=> $opt_C, 
+    command	=> $opt_C, 
   );
   die "$0: no response from fex server $server\n" unless @r;
   $_ = shift @r;
@@ -1135,8 +1233,22 @@
         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?
-        if ($AB{$to}) {  
+        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};
@@ -1169,7 +1281,8 @@
       }
     }
   
-    $to = join(',',@to);
+    $to = join(',',grep /./,@to) or exit;
+    warn "Server/User: $fexcgi/$from\n" unless $opt_q;
   
     if (
       not $skey and not $gkey
@@ -1356,10 +1469,21 @@
     }
     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,$location);
       foreach (@r) {
-        if ($from eq $to or $from =~ /^\Q$to\E@/i or $nomail or $anonymous) {
-          print "$1\n" if /^X-(Recipient.*)/i;
-          print "$2\n" if /^(X-)?(Location:.*)/i;
+        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";
+            print "$location\n";
+          }
         }
       }
     }
@@ -1440,6 +1564,61 @@
 }
 
 
+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+) \[\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);
@@ -1702,11 +1881,12 @@
   if ($file and not $xx and not 
       ($opt_s or $opt_g or $opt_o or $opt_d or $opt_l or $opt_L or ${'opt_/'}))
   {
-    ($seek,$location) = query_file($server,$port,$P{to},$P{from},$P{id},
-                                   $filename,$fileid);
+    ($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;
-      die "$0: $file has been already transferred\n";
+      warn "$0: $file has been already transferred\n";
+      return $file;
     } elsif ($seek and $seek < $filesize) {
       $resume = " (resuming at byte $seek)";
     } elsif ($filesize <= $seek) {
@@ -2063,7 +2243,7 @@
   $zipbase =~ s/\.zip$//;
   map { s/([^_\w\+\-\.])/\\$1/g } @files;
 
-  open my $ff,"find @files -type f|" or die "$0: cannot search for @_ - $!\n";
+  open my $ff,"find @files|" or die "$0: cannot search for @_ - $!\n";
   @files = ();
 
   zipfile: for (;;) {
@@ -2075,7 +2255,8 @@
     $zsize = 0;
     while ($file = <$ff>) {
       chomp $file;
-      next if -l $file or not -f $file;
+      # next if -l $file or not -f $file;
+      next unless -f $file;
       $size = -s $file;
       if ($size > 2147480000) {
         unlink @zipfiles;
@@ -2114,7 +2295,10 @@
   }
   print $cmd,"\n" if $opt_v;
   open $cmd,"|$cmd" or die "$0: cannot create $zip - $!\n";
-  foreach (@_) { print {$cmd} $_."\n" }
+  foreach (@_) { 
+    print {$cmd} $_."\n";
+    print "  $_\n" if $opt_v;
+  }
   close $cmd or die "$0: zip failed - $!\n";
 
   return $zip;
@@ -2137,67 +2321,6 @@
 }
 
 
-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 query_file {
   my ($server,$port,$to,$from,$id,$filename,$fileid) = @_;
   my $seek = 0;
@@ -2480,42 +2603,6 @@
 }
 
 
-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;
-}
-
-
 # transfer status
 sub ts {
   my ($b,$tb) = @_;
@@ -2568,6 +2655,7 @@
         s/autodelete=\w+/autodelete=$opt_D/ if $opt_D;
         s/keep=\d+/keep=$opt_k/             if $opt_k;
         print;
+        $frecipient ||= (split)[1];
       }
     }
   } else {
@@ -2624,12 +2712,6 @@
 }
 
 
-sub mtime {
-  my @d = localtime((stat shift)[9]);
-  return sprintf('%d%02d%02d',$d[5]+1900,$d[4]+1,$d[3]);
-}
-
-
 # emulate seek on a pipe
 sub readahead {
   my $fh = shift; # filehandle
@@ -2706,21 +2788,6 @@
 }
 
 
-# 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;
-}
-
-
 sub female_mode {
   local $_;
   if (open my $tty,'/dev/tty') {
@@ -2742,6 +2809,7 @@
 sub http_response {
   local $_ = shift || <$SH>;
   my @r = @_;
+  my $error;
 
   $_ = <$SH> unless $_;
   unless (defined $_ and /\w/) {
@@ -2755,8 +2823,13 @@
     die "$0: server error: $_\n@r\n";
   }
   unless (/^HTTP.* 200/) {
-    s/HTTP.[\s\d.]+//;
-    die "$0: server error: $_\n";
+    $error = $_;
+    $error =~ s/HTTP.[\s\d.]+//;
+    if ($opt_v) {
+      print "<-- $_";
+      print "<-- $_" while <$SH>;
+    }
+    die "$0: server error: $error\n";
   }
 
   print "<-- $_\n" if $opt_v;
@@ -2764,6 +2837,48 @@
 }
 
 
+sub ws {
+  local $_ = shift;
+  return split;
+}
+
+
+sub update {
+  my $cfb = '### common functions ###';
+  my $cfc;
+  
+  local $/;
+  
+  open $0,$0 or die "cannot read $0 - $!\n";
+  $_ = <$0>;
+  close $0;
+  s/.*\n$cfb\n//s;
+  $cfc = $_;
+  
+  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 $0 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;
@@ -2771,7 +2886,170 @@
 }
 
 
-sub ws {
-  local $_ = shift;
-  return split;
+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 ($opt_v and $port == 443 and %SSL) {
+    foreach my $v (keys %SSL) {
+      printf "%s => %s\n",$v,$SSL{$v};
+    }
+  }
+  
+  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,%SSL);
+    }
+  } else {
+    tcpconnect($server,$port);
+  }
+#  if ($port == 443 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 ($port == 443) {
+    # eval "use IO::Socket::SSL qw(debug3)";
+    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',
+    );
+  }
+  
+  if ($SH) {
+    autoflush $SH 1;
+  } else {
+    die "$0: cannot connect $server:$port - $@\n";
+  }
+  
+  print "TCPCONNECT to $server:$port\n" if $opt_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;
+}
+
+
+# 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;
 }
diff -Nru fex-20140917/bin/fexsrv fex-20150120/bin/fexsrv
--- fex-20140917/bin/fexsrv	2014-09-16 11:32:41.000000000 +0200
+++ fex-20150120/bin/fexsrv	2014-12-16 15:20:32.000000000 +0100
@@ -77,11 +77,6 @@
   SID CHECKRECIPIENT GROUPS QUOTA FILEID MULTIPOST XKEY FILEQUERY FILESTREAM
   JUP NOSTORE AXEL FEXMAIL FILELINK
 ));
-  
-# ignore bullshit requests
-my $ignore = join('|',(
-  '^GET /w00tw00t\.at\.ISC\.SANS',
-));
 
 $port = 0;
 
@@ -219,11 +214,6 @@
       if ($ENV{PROTO} eq 'https') { $port = 443 }
       else                        { $port = 80 }
     }
-
-    if (/$ignore/) {
-      fexlog($connect,@log,'IGNORED');
-      exit;
-    }
   }
 
   exit unless @header;
@@ -241,6 +231,7 @@
   $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;
   }
   
@@ -341,7 +332,7 @@
       exit;
     }
 
-    if (/^User-Agent: (FDM)/ and $header =~ /\nRange:/) {
+    if ($header =~ /\nRange:/ and /^User-Agent: (FDM)/) {
       disconnect($1,"499 Download Manager $1 Not Supported",30);
     }
     
@@ -776,7 +767,7 @@
 
 sub badlog {
   my $request = shift;
-  my $n = 1;
+  my @n;
   my $ed = "$spooldir/.error";
   local $_;
   
@@ -792,10 +783,10 @@
     if (open $ra,"+>>$ed/$ra") {
       flock($ra,LOCK_EX);
       seek $ra,0,SEEK_SET;
-      $n++ while <$ra>;
+      @n = <$ra>;
       printf {$ra} "%s %s\n",isodate(time),$request;
       close $ra;
-      &$max_error_handler($ra,$n) if $n > $max_error;
+      &$max_error_handler($ra,@n) if scalar(@n) > $max_error;
     }
   }
 }
diff -Nru fex-20140917/bin/fexwall fex-20150120/bin/fexwall
--- fex-20140917/bin/fexwall	2014-07-24 15:45:39.000000000 +0200
+++ fex-20150120/bin/fexwall	2015-01-15 09:36:20.000000000 +0100
@@ -62,12 +62,43 @@
   close $sig;
 }
 
+local $/ = "\n";
+
 chdir $spooldir or die "$0: $spooldir - $!\n";
 
-@users = grep { s:/@:: } glob("*/@");
+# @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";
 
@@ -82,6 +113,10 @@
 print "mail sent to:\n",map { "$_\n" } @users;
 exit;
 
+sub uniq {
+  my %x;
+  grep !$x{$_}++,@_;
+}
 
 sub usage {
   print "usage: $0 \"SUBJECT\" < mail.text\n";
diff -Nru fex-20140917/bin/l fex-20150120/bin/l
--- fex-20140917/bin/l	1970-01-01 01:00:00.000000000 +0100
+++ fex-20150120/bin/l	2014-12-09 12:31:43.000000000 +0100
@@ -0,0 +1,597 @@
+#!/usr/bin/perl -w
+#
+# l / ll / lf / llf -  substitute of the classic ls command
+#
+# Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
+#
+# Copyright: GNU General Public License 
+
+use Cwd qw'abs_path';
+use File::Basename;
+use Getopt::Std;
+
+# the name of the game
+$0 =~ s:.*/::;
+
+$ENV{LC_CTYPE} = 'C';
+
+# unshift @ARGV,split /\s+/,$ENV{'l_opt'} if $ENV{'l_opt'};
+
+@ARGV = grep { chomp } <STDIN> 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 = 0;
+${'opt_*'} = ${'opt_?'} = 0;
+$opt_m = $opt_f = $opt_F = $opt_D = '';
+&usage if !getopts('hdnlLNitcuarsUSRz*?m:f:D:F:') || $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';
+if ($0 eq 'lf' or $0 eq 'llf') {
+  unless ($opt_F) {
+    $opt_F = shift;
+    unless (length $opt_F) {
+      print "find regexp: ";
+      chomp($opt_F = <STDIN>||'');
+    }
+  }
+  $opt_l = $0 if $0 eq 'llf';
+  $opt_F = '.' unless length $opt_F;
+  $opt_R = $opt_F;
+}
+
+$postsort = $opt_t||$opt_s;
+$postproc = $postsort||$opt_z;
+
+&examples if ${'opt_?'};
+
+# 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;
+
+  # 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:/*$:/:;
+        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 {
+	    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) { $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 effektive file access modes
+        $mode = $type 
+	        . (-r _ ? 'R' : '-')
+                . (-w _ ? 'W' : '-')
+                . (-x _ ? 'X' : '-');
+        substr($mode,2,1) =~ tr/-x/Ss/ if -u _ or -g _;
+        substr($mode,3,1) =~ tr/-x/Tt/ if -k _;
+      }
+    }
+
+  # 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);
+}
+
+
+# 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";
+  }
+  
+  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);
+}
+
+
+# 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 $opts = '[-lastcuidnrzLRNS*] [-f format] [-D X:Y]';
+  if ($0 ne 'lf') { 
+    print "usage: $0 $opts [-F regexp] [file...]\n";
+  }
+  $opts =~ s/R//;
+  print "usage: lf $opts regexp [directory...]\n";
+  print <<EOD;
+options: -l  long list
+         -a  list also .* files
+         -s  sort by size
+         -t  sort by time
+         -U  sort by nothing (original i-node order)
+         -c  list status change time instead of modification time
+         -u  list last access time instead of modification time
+         -i  list also inode and hard links numbers
+         -d  do not list contents of diretories
+         -n  numerical output
+         -r  reverse list
+         -z  squeeze size field (slows down output)
+         -L  derefernce symbolic links
+         -R  recursive into subdirs
+         -F  find files matching case insensitive regexp
+         -N  show only normal (regular) files
+         -S  print statistics summary at end
+         -*  list plain file names (without masking \\)
+	 -f  user defined format output, format characters are:
+	     m=mode, u=user, g=group, s=size, l=hard links count, i=inode
+	     n=name only, d=date, a=access+modification+inodechange dates
+         -D  list only files newer than X and older than Y 
+             XY format: NUMBER[smhd] (s=seconds, m=minutes, h=hours, d=days)
+             XY format: YYYY-MM-DD (Y=year, M=month, D=day)
+         -?  show examples
+EOD
+  exit 2;
+}
+
+sub examples {
+  print <<EOD;
+l *.c            # list files ending with .c
+l -la            # list all files in long format
+l -Rrs           # list files recursive reverse sorted by size 
+l -*f mus        # list files native names with format: mode+user+size
+l -D 10d:        # list files newer than 10 days
+ll               # list files long format (equal to: l -l)
+lll              # list files extra long format (equal to: l -liS)
+lf 'status.*mp3' # list files recursive matching regexp (equal to: l -RF)
+lf sda3 /dev     # list devices matching sda3 (equal to: l -RF sd3 /dev)                                                       
+EOD
+  exit;
+}
diff -Nru fex-20140917/bin/lf fex-20150120/bin/lf
--- fex-20140917/bin/lf	1970-01-01 01:00:00.000000000 +0100
+++ fex-20150120/bin/lf	2014-12-09 12:31:43.000000000 +0100
@@ -0,0 +1,597 @@
+#!/usr/bin/perl -w
+#
+# l / ll / lf / llf -  substitute of the classic ls command
+#
+# Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
+#
+# Copyright: GNU General Public License 
+
+use Cwd qw'abs_path';
+use File::Basename;
+use Getopt::Std;
+
+# the name of the game
+$0 =~ s:.*/::;
+
+$ENV{LC_CTYPE} = 'C';
+
+# unshift @ARGV,split /\s+/,$ENV{'l_opt'} if $ENV{'l_opt'};
+
+@ARGV = grep { chomp } <STDIN> 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 = 0;
+${'opt_*'} = ${'opt_?'} = 0;
+$opt_m = $opt_f = $opt_F = $opt_D = '';
+&usage if !getopts('hdnlLNitcuarsUSRz*?m:f:D:F:') || $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';
+if ($0 eq 'lf' or $0 eq 'llf') {
+  unless ($opt_F) {
+    $opt_F = shift;
+    unless (length $opt_F) {
+      print "find regexp: ";
+      chomp($opt_F = <STDIN>||'');
+    }
+  }
+  $opt_l = $0 if $0 eq 'llf';
+  $opt_F = '.' unless length $opt_F;
+  $opt_R = $opt_F;
+}
+
+$postsort = $opt_t||$opt_s;
+$postproc = $postsort||$opt_z;
+
+&examples if ${'opt_?'};
+
+# 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;
+
+  # 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:/*$:/:;
+        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 {
+	    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) { $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 effektive file access modes
+        $mode = $type 
+	        . (-r _ ? 'R' : '-')
+                . (-w _ ? 'W' : '-')
+                . (-x _ ? 'X' : '-');
+        substr($mode,2,1) =~ tr/-x/Ss/ if -u _ or -g _;
+        substr($mode,3,1) =~ tr/-x/Tt/ if -k _;
+      }
+    }
+
+  # 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);
+}
+
+
+# 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";
+  }
+  
+  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);
+}
+
+
+# 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 $opts = '[-lastcuidnrzLRNS*] [-f format] [-D X:Y]';
+  if ($0 ne 'lf') { 
+    print "usage: $0 $opts [-F regexp] [file...]\n";
+  }
+  $opts =~ s/R//;
+  print "usage: lf $opts regexp [directory...]\n";
+  print <<EOD;
+options: -l  long list
+         -a  list also .* files
+         -s  sort by size
+         -t  sort by time
+         -U  sort by nothing (original i-node order)
+         -c  list status change time instead of modification time
+         -u  list last access time instead of modification time
+         -i  list also inode and hard links numbers
+         -d  do not list contents of diretories
+         -n  numerical output
+         -r  reverse list
+         -z  squeeze size field (slows down output)
+         -L  derefernce symbolic links
+         -R  recursive into subdirs
+         -F  find files matching case insensitive regexp
+         -N  show only normal (regular) files
+         -S  print statistics summary at end
+         -*  list plain file names (without masking \\)
+	 -f  user defined format output, format characters are:
+	     m=mode, u=user, g=group, s=size, l=hard links count, i=inode
+	     n=name only, d=date, a=access+modification+inodechange dates
+         -D  list only files newer than X and older than Y 
+             XY format: NUMBER[smhd] (s=seconds, m=minutes, h=hours, d=days)
+             XY format: YYYY-MM-DD (Y=year, M=month, D=day)
+         -?  show examples
+EOD
+  exit 2;
+}
+
+sub examples {
+  print <<EOD;
+l *.c            # list files ending with .c
+l -la            # list all files in long format
+l -Rrs           # list files recursive reverse sorted by size 
+l -*f mus        # list files native names with format: mode+user+size
+l -D 10d:        # list files newer than 10 days
+ll               # list files long format (equal to: l -l)
+lll              # list files extra long format (equal to: l -liS)
+lf 'status.*mp3' # list files recursive matching regexp (equal to: l -RF)
+lf sda3 /dev     # list devices matching sda3 (equal to: l -RF sd3 /dev)                                                       
+EOD
+  exit;
+}
diff -Nru fex-20140917/bin/ll fex-20150120/bin/ll
--- fex-20140917/bin/ll	1970-01-01 01:00:00.000000000 +0100
+++ fex-20150120/bin/ll	2014-12-09 12:31:43.000000000 +0100
@@ -0,0 +1,597 @@
+#!/usr/bin/perl -w
+#
+# l / ll / lf / llf -  substitute of the classic ls command
+#
+# Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
+#
+# Copyright: GNU General Public License 
+
+use Cwd qw'abs_path';
+use File::Basename;
+use Getopt::Std;
+
+# the name of the game
+$0 =~ s:.*/::;
+
+$ENV{LC_CTYPE} = 'C';
+
+# unshift @ARGV,split /\s+/,$ENV{'l_opt'} if $ENV{'l_opt'};
+
+@ARGV = grep { chomp } <STDIN> 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 = 0;
+${'opt_*'} = ${'opt_?'} = 0;
+$opt_m = $opt_f = $opt_F = $opt_D = '';
+&usage if !getopts('hdnlLNitcuarsUSRz*?m:f:D:F:') || $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';
+if ($0 eq 'lf' or $0 eq 'llf') {
+  unless ($opt_F) {
+    $opt_F = shift;
+    unless (length $opt_F) {
+      print "find regexp: ";
+      chomp($opt_F = <STDIN>||'');
+    }
+  }
+  $opt_l = $0 if $0 eq 'llf';
+  $opt_F = '.' unless length $opt_F;
+  $opt_R = $opt_F;
+}
+
+$postsort = $opt_t||$opt_s;
+$postproc = $postsort||$opt_z;
+
+&examples if ${'opt_?'};
+
+# 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;
+
+  # 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:/*$:/:;
+        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 {
+	    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) { $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 effektive file access modes
+        $mode = $type 
+	        . (-r _ ? 'R' : '-')
+                . (-w _ ? 'W' : '-')
+                . (-x _ ? 'X' : '-');
+        substr($mode,2,1) =~ tr/-x/Ss/ if -u _ or -g _;
+        substr($mode,3,1) =~ tr/-x/Tt/ if -k _;
+      }
+    }
+
+  # 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);
+}
+
+
+# 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";
+  }
+  
+  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);
+}
+
+
+# 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 $opts = '[-lastcuidnrzLRNS*] [-f format] [-D X:Y]';
+  if ($0 ne 'lf') { 
+    print "usage: $0 $opts [-F regexp] [file...]\n";
+  }
+  $opts =~ s/R//;
+  print "usage: lf $opts regexp [directory...]\n";
+  print <<EOD;
+options: -l  long list
+         -a  list also .* files
+         -s  sort by size
+         -t  sort by time
+         -U  sort by nothing (original i-node order)
+         -c  list status change time instead of modification time
+         -u  list last access time instead of modification time
+         -i  list also inode and hard links numbers
+         -d  do not list contents of diretories
+         -n  numerical output
+         -r  reverse list
+         -z  squeeze size field (slows down output)
+         -L  derefernce symbolic links
+         -R  recursive into subdirs
+         -F  find files matching case insensitive regexp
+         -N  show only normal (regular) files
+         -S  print statistics summary at end
+         -*  list plain file names (without masking \\)
+	 -f  user defined format output, format characters are:
+	     m=mode, u=user, g=group, s=size, l=hard links count, i=inode
+	     n=name only, d=date, a=access+modification+inodechange dates
+         -D  list only files newer than X and older than Y 
+             XY format: NUMBER[smhd] (s=seconds, m=minutes, h=hours, d=days)
+             XY format: YYYY-MM-DD (Y=year, M=month, D=day)
+         -?  show examples
+EOD
+  exit 2;
+}
+
+sub examples {
+  print <<EOD;
+l *.c            # list files ending with .c
+l -la            # list all files in long format
+l -Rrs           # list files recursive reverse sorted by size 
+l -*f mus        # list files native names with format: mode+user+size
+l -D 10d:        # list files newer than 10 days
+ll               # list files long format (equal to: l -l)
+lll              # list files extra long format (equal to: l -liS)
+lf 'status.*mp3' # list files recursive matching regexp (equal to: l -RF)
+lf sda3 /dev     # list devices matching sda3 (equal to: l -RF sd3 /dev)                                                       
+EOD
+  exit;
+}
diff -Nru fex-20140917/bin/logwatch fex-20150120/bin/logwatch
--- fex-20140917/bin/logwatch	2014-09-12 17:00:29.000000000 +0200
+++ fex-20150120/bin/logwatch	2014-12-12 17:15:45.000000000 +0100
@@ -35,13 +35,15 @@
   GET.*(favicon|robots\.txt)
   GET./organization\.gif
   GET./small_logo\.jpg
+  GET./logo\.jpg
+  GET./action-fex-camel\.gif
+  GET./fup\?showstatus
   GET./FAQ/faq\.css
   GET./FAQ/jquery\.js
   GET./10+.B
   GET.*Arrow\.gif
   GET./apple-touch
-  User-Agent:.*(Webnote|FeedFetcher|\w+bot|bot/|Website.Watcher|crawler|spider|searchme|Yandex|Slurp|ScoutJet|findlinks|urlmon)
-  User-Agent:.ichiro
+  User-Agent:.*(Webnote|FeedFetcher|\w+bot|bot/|Website.Watcher|crawler|spider|searchme|Yandex|Slurp|ScoutJet|findlinks|urlmon|nagios)
   User-Agent:.fnb.*quak
   From:.*(msnbot|yandex|googlebot|webcrawler)
   Referer:.*sex.*stream
@@ -69,6 +71,7 @@
   http\.
   NOKIA_
   GPRS
+  X-Proxy-ID
   X-Moz
   X.Wap
   X-FH
@@ -97,7 +100,7 @@
 } else {
   *L = *STDIN;
 }
-binmode(L,":encoding(UTF-8)");
+# binmode(L,":encoding(UTF-8)");
 
 for (;;) {
   while (<L>) {
@@ -116,7 +119,11 @@
     }
     s/[\s\n]*$/\n\n/;
     print or exit;
-    if (m:\nGET /fop/(\w+)/:) {
+    $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;
@@ -125,21 +132,23 @@
       printf "  TO=\"%s\"\n",$to;
       $cgi = '';
       if ($comment = slurp("$ddir/comment")) {
-        printf "  COMMENT=\"%s\"\n",decode_utf8($comment)||'';
+        printf "  COMMENT=\"%s\"\n",decode_utf8($comment,0)||'';
       }
       if (not -f "$ddir/data" and $_ = slurp("$ddir/error")) {
         s/\n.*//s;
         print "  ERROR=\"$_\"\n";
       }
-      elsif ($size = readlink("$ddir/size")) {
+      elsif ($size = -s "$ddir/data") {
         printf "  SIZE=%s MB\n",int($size/1024/1024);
       }
-      print "\n" if $_;
+      print "\n";
+    } elsif (m:\nGET /fup.*skey=(\w+):) {
+      read_skey($1);
+      print "\n";
     }
   }
   sleep 1;
   if ($debug and $pid and $cgi) {
-    sleep 1;
     &read_debug_log;
     $pid = $cgi = '';
   };
@@ -149,28 +158,54 @@
 sub read_debug_log {
   my (@log,$log);
   local $/ = "\n";
+  local $_;
+  local $^W;
   # no warnings "all";
-  
-  if (@log = glob "$logdir/.debug/*_$pid.$cgi") {
-    $log = pop @log;
-    if (open $log,$log) {
-      binmode($log,":encoding(UTF-8)");
+
+  for (1..2) {
+    sleep 1;
+    @log = `ls -rt $logdir/.debug/*_${pid}.$cgi 2>/dev/null`;
+    if ($log = $log[-1] and open $log,$log) {
+      # binmode($log,":encoding(UTF-8)");
       while (<$log>) {
         s/\r//;
         if (/^Content-Disposition:.*name="FILE".*filename="(.+)"/i) {
           print "  FILE=\"$1\"\n";
         } elsif (/^Content-Disposition:.*name="(\w+)"/i) {
-          $p = $1;
+          my $p = uc($1);
           $_ = <$log>;
-          $v = <$log>;
+          my $v = <$log>||'';
           $v =~ s/[\r\n]+//;
-          printf "  %s=\"%s\"\n",$p,decode_utf8($v) if $v;
+          printf "  %s=\"%s\"\n",$p,decode_utf8($v,0)||$v if $v;
+          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;
   }
 }
diff -Nru fex-20140917/bin/sexget fex-20150120/bin/sexget
--- fex-20140917/bin/sexget	2014-07-26 16:43:02.000000000 +0200
+++ fex-20150120/bin/sexget	2015-01-19 13:59:57.000000000 +0100
@@ -4,7 +4,7 @@
 #
 # Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
 #
-# Copyright: Perl Artistic
+# Perl Artistic Licence
 
 # sexsend / sexget / sexxx
 
@@ -19,9 +19,14 @@
 
 eval 'use Net::INET6Glue::INET_is_INET6';
 
-our $version = 20140917;
+our $version = 20150120;
 
-$version = mtime($0) unless $version;
+my %SSL = (SSL_version => 'TLSv1');
+my $sigpipe;
+
+if (-f ($_ = '/etc/fex/config.pl')) {
+  eval { require } or warn $@;
+}
 
 $0 =~ s:.*/::;
 $| = 1;
@@ -30,6 +35,7 @@
 $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".
@@ -39,8 +45,8 @@
 if ($0 eq 'sexget' or $0 eq 'fuckme') {
   $usage = 
     "usage: $0 [options] [[SEX-URL/]user:ID] [stream]\n".
-    "options: -g           show transfer rate\n".
-    "         -v           verbose mode\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".
@@ -53,8 +59,8 @@
   $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: -g               show transfer rate\n".
-    "         -v               verbose mode\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".
@@ -93,6 +99,8 @@
 $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
@@ -206,6 +214,8 @@
   
 }
 
+&get_ssl_env;
+
 $fexcgi =~ s(^http://)()i;
 $fexcgi =~ s(/fup.*)();
 $server = $fexcgi;
@@ -223,12 +233,18 @@
 # 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',                                                         
+    Proto    => 'tcp',
+    %SSL
   );                                                                           
 } else {                                                                       
   $SH = IO::Socket::INET->new(
@@ -499,11 +515,6 @@
   return $line;
 }
 
-sub mtime {
-  my @d = localtime((stat shift)[9]);
-  return sprintf('%d%02d%02d',$d[5]+1900,$d[4]+1,$d[3]);
-}
-
 # from MIME::Base64::Perl
 sub decode_b64 {
   local $_ = shift;
@@ -527,12 +538,182 @@
 }
 
 
+### 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 ($opt_v and $port == 443 and %SSL) {
+    foreach my $v (keys %SSL) {
+      printf "%s => %s\n",$v,$SSL{$v};
+    }
+  }
+  
+  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,%SSL);
+    }
+  } else {
+    tcpconnect($server,$port);
+  }
+#  if ($port == 443 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 ($port == 443) {
+    # eval "use IO::Socket::SSL qw(debug3)";
+    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',
+    );
+  }
+  
+  if ($SH) {
+    autoflush $SH 1;
+  } else {
+    die "$0: cannot connect $server:$port - $@\n";
+  }
+  
+  print "TCPCONNECT to $server:$port\n" if $opt_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;
+}
+
+
+# from MIME::Base64::Perl
 sub encode_b64 {
   my $res = "";
-  my $eol = $_[1];
+  my $eol = "\n";
   my $padding;
   
-  $eol = "\n" unless defined $eol;
   pos($_[0]) = 0;
   $res = join '',map(pack('u',$_)=~ /^.(\S*)/, ($_[0]=~/(.{1,45})/gs));
   $res =~ tr|` -_|AA-Za-z0-9+/|;
diff -Nru fex-20140917/bin/sexsend fex-20150120/bin/sexsend
--- fex-20140917/bin/sexsend	2014-07-26 16:43:02.000000000 +0200
+++ fex-20150120/bin/sexsend	2015-01-19 13:59:57.000000000 +0100
@@ -4,7 +4,7 @@
 #
 # Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
 #
-# Copyright: Perl Artistic
+# Perl Artistic Licence
 
 # sexsend / sexget / sexxx
 
@@ -19,9 +19,14 @@
 
 eval 'use Net::INET6Glue::INET_is_INET6';
 
-our $version = 20140917;
+our $version = 20150120;
 
-$version = mtime($0) unless $version;
+my %SSL = (SSL_version => 'TLSv1');
+my $sigpipe;
+
+if (-f ($_ = '/etc/fex/config.pl')) {
+  eval { require } or warn $@;
+}
 
 $0 =~ s:.*/::;
 $| = 1;
@@ -30,6 +35,7 @@
 $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".
@@ -39,8 +45,8 @@
 if ($0 eq 'sexget' or $0 eq 'fuckme') {
   $usage = 
     "usage: $0 [options] [[SEX-URL/]user:ID] [stream]\n".
-    "options: -g           show transfer rate\n".
-    "         -v           verbose mode\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".
@@ -53,8 +59,8 @@
   $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: -g               show transfer rate\n".
-    "         -v               verbose mode\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".
@@ -93,6 +99,8 @@
 $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
@@ -206,6 +214,8 @@
   
 }
 
+&get_ssl_env;
+
 $fexcgi =~ s(^http://)()i;
 $fexcgi =~ s(/fup.*)();
 $server = $fexcgi;
@@ -223,12 +233,18 @@
 # 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',                                                         
+    Proto    => 'tcp',
+    %SSL
   );                                                                           
 } else {                                                                       
   $SH = IO::Socket::INET->new(
@@ -499,11 +515,6 @@
   return $line;
 }
 
-sub mtime {
-  my @d = localtime((stat shift)[9]);
-  return sprintf('%d%02d%02d',$d[5]+1900,$d[4]+1,$d[3]);
-}
-
 # from MIME::Base64::Perl
 sub decode_b64 {
   local $_ = shift;
@@ -527,12 +538,182 @@
 }
 
 
+### 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 ($opt_v and $port == 443 and %SSL) {
+    foreach my $v (keys %SSL) {
+      printf "%s => %s\n",$v,$SSL{$v};
+    }
+  }
+  
+  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,%SSL);
+    }
+  } else {
+    tcpconnect($server,$port);
+  }
+#  if ($port == 443 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 ($port == 443) {
+    # eval "use IO::Socket::SSL qw(debug3)";
+    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',
+    );
+  }
+  
+  if ($SH) {
+    autoflush $SH 1;
+  } else {
+    die "$0: cannot connect $server:$port - $@\n";
+  }
+  
+  print "TCPCONNECT to $server:$port\n" if $opt_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;
+}
+
+
+# from MIME::Base64::Perl
 sub encode_b64 {
   my $res = "";
-  my $eol = $_[1];
+  my $eol = "\n";
   my $padding;
   
-  $eol = "\n" unless defined $eol;
   pos($_[0]) = 0;
   $res = join '',map(pack('u',$_)=~ /^.(\S*)/, ($_[0]=~/(.{1,45})/gs));
   $res =~ tr|` -_|AA-Za-z0-9+/|;
diff -Nru fex-20140917/bin/sexxx fex-20150120/bin/sexxx
--- fex-20140917/bin/sexxx	2014-07-26 16:43:02.000000000 +0200
+++ fex-20150120/bin/sexxx	2015-01-19 13:59:57.000000000 +0100
@@ -4,7 +4,7 @@
 #
 # Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
 #
-# Copyright: Perl Artistic
+# Perl Artistic Licence
 
 # sexsend / sexget / sexxx
 
@@ -19,9 +19,14 @@
 
 eval 'use Net::INET6Glue::INET_is_INET6';
 
-our $version = 20140917;
+our $version = 20150120;
 
-$version = mtime($0) unless $version;
+my %SSL = (SSL_version => 'TLSv1');
+my $sigpipe;
+
+if (-f ($_ = '/etc/fex/config.pl')) {
+  eval { require } or warn $@;
+}
 
 $0 =~ s:.*/::;
 $| = 1;
@@ -30,6 +35,7 @@
 $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".
@@ -39,8 +45,8 @@
 if ($0 eq 'sexget' or $0 eq 'fuckme') {
   $usage = 
     "usage: $0 [options] [[SEX-URL/]user:ID] [stream]\n".
-    "options: -g           show transfer rate\n".
-    "         -v           verbose mode\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".
@@ -53,8 +59,8 @@
   $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: -g               show transfer rate\n".
-    "         -v               verbose mode\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".
@@ -93,6 +99,8 @@
 $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
@@ -206,6 +214,8 @@
   
 }
 
+&get_ssl_env;
+
 $fexcgi =~ s(^http://)()i;
 $fexcgi =~ s(/fup.*)();
 $server = $fexcgi;
@@ -223,12 +233,18 @@
 # 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',                                                         
+    Proto    => 'tcp',
+    %SSL
   );                                                                           
 } else {                                                                       
   $SH = IO::Socket::INET->new(
@@ -499,11 +515,6 @@
   return $line;
 }
 
-sub mtime {
-  my @d = localtime((stat shift)[9]);
-  return sprintf('%d%02d%02d',$d[5]+1900,$d[4]+1,$d[3]);
-}
-
 # from MIME::Base64::Perl
 sub decode_b64 {
   local $_ = shift;
@@ -527,12 +538,182 @@
 }
 
 
+### 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 ($opt_v and $port == 443 and %SSL) {
+    foreach my $v (keys %SSL) {
+      printf "%s => %s\n",$v,$SSL{$v};
+    }
+  }
+  
+  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,%SSL);
+    }
+  } else {
+    tcpconnect($server,$port);
+  }
+#  if ($port == 443 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 ($port == 443) {
+    # eval "use IO::Socket::SSL qw(debug3)";
+    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',
+    );
+  }
+  
+  if ($SH) {
+    autoflush $SH 1;
+  } else {
+    die "$0: cannot connect $server:$port - $@\n";
+  }
+  
+  print "TCPCONNECT to $server:$port\n" if $opt_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;
+}
+
+
+# from MIME::Base64::Perl
 sub encode_b64 {
   my $res = "";
-  my $eol = $_[1];
+  my $eol = "\n";
   my $padding;
   
-  $eol = "\n" unless defined $eol;
   pos($_[0]) = 0;
   $res = join '',map(pack('u',$_)=~ /^.(\S*)/, ($_[0]=~/(.{1,45})/gs));
   $res =~ tr|` -_|AA-Za-z0-9+/|;
diff -Nru fex-20140917/bin/xx fex-20150120/bin/xx
--- fex-20140917/bin/xx	2014-09-05 09:03:47.000000000 +0200
+++ fex-20150120/bin/xx	2015-01-16 15:52:53.000000000 +0100
@@ -6,7 +6,7 @@
 #
 # Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
 #
-# Copyright: Perl Artistic
+# Perl Artistic Licence
 
 use 5.006;
 use strict qw'vars subs';
@@ -27,17 +27,23 @@
 
 eval 'use Net::INET6Glue::INET_is_INET6';
 
-our ($SH,$fexhome,$idf,$tmpdir,$windoof,$sigpipe,$useragent,$editor,$nomail);
+&update if "@ARGV" eq 'UPDATE';
+
+$| = 1;
+
+our ($SH,$fexhome,$idf,$tmpdir,$windoof,$useragent,$editor,$nomail);
 our ($anonymous,$public);
-our ($tpid);
+our ($tpid,$frecipient);
 our ($FEXID,$FEXXX,$HOME);
+our (%alias);
 our $chunksize = 0;
-our $version = 20140917;
+our $version = 20150120;
 our $_0 = $0;
 our $DEBUG;
-  
-$version ||= mtime($0);
-  
+
+my %SSL = (SSL_version => 'TLSv1');
+my $sigpipe;
+
 if ($Config{osname} =~ /^mswin/i) {
   $windoof = $Config{osname};
   $HOME = $ENV{USERPROFILE};
@@ -47,6 +53,7 @@
   $editor = $ENV{EDITOR} || 'notepad.exe';
   $useragent = sprintf("fexsend-$version (%s %s)",
                        $Config{osname},$Config{archname});
+  $SSL{SSL_verify_mode} = 0;
 } else {
   $0 =~ s:.*/::;
   $HOME = (getpwuid($<))[7]||$ENV{HOME};
@@ -61,7 +68,9 @@
   chmod 0600,$idf;
 }
 
-$| = 1;
+if (-f ($_ = '/etc/fex/config.pl')) {
+  eval { require } or warn $@;
+}
 
 my $from = '';
 my $to = '';
@@ -79,7 +88,6 @@
 my $timeout = 30; 	# server timeout
 my $fexlist = "$tmpdir/fexlist";
 my ($usage,$hints);
-
 my $xx = $0 =~ /^xx/;
 
 if ($xx) {
@@ -97,7 +105,7 @@
 usage: $0 [options] file(s) [@] recipient(s)
    or: $0 [special options]
    or: $0 -f \# recipient(s)
-   or: $0 -x \# [-C -k -D -K]
+   or: $0 -x \# [-C -k -D -K -S]
 options: -v           verbose mode
          -d           delete file on fex server
          -c           compress file
@@ -114,13 +122,14 @@
          -s stream    read data from pipe and upload it with stream name
 special options: -I      initialize ID file or show ID
                  -I tag  add alternate ID data (secondary logins) to ID file
-                 -l      list sent files numbered (# needed for -f -x -d)
+                 -l      list sent files numbered (# needed for -f -x -d -N)
                  -f \#    forward already uploaded file to another recipient
                  -x \#    modify options -C -k -D -K for already uploaded file
                  -d \#    delete file on fex server
+                 -N \#    resend notification e-mail
                  -Q      check quotas
                  -A      edit server address book (aliases)
-                 -U      show authorized URL
+                 -S      show server/user settings and auth-ID
                  -H      show hints, examples and more options
                  -V      show version
                  (\# is a file number, see output from $0 -l)
@@ -132,7 +141,7 @@
 #         -R FEX mail  self-register your e-mail address at FEX server
 
   $hints = <<EOD;
-$0 Hints and more options:
+$0 hints and more options:
   
 usage: $0 [options] file recipient(s)
 
@@ -167,7 +176,7 @@
 If you want a Bcc of the notification e-mail then add '!bcc!' to the comment:
 fexsend -C '!bcc! for me and you' ...
 
-Special options:
+Additional special options:
 
   -. sends a short instead of a detailed notification e-mail
   -/ does not upload the file, but tells the server to link it
@@ -177,6 +186,7 @@
   -q is quiet mode
   -r ADDRESS sets e-mail Reply-To ADDRESS
   -F activates female mode
+  -U show authorized URL
   -+ is an undocumented feature - test it :-)
     
 To manage your subuser and groups or forward or redirect files, use a 
@@ -204,6 +214,13 @@
 without wasting local disc space.
  
 With option -X you can specify any parameter, e.g.: -X autodelete=yes
+
+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
   
 Partner program xx is an internet clipboard. See: xx -h
   
@@ -218,7 +235,27 @@
   FEXID="FEXSERVER USER AUTHID" $0 file recipient
 Example:
   FEXID="fex.flupp.org gaga\@flupp.org blubb" $0 big.file framstag\@rus.uni-stuttgart.de
-    
+
+You can define aliases (and optional fexsend options) in \$HOME/.fex/config.pl:
+  %alias = (
+    'alias1' => '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
 }
 
@@ -255,22 +292,25 @@
 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_o,$opt_g,$opt_F,$opt_n,$opt_r,$opt_S,$opt_N);
 
 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 {
   $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 = '';
-  getopts('hHvcdognVDKlILUARWMFzZqQ@!+./r:m:k:u:f:a:s:C:i:b:P:x:X:=:#:') 
+  $_ = "$fexhome/config.pl"; require if -f;
+  getopts('hHvcdognVDKlILUARWMFzZqQS@!+./r:m:k:u:f:a:s:C:i:b:P:x:X:N:=:#:') 
     or die $usage;
 
   if ($opt_H) {
@@ -307,16 +347,12 @@
     die "$0: you cannot use both options -I and -R\n";
   }
 
-  if ($opt_R) {
-    &register;
-    exit;
-  }
-
   # $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':
@@ -328,12 +364,21 @@
   $opt_D;
 }
 
+&get_ssl_env;
+
 if ($opt_h) {
   female_mode("show help?") if $opt_F;
   print $usage;
   exit;
 }
 
+
+if ($opt_R) {
+  &register;
+  exit;
+}
+
+
 die $usage if $opt_m and $opt_m !~ /^\d+/;
 
 if ($opt_P) { 
@@ -492,7 +537,7 @@
 
 &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);
+             $opt_f or $opt_x or $opt_N);
 
 if (${'opt_.'}) {
   $opt_C = "!SHORTMAIL! $opt_C";
@@ -503,20 +548,18 @@
 }
 
 unless ($skey or $gkey or $anonymous) {
-  if ($opt_v) {
-    if ($FEXID) {
-      warn "ID data from \$FEXID: $fexcgi $from $id\n";
-    } elsif (-f $idf) {
-      warn "ID data from $idf: $fexcgi $from $id\n";
-    }
-  }
-  warn "Server/User: $fexcgi/$from\n" unless $opt_q;
+  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 } 
@@ -817,7 +860,51 @@
     from	=> $from,
     to		=> $from,
     id		=> $sid,
-    comment	=> $opt_C, 
+    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;
@@ -825,6 +912,18 @@
     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 {
@@ -934,7 +1033,6 @@
 
 sub show_URL {
   printf "%s/fup/%s\n",$fexcgi,encode_b64("from=$from&id=$id");
-  exit;
 }
 
 
@@ -946,7 +1044,7 @@
     from	=> $from,
     to		=> $from,
     id		=> $sid,
-    comment	=> $opt_C, 
+    command	=> $opt_C, 
   );
   die "$0: no response from fex server $server\n" unless @r;
   $_ = shift @r;
@@ -1135,8 +1233,22 @@
         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?
-        if ($AB{$to}) {  
+        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};
@@ -1169,7 +1281,8 @@
       }
     }
   
-    $to = join(',',@to);
+    $to = join(',',grep /./,@to) or exit;
+    warn "Server/User: $fexcgi/$from\n" unless $opt_q;
   
     if (
       not $skey and not $gkey
@@ -1356,10 +1469,21 @@
     }
     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,$location);
       foreach (@r) {
-        if ($from eq $to or $from =~ /^\Q$to\E@/i or $nomail or $anonymous) {
-          print "$1\n" if /^X-(Recipient.*)/i;
-          print "$2\n" if /^(X-)?(Location:.*)/i;
+        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";
+            print "$location\n";
+          }
         }
       }
     }
@@ -1440,6 +1564,61 @@
 }
 
 
+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+) \[\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);
@@ -1702,11 +1881,12 @@
   if ($file and not $xx and not 
       ($opt_s or $opt_g or $opt_o or $opt_d or $opt_l or $opt_L or ${'opt_/'}))
   {
-    ($seek,$location) = query_file($server,$port,$P{to},$P{from},$P{id},
-                                   $filename,$fileid);
+    ($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;
-      die "$0: $file has been already transferred\n";
+      warn "$0: $file has been already transferred\n";
+      return $file;
     } elsif ($seek and $seek < $filesize) {
       $resume = " (resuming at byte $seek)";
     } elsif ($filesize <= $seek) {
@@ -2063,7 +2243,7 @@
   $zipbase =~ s/\.zip$//;
   map { s/([^_\w\+\-\.])/\\$1/g } @files;
 
-  open my $ff,"find @files -type f|" or die "$0: cannot search for @_ - $!\n";
+  open my $ff,"find @files|" or die "$0: cannot search for @_ - $!\n";
   @files = ();
 
   zipfile: for (;;) {
@@ -2075,7 +2255,8 @@
     $zsize = 0;
     while ($file = <$ff>) {
       chomp $file;
-      next if -l $file or not -f $file;
+      # next if -l $file or not -f $file;
+      next unless -f $file;
       $size = -s $file;
       if ($size > 2147480000) {
         unlink @zipfiles;
@@ -2114,7 +2295,10 @@
   }
   print $cmd,"\n" if $opt_v;
   open $cmd,"|$cmd" or die "$0: cannot create $zip - $!\n";
-  foreach (@_) { print {$cmd} $_."\n" }
+  foreach (@_) { 
+    print {$cmd} $_."\n";
+    print "  $_\n" if $opt_v;
+  }
   close $cmd or die "$0: zip failed - $!\n";
 
   return $zip;
@@ -2137,67 +2321,6 @@
 }
 
 
-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 query_file {
   my ($server,$port,$to,$from,$id,$filename,$fileid) = @_;
   my $seek = 0;
@@ -2480,42 +2603,6 @@
 }
 
 
-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;
-}
-
-
 # transfer status
 sub ts {
   my ($b,$tb) = @_;
@@ -2568,6 +2655,7 @@
         s/autodelete=\w+/autodelete=$opt_D/ if $opt_D;
         s/keep=\d+/keep=$opt_k/             if $opt_k;
         print;
+        $frecipient ||= (split)[1];
       }
     }
   } else {
@@ -2624,12 +2712,6 @@
 }
 
 
-sub mtime {
-  my @d = localtime((stat shift)[9]);
-  return sprintf('%d%02d%02d',$d[5]+1900,$d[4]+1,$d[3]);
-}
-
-
 # emulate seek on a pipe
 sub readahead {
   my $fh = shift; # filehandle
@@ -2706,21 +2788,6 @@
 }
 
 
-# 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;
-}
-
-
 sub female_mode {
   local $_;
   if (open my $tty,'/dev/tty') {
@@ -2742,6 +2809,7 @@
 sub http_response {
   local $_ = shift || <$SH>;
   my @r = @_;
+  my $error;
 
   $_ = <$SH> unless $_;
   unless (defined $_ and /\w/) {
@@ -2755,8 +2823,13 @@
     die "$0: server error: $_\n@r\n";
   }
   unless (/^HTTP.* 200/) {
-    s/HTTP.[\s\d.]+//;
-    die "$0: server error: $_\n";
+    $error = $_;
+    $error =~ s/HTTP.[\s\d.]+//;
+    if ($opt_v) {
+      print "<-- $_";
+      print "<-- $_" while <$SH>;
+    }
+    die "$0: server error: $error\n";
   }
 
   print "<-- $_\n" if $opt_v;
@@ -2764,6 +2837,48 @@
 }
 
 
+sub ws {
+  local $_ = shift;
+  return split;
+}
+
+
+sub update {
+  my $cfb = '### common functions ###';
+  my $cfc;
+  
+  local $/;
+  
+  open $0,$0 or die "cannot read $0 - $!\n";
+  $_ = <$0>;
+  close $0;
+  s/.*\n$cfb\n//s;
+  $cfc = $_;
+  
+  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 $0 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;
@@ -2771,7 +2886,170 @@
 }
 
 
-sub ws {
-  local $_ = shift;
-  return split;
+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 ($opt_v and $port == 443 and %SSL) {
+    foreach my $v (keys %SSL) {
+      printf "%s => %s\n",$v,$SSL{$v};
+    }
+  }
+  
+  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,%SSL);
+    }
+  } else {
+    tcpconnect($server,$port);
+  }
+#  if ($port == 443 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 ($port == 443) {
+    # eval "use IO::Socket::SSL qw(debug3)";
+    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',
+    );
+  }
+  
+  if ($SH) {
+    autoflush $SH 1;
+  } else {
+    die "$0: cannot connect $server:$port - $@\n";
+  }
+  
+  print "TCPCONNECT to $server:$port\n" if $opt_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;
+}
+
+
+# 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;
 }
diff -Nru fex-20140917/cgi-bin/fac fex-20150120/cgi-bin/fac
--- fex-20140917/cgi-bin/fac	2014-08-18 12:32:32.000000000 +0200
+++ fex-20150120/cgi-bin/fac	2015-01-17 00:17:28.000000000 +0100
@@ -816,7 +816,7 @@
     }
 
     $user .= '@'.$mdomain if $mdomain and $user !~ /@/;
-    open my $mail,"|$sendmail -f '$admin' '$user' '$bcc'"
+    open my $mail,'|-',$sendmail,'-f',$admin,$user,$bcc
 	or http_die("cannot start sendmail - $!\n");
     pq($mail,qq(
         'From: $admin'
diff -Nru fex-20140917/cgi-bin/foc fex-20150120/cgi-bin/foc
--- fex-20140917/cgi-bin/foc	2014-05-26 14:08:41.000000000 +0200
+++ fex-20150120/cgi-bin/foc	2015-01-11 11:58:09.000000000 +0100
@@ -10,6 +10,9 @@
 use Fcntl 	qw(:flock);
 use Digest::MD5	qw(md5_hex);
 
+$CGI::LIST_CONTEXT_WARN = 0;
+$CGI::LIST_CONTEXT_WARN = 0;
+
 # add fex lib
 ($FEXLIB) = $ENV{FEXLIB} =~ /(.+)/;
 die "$0: no $FEXLIB\n" unless -d $FEXLIB;
@@ -208,6 +211,17 @@
       '  Get <a href="/fuc?reminder=no&akey=$akey">no reminder</a> notification e-mails (current setting: <em>send reminders</em>).'
     ));
   }
+  if (-e "$user/\@MIME") {
+    pq(qq(
+      '  <p><hr><p>'
+      '  <a href="/fuc?mime=no&akey=$akey">Save</a> files after download (current setting: <em>display</em>).'
+    ));
+  } else {
+    pq(qq(
+      '  <p><hr><p>'
+      '  <a href="/fuc?mime=yes&akey=$akey">Display</a> files when downloading with web browser (current setting: <em>save</em>).'
+    ));
+  }
   pq(qq(
     '  <p><hr><p>'
     '  <a href="/fup?akey=$akey">Back to fup (upload page)</a>'
diff -Nru fex-20140917/cgi-bin/fop fex-20150120/cgi-bin/fop
--- fex-20140917/cgi-bin/fop	2014-09-11 23:54:12.000000000 +0200
+++ fex-20150120/cgi-bin/fop	2015-01-13 14:03:50.000000000 +0100
@@ -307,7 +307,7 @@
     }
       
   }
-
+  
   if ($qs =~ /\&?KEEP=(\d+)/i) {
     $keep = $1;
     $filename = filename($file);
@@ -692,8 +692,10 @@
   $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 ($http_client !~ /MSIE/ and $type =~ /x-mime/i and open $mt,'<',$mt) {
+  if (($type =~ /x-mime/i or -e $mime) and open $mt,'<',$mt) {
     $type = 'application/octet-stream';
     MIMETYPES: while (<$mt>) {
       chomp;
diff -Nru fex-20140917/cgi-bin/fuc fex-20150120/cgi-bin/fuc
--- fex-20140917/cgi-bin/fuc	2014-06-03 10:51:57.000000000 +0200
+++ fex-20150120/cgi-bin/fuc	2015-01-09 21:55:57.000000000 +0100
@@ -1,7 +1,7 @@
 #!/usr/bin/perl -wT
 
 # FEX CGI for user control 
-# (subuser, groups, address book, one time upload key, auth-ID)
+# (subuser, groups, address book, one time upload key, auth-ID, etc)
 #
 # Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
 #
@@ -11,6 +11,9 @@
 use Fcntl 	qw(:flock);
 use Digest::MD5	qw(md5_hex);
 
+$CGI::LIST_CONTEXT_WARN = 0;
+$CGI::LIST_CONTEXT_WARN = 0;
+
 # add fex lib
 ($FEXLIB) = $ENV{FEXLIB} =~ /(.+)/;
 die "$0: no $FEXLIB\n" unless -d $FEXLIB;
@@ -36,7 +39,7 @@
 
 my $user = my $id = my $nid = my $ssid = my $comment = '';
 my $notification = my $reminder = my $disclaimer = '';
-my $encryption = my $pubkey = '';
+my $encryption = my $pubkey = my $mime = '';
 
 $akey = ''; # delete akey cookie
 
@@ -64,6 +67,7 @@
     $v =~ /^encryption$/i	? $encryption	= checkchars('parameter',$vv):
     $v =~ /^pubkey$/i		? $pubkey	= $vv:
     $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):
@@ -327,7 +331,7 @@
     my $rows = ($ab =~ tr/\n//) + 5;
     pq(qq(
       '<h2>Edit address book</h2>'
-      '<table border=1>'
+      '<table border=0>'
       '  <tr align="left"><th>Entry:<th>alias<th>e-mail address<th># optional comment</tr>'
       '  <tr align="left"><td>Example:<td><code>Framstag</code><td><code>framstag\@rus.uni-stuttgart.de</code><td><code># Ulli Horlacher</code></tr>'
       '</table>'
@@ -336,7 +340,7 @@
       '      accept-charset="UTF-8"'
       '      enctype="multipart/form-data">'
       '  <input type="hidden" name="akey" value="$akey">'
-      '  <textarea name="ab" cols="80" rows="$rows">$ab</textarea><br>'
+      '  <textarea name="ab" cols="160" rows="$rows">$ab</textarea><br>'
       '  <input type="submit" value="submit">'
       '</form>'
       '<p>'
@@ -414,6 +418,29 @@
     '<p>'
     '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
     '</body></html>'
+  ));
+  &reexec;
+}
+
+if ($user and $mime eq 'yes') {
+  open $mime,'>',"$user/\@MIME" or http_die("cannot write $user/\@MIME - $!\n");
+  close $mime;
+  pq(qq(
+    '<h3>Downloads will now be displayed (if possible).<h3>'
+    '<p>'
+    '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
+    '</body></html>'
+  ));
+  &reexec;
+}
+
+if ($user and $mime eq 'no') {
+  unlink "$user/\@MIME";
+  pq(qq(
+    '<h3>Downloads will now be saved.<h3>'
+    '<p>'
+    '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
+    '</body></html>'
   ));
   &reexec;
 }
diff -Nru fex-20140917/cgi-bin/fup fex-20150120/cgi-bin/fup
--- fex-20140917/cgi-bin/fup	2014-09-17 21:16:08.000000000 +0200
+++ fex-20150120/cgi-bin/fup	2015-01-18 01:22:56.000000000 +0100
@@ -16,6 +16,7 @@
 use Cwd			qw'abs_path';
 
 use constant DS => 60*60*24;
+use constant M  => 1024*1024;
 
 # add fex lib
 die "$0: no \$FEXLIB\n" unless $ENV{FEXLIB};
@@ -40,7 +41,7 @@
 our ($FEXHOME);
 our ($spooldir,$durl,$tmpdir,$logdir,$docdir,$hostname,$admin,$fra);
 our ($keep_default,$recipient_quota,$sender_quota);
-our ($sendmail,$mdomain,$fop_auth,$faillog);
+our ($sendmail,$mdomain,$fop_auth,$mail_auth,$faillog);
 our ($dkeydir,$ukeydir,$akeydir,$skeydir,$gkeydir,$xkeydir);
 our $akey = '';
 our $dkey = '';
@@ -118,8 +119,8 @@
 $uid = randstring(8) unless $uid; # upload ID
 
 # user requests for forgotten ID
-$id_forgotten = $id if $id =~ /^"?\?"?/;
-if ($from and $id_forgotten and not $fop_auth and not $nomail) {
+$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;
@@ -154,10 +155,6 @@
   $nomail = $anonymous;
 }
 
-if ($to and (readlink "$to/\@NOTIFICATION"||'') =~ /^no/i) {
-  $nomail = 'recipient';
-}
-
 $comment = 'NOMAIL' if $nomail and not $comment;
 
 # one time token
@@ -315,7 +312,6 @@
                                                                      
   if ($command eq 'CHECKQUOTA') {
     http_die("illegal command \"$command\"") if $public or $anonymous;
-    my ($quota,$du);
     nvt_print('HTTP/1.1 204 OK');
     # nvt_print("X-SID: $ENV{SID}") if $ENV{SID};
     ($quota,$du) = check_sender_quota($muser||$from);
@@ -326,36 +322,45 @@
     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 ($file,$filename,$mtime,$comment,$keep);
     my $nfile = '';
     if ($dkey) {
       # resend notification e-mail
-      $file = readlink(".dkeys/$dkey")
+      $file = readlink("$dkeydir/$dkey")
         or html_error($error,"illegal DKEY $dkey");
       $file =~ s:^../::;
-      $nfile = $file;
-      $mtime = mtime("$file/data") 
-        or html_error($error,"illegal DKEY $dkey");
-      $comment = slurp("$file/comment")||'';
-      $keep = untaint(
-        readlink "$file/keep" || 
-        readlink "$file/../../\@KEEP" || 
-        $keep_default
-      );
-      $filename = filename($file);
-
-      notify(
-        status     => 'new',
-        dkey       => $dkey,
-        filename   => $filename,
-        keep       => $keep-int((time-$mtime)/DS),
-        comment    => $comment,
-        autodelete => readlink "$file/autodelete" || $autodelete,
+      $file = untaint($file);
+      unlink "$file/download"; # re-allow download from any ip address
+      notify_locale($dkey,'new');
+      http_header(
+        '200 OK',
+        "X-Notify: $file",
       );
-    } 
-    http_header('200 OK');
+      $nfile = $file;
+    } else {
+      http_header('200 OK');
+    }
     print html_header($head);
     # list sent files
     print "<h3>Files from $from, ",
@@ -366,7 +371,7 @@
       next if $file =~ m:(.+?)/: and -l $1;
       $size = -s "$file/data";
       next unless $size;
-      $size = int($size/1024/1024+0.5);
+      $size = int($size/M+0.5);
       $filename = $comment = '';
       my $rto = $file;
       $rto =~ s:/.*::;
@@ -390,7 +395,8 @@
         }
         my $rkeep = untaint(readlink "$file/keep"||$keep_default)
                     - int((time-mtime("$file/filename"))/DS);
-        if ($comment =~ /NOMAIL/) {
+        if ($comment =~ /NOMAIL/ or 
+           (readlink "$to/\@NOTIFICATION"||'') =~ /^no/i) {
           printf "%8s MB [%s d] %s/%s/%s\n",
                  $size,
                  $rkeep,
@@ -432,7 +438,7 @@
         next if $file =~ m:(.+?)/: and -l $1;
         $size = -s "$file/data";
         next unless $size;
-        $size = int($size/1024/1024+0.5);
+        $size = int($size/M+0.5);
         $filename = $comment = '';
         my $rto = $file;
         $rto =~ s:/.*::;
@@ -487,7 +493,7 @@
           $filename = $comment = '';
           $size = -s "$file/data";
           next unless $size;
-          $size = int($size/1024/1024+0.5);
+          $size = int($size/M+0.5);
           if ($dkey = readlink "$file/dkey") {
             print "\nfrom $from :\n" unless $url;
             $file =~ m:.*/(.+):;
@@ -611,14 +617,17 @@
 
   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)",
-                    $autodelete{$to}||$autodelete,
-                    $keep{$to}||$keep_default;
+      my $options = sprintf "(autodelete=%s,keep=%s,locale=%s,notification=%s)",
+        $autodelete{$to}||$autodelete,
+        $keep{$to}||$keep_default,
+        readlink("$to/\@LOCALE")||$default_locale,
+        readlink("$to/\@NOTIFICATION")||'full';
       nvt_print("X-Recipient: $to $options");
     }
     nvt_print('');
@@ -680,19 +689,19 @@
 }
 
 # quotas 
-if ($from and $id and $rid eq $id and @to and not $flink) {
+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/1024/1024 > $quota) {
+  if ($quota and $du+$cl/M > $quota) {
     http_die("you are overquota");
   }
   
   # check recipient quota
   foreach my $to (@to) {
     ($quota,$du) = check_recipient_quota($to);
-    if ($quota and $du+$cl/1024/1024 > $quota) {
+    if ($quota and $du+$cl/M > $quota) {
       http_die("$to cannot receive files: is overquota");
     }
   }
@@ -822,6 +831,8 @@
   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');
+    
     @ab = ("<option></option>");
     
     # select menu from server address book
@@ -840,12 +851,14 @@
     unless (@to) {
       unless ($nomail) {
         foreach (glob "$from/\@GROUP/*") {
-          s:.*/::;
-          push @ab,"<option>\@$_</option>" unless /~$/;
+          if (-f and not -l) {
+            s:.*/::;
+            push @ab,"<option>\@$_</option>" unless /~$/;
+          }
         }
       }
     }
-    
+      
     my $ab64 = b64("from=$from&id=$id");
 #     '<form class="uploadform" name="upload"'
     pq(qq(
@@ -949,8 +962,12 @@
       '    }'
       '    return false;'
       '  }'
-      '</script>'
-      '<script type="text/javascript">'
+      ''
+      '  function checkupload() {'
+      '    var file  = document.forms["upload"].elements["file"].value;'
+      '    if (file == "") { alert("No file selected"); }'
+      '  }'
+      ''
       '  function reportsize() {'
       '    var form = document.forms["upload"];'
       '    var filesize = form.file.files[0].size;'
@@ -1005,13 +1022,15 @@
         ));
       }
       my $toh = "group $group:<ul>";
+      my $toc = join(',',@group);
       foreach my $gm (@group) { $toh .= "<li>$gm" }
       $toh .= "</ul>";
       pq(qq(
         '  <input type="hidden" name="id" value="$id">'
         '  <table border="1">'
         '    <tr><td>sender:<td>$from</tr>'
-        '    <tr><td>recipient(s):<td>$toh</tr>'
+        '    <tr><td>recipient(s):'
+        '        <td><input type="hidden" name="to" value="$toc">$toh</tr>'
       ));
     } else {
       my $toc = join(',',@to);
@@ -1106,11 +1125,12 @@
       '    </tr>'
       '    <tr title="If you want to send more than one file, then put them in a zip or tar archive">'
       '        <td>file:'
-      '        <td><input type="file" name="file"    size="80" value="$file" onchange="reportsize();">'
+      '        <td><input type="file" name="file" size="80" value="$file" onchange="reportsize();">'
       '    </tr>'
       '    <tr><td>file size:<td id="filesize"></td></tr>'
       '  </table>'
-      '  <p><input type="submit" value="upload">'
+      '  <p>
+      '  <input type="submit" value="upload" onclick="checkupload()">'
       '<p>'
       '</form>'
     ));
@@ -1139,7 +1159,7 @@
     exit;
   }
 
-  present_locales('fup');
+  present_locales('/fup');
 
   if ($ENV{REQUEST_METHOD} eq 'POST') {
     pq(qq(
@@ -1148,23 +1168,22 @@
       '</h3></font>'
     ));
   }
-  
+
   pq(qq(
-    '<form action="/fup" '
-    '      method="post" '
-    '      accept-charset="ISO-8859-1" '
+    '<form action="/fup"'
+    '      method="post"'
+    '      accept-charset="ISO-8859-1"'
     '      enctype="multipart/form-data">'
     '  <table>'
     '    <tr><td>sender:'
     '        <td><input type="text"     name="from" size="40" value="$from"></tr>'
-    '    <tr><td>auth-ID:       '
+    '    <tr><td>auth-ID:'
     '        <td><input type="password" name="id"   size="16" value="$id" autocomplete="off"></tr>'
-    '  </table> '
+    '  </table>'
   ));
-  unless ($fop_auth or $nomail) {
+  if ($mail_authid and not ($fop_auth or $nomail)) {
 #    pq(qq(
-#      'If you have lost your auth-ID use "?"'
-#      'and your auth-ID will be sent by e-mail to you.'
+#      'If you enter "?" as your auth-ID then it will be sent by e-mail to you.'
 #      '<p>'
 #    ));
     pq(qq(
@@ -1277,6 +1296,12 @@
   }
 }
 
+# additional last check
+foreach $to (@to) {
+  checkaddress($to) or 
+    http_die("<code>$to</code> is not a valid e-mail address");
+}
+
 $to = join(',',@to);
 
 # file overwriting for anonymous is only possible if his client has the 
@@ -1318,12 +1343,13 @@
   foreach (@group?@group:@to) {
     my $to = $_;
     $to =~ s/:\w+=.*//; # remove options from address
-    $filed  = "$to/$from/$fkey";
-    $save   = "$filed/data";
-    $upload = "$filed/upload";
+    $filed     = "$to/$from/$fkey";
+    $save      = "$filed/data";
+    $upload    = "$filed/upload";
+    $download  = "$filed/download";
     $dkey{$to} = readlink "$filed/dkey";
-    unlink $save unless -s $save;
-    unlink $save and $overwrite{$to}++;
+    $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
@@ -1337,27 +1363,9 @@
     }
     
     # send notification e-mails if necessary
-    if (not $nomail and ($comment or not $overwrite{$to})) {
-      my $locale = readlink "$to/\@LOCALE" || readlink "$filed/locale" 
-                   || $default_locale;
-      my $lf = untaint("$FEXHOME/locale/$locale/lib/lf.pl");
-      require $lf if -f $lf;
-      unless ($notify{$locale}) {
-        $locale = 'english';
-        $lf = "$FEXHOME/lib/lf.pl";
-        if (-f $lf) { require $lf }
-        else        { $notify{$locale} = \&notify }
-      }
-      &{$notify{$locale}}(
-# notify(
-        status	   => "new",
-        dkey	   => $dkey{$to},
-        filename   => $filename,
-        keep	   => $keep{$to}||$keep||$keep_default,
-        comment	   => $comment,
-        replyto	   => $replyto,
-        autodelete => $autodelete{$to}||$autodelete,
-      );
+    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'");
     }
   }
@@ -1384,14 +1392,17 @@
     $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 $options = sprintf "(autodelete=%s,keep=%s,locale=%s)",
-      readlink "$to/$from/$fkey/autodelete"||$autodelete,
-      readlink "$to/$from/$fkey/keep"||$keep_default,
-      readlink "$to/$from/$fkey/locale"||$locale;
+    my $file = "$to/$from/$fkey";
+    my $options = sprintf "(autodelete=%s,keep=%s,locale=%s,notification=%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;
   }
@@ -1407,50 +1418,66 @@
 print html_header($head);
 
 if ($nostore) {
-  printf "%s (%s MB) received\n",$file,$ndata/1024/1024;
-} elsif (not $restricted and ($anonymous or $nomail or $from eq $to)) {
-  my $size = $ndata<2*1024      ? sprintf "%s B",$ndata:
-             $ndata<2*1024*1024 ? sprintf "%s kB",int($ndata/1024):
-                                  sprintf "%s MB",int($ndata/1024/1024);
+  printf "%s (%s MB) received\n",$file,$ndata/M;
+} elsif (not $restricted and ($anonymous or $from eq $to)) {
+  my $size = $ndata<2*1024 ? sprintf "%s B",$ndata:
+             $ndata<2*M	   ? sprintf "%s kB",int($ndata/1024):
+                             sprintf "%s MB",int($ndata/M);
   pq(qq(
-    '$file ($size) received and saved<p>'
+    '<code>$file</code> ($size) received and saved<p>'
     'Download URL for copy & paste:'
+    '<h2>$durl/$dkey{$to}/$fkey</h2>'
+    'Link is valid for $keep{$to} days!<p>'
   ));
-  if ($xkey) {
-    my $x = "$durl//$xkey";
-    $x =~ s:/fop::;
-    print "<h2><code>$x</code></h2>\n";
-  } else {
-    foreach my $to (@to) {
-      print "<h2><code>$to</code>:<br></h2>\n" if $to !~ /^anonymous/;
-      print "<h2>$durl/$dkey{$to}/$fkey</h2>\n";
-    }
-  }
-  print "Link is valid for $keep days!<p>\n";
 } else {
   if ($ndata<2*1024) {
-    print "$file ($ndata B) received and saved<p>\n";
+    print "<code>$file</code> ($ndata B) received and saved<p>\n";
     if (not $boring and not $seek) {
       print "Ehh... $ndata <b>BYTES</b>?! You are kidding?<p>\n";
     }
-  } elsif ($ndata<2*1024*1024) {
+  } elsif ($ndata<2*M) {
     $ndata = int($ndata/1024);
-    print "$file ($ndata kB) received and saved<p>\n";
+    print "<code>$file</code> ($ndata kB) received and saved<p>\n";
     if ($ndata<1024 and not ($boring or $seek)) {
       print "Using F*EX for less than 1 MB: ",
-        "ever heard of MIME e-mail? :-)<p>\n";
+        "ever heard of MIME e-mail? &#9786;<p>\n";
     }
   } else {
-    $ndata = int($ndata/1024/1024);
-    print "$file ($ndata MB) received and saved<p>\n";
+    $ndata = int($ndata/M);
+    print "<code>$file</code> ($ndata MB) received and saved<p>\n";
   }
+  print "<ul>\n";
   foreach $to (@to) {
-    if ($overwrite{$to}) { 
-      print "(old $file for $to overwritten)<p>\n" 
+    print "<li>";
+    if ($nomail or $nomail{$to}) {
+      if ($restricted) {
+        rmrf("$to/$from/$fkey");
+        print "<code>$file</code> removed because you are a restricted user ".
+              "and recipient $to cannot receive e-mail<p>\n";
+      } else {
+        pq(qq(
+          '$to cannot receive e-mail &rarr;'
+          '<h3><font color="red">'
+          '  No notification e-mail has been sent to $to!'
+          '</font></h3>'
+          'Download URL for copy & paste:'
+        ));
+        if ($xkey) {
+          my $x = "$durl{$to}//$xkey";
+          $x =~ s:/fop::;
+          print "<h2><code>$x</code></h2>\n";
+        } else {
+          print "<h2>$durl/$dkey{$to}/$fkey</h2>\n";
+          print "Link is valid for $keep{$to} days!<p>\n";
+        }
+      }
+    } elsif ($overwrite{$to} and not $comment) { 
+      print "(old <code>$file</code> for $to overwritten)<p>\n" 
     } else { 
-      print "$to notified<p>\n" 
+      print "$to notified<p>\n"
     }
   }
+  print "</ul>\n";
 }
 
 if ($okey) {
@@ -1463,6 +1490,9 @@
   elsif ($akey)   { print "&akey=$akey&to=$to" }
   print "&bwlimit=$bwlimit&autodelete=$autodelete&keep=$keep\">";
   print "send another file</a>\n";
+  if ($http_client !~ /fexsend/ and $http_client =~ /Linux/i) {
+    print qq'<p>Hi Linux-user, try <a href="/FAQ/user.html#Why_should_I_use_a_special_F_EX_client">fexsend</a>! &#9786;<p>\n';
+  }
   print &logout;
 }
 
@@ -1959,10 +1989,9 @@
           symlink untaint($flink),$upload;
         } else {
           unlink $upload if -l $upload;
-          open $upload,'>>',$upload or http_die("cannot create $upload - $!");
-          unless (flock($upload,LOCK_EX|LOCK_NB)) {
+          open $upload,'>>',$upload or http_die("cannot write $upload - $!");
+          flock($upload,LOCK_EX|LOCK_NB) or
             http_die("<code>$file</code> locked: a transfer is already in progress");
-          }
           unless ($seek) {
             seek $upload,0,0;
             truncate $upload,0;
@@ -1976,7 +2005,6 @@
       
       unlink "$filed/autodelete",
              "$filed/error",
-             "$filed/download",
              "$filed/restrictions",
              "$filed/locale",
              "$filed/keep",
@@ -1984,6 +2012,8 @@
              "$filed/id",
              "$filed/ip",
              "$filed/speed",
+             "$filed/replyto",
+             "$filed/useragent",
              "$filed/comment",
              "$filed/notify";
       unlink "$filed/size" unless $seek;
@@ -2021,13 +2051,20 @@
       }
       mksymlink("$filed/id",$fileid) if $fileid;
       mksymlink("$filed/ip",$ra)     if $ra;
+      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",$_);
+        # mksymlink("$filed/locale",$_);
       } elsif ($locale{$to}) {
         mksymlink("$filed/locale",$locale{$to});
-      } elsif ($locale) {
+      } 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) {
@@ -2039,6 +2076,10 @@
         close $fh;
       }
     
+      if ((readlink "$to/\@NOTIFICATION"||'') =~ /^no/i) {
+        $nomail{$to} = 'NOTIFICATION';
+      }
+
       if ($nomail) {
         open $fh,'>',"$filed/notify" and close $fh;
       } 
@@ -2053,7 +2094,8 @@
       unless ($dkey = readlink("$filed/dkey") and -l "$dkeydir/$dkey") {
         $dkey = randstring(8);
         unlink "$dkeydir/$dkey";
-        symlink "../$filed","$dkeydir/$dkey" or die "cannot symlink $dkeydir/$dkey";
+        symlink "../$filed","$dkeydir/$dkey" 
+          or http_die("cannot symlink $dkeydir/$dkey ($!)");
         unlink "$filed/dkey";
         symlink $dkey,"$filed/dkey";
       }
@@ -2085,7 +2127,7 @@
     # upload link has been already created, no data to read any more
     $to = join(',',@to);
     fuplog($to,$fkey,0);
-    debuglog("upload successfull, dkey=$dkey");
+    debuglog("upload link successfull, dkey=$dkey");
   }
 
   # regular file
@@ -2292,8 +2334,11 @@
       $u = "$u\@$hostname";
     }
     if ($u eq 'nettest') { 
-      $u = "$u\@$mdomain"  if -d "$u\@$mdomain";
-      $u = "$u\@$hostname" if -d "$u\@$hostname";
+      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" } 
@@ -2363,15 +2408,16 @@
       http_die("cannot create directory $nfile") unless -d $nfile;
       unlink "$nfile/data",
              "$nfile/upload",
+             "$nfile/download",
              "$nfile/autodelete",
              "$nfile/error",
-             "$nfile/download",
              "$nfile/restrictions",
              "$nfile/keep",
              "$nfile/header",
              "$nfile/id",
              "$nfile/speed",
              "$nfile/comment",
+             "$nfile/replyto",
              "$nfile/notify";
       if ($comment) {
         open $comment,'>',"$nfile/comment";
@@ -2384,18 +2430,22 @@
       symlink($keep||$keep_default,         "$nfile/keep");
                     copy("$file/id",        "$nfile/id");
                     copy("$file/ip",        "$nfile/ip");
-      $filename   = copy("$file/filename",  "$nfile/filename",'NEW:');
+                    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 die "cannot symlink $dkeydir/$dkey";
+        symlink "../$nfile","$dkeydir/$dkey" 
+          or http_die("cannot symlink $dkeydir/$dkey");
         unlink "$nfile/dkey";
-        symlink $dkey,"$nfile/dkey";
+        symlink $dkey,"$nfile/dkey" 
+          or http_die("cannot create $nfile/dkey - $!");
       }
       
-      if ($nomail) {
+      if ($nomail or $nomail{$to}) {
         if ($filename) {
           my $url = "$durl/$dkey/".normalize_filename($filename);
           pq(qq(
@@ -2405,24 +2455,7 @@
           ));
         }
       } else {
-        my $locale = readlink "$to/\@LOCALE" || $::locale 
-          || readlink "$file/locale" || 'english';
-        my $lf = untaint("$FEXHOME/locale/$locale/lib/lf.pl");
-        require $lf if -f $lf;
-        if ($notify{$locale}) {
-          mksymlink("$nfile/locale",$locale);
-        } else {
-          $locale = 'english';
-          $notify{$locale} = \&notify unless $notify{$locale};
-        }
-        &{$notify{$locale}}(
-          status	=> "new",
-          dkey	   	=> $dkey,
-          filename	=> $filename,
-          keep		=> $keep||$keep_default,
-          comment    	=> $comment||'',
-          autodelete 	=> $autodelete,
-        );
+        notify_locale($dkey,'new');
         fuplog($to,urlencode($filename),"(forwarded)");
         if ($filename) {
           pq(qq(
@@ -2462,6 +2495,7 @@
 sub modify {
   my $file = shift;
   my $filename = filename($file);
+  my $dkey = readlink "$file/$dkey";
   my $to;
   my @parameter;
 
@@ -2483,14 +2517,7 @@
       print {$comment} $comment;
       close $comment;
     }
-    notify(
-      status	 => "new",
-      dkey	 => $dkey,
-      filename	 => $filename,
-      keep	 => $keep||$keep_default,
-      comment	 => $comment,
-      autodelete => $autodelete,
-    );
+    notify_locale($dkey,'new');
     push @parameter,'COMMENT';
   }
   http_header('200 OK');
@@ -2864,7 +2891,7 @@
     while (<$df>) {
       if (/^.+?\s+\d+\s+\d+\s+(\d+)/ and $req/1024 > $1) {
         $free = int($1/1024);
-        $uprq = int($req/1024/1024);
+        $uprq = int($req/M);
         if (not $nomail and open P,"|$sendmail -t") {
           pq(P,qq(
             'From: $admin'
@@ -2924,7 +2951,10 @@
   my ($sig) = @_;
   my $msg;
   my $to = join(',',@to);
-  
+
+  $SIG{__DIE__} = 'DEFAULT';
+  foreach (keys %SIG) { $SIG{$_} = 'DEFAULT' }
+
   $msg = @_ ? "@_" : '???';
   $msg =~ s/\n/ /g;
   $msg =~ s/\s+$//;
@@ -2941,7 +2971,6 @@
            $rb?"(after $rb bytes)":"";
     close $log;
   }
-  $SIG{__DIE__} = '';
   if ($sig eq 'DIE') {
     shift;
     die "$msg\n";
@@ -2997,7 +3026,7 @@
 
 sub check_camel {
   my ($logo,$camel);
-  local $\;
+  local $/;
   
   if (open $logo,"$docdir/logo.jpg") {
     $camel = md5_hex(<$logo>) eq 'ad8a95bba8dd1a61d70bd38611bc2059';
diff -Nru fex-20140917/cgi-bin/fur fex-20150120/cgi-bin/fur
--- fex-20140917/cgi-bin/fur	2014-09-15 16:00:08.000000000 +0200
+++ fex-20150120/cgi-bin/fur	2014-12-19 10:17:59.000000000 +0100
@@ -9,6 +9,9 @@
 use CGI::Carp	qw(fatalsToBrowser);
 use Fcntl 	qw(:flock :seek :mode);
 
+$CGI::LIST_CONTEXT_WARN = 0;
+$CGI::LIST_CONTEXT_WARN = 0;
+
 # import from fex.ph
 our (@local_hosts,@local_domains,@local_rhosts,@local_rdomains);
 our (@registration_hosts,@registration_domains);
@@ -39,6 +42,13 @@
 
 &check_maint;
 
+unless (@local_domains or @local_rdomains) {
+  html_error($error,
+    "No domains for registrations are defined.",
+    "Contact $ENV{SERVER_ADMIN} for details."
+  );
+}
+
 # look for CGI parameters
 foreach my $v (param) {
   my $vv = despace(param($v));
@@ -67,8 +77,8 @@
   unless ($user and $id) {
     http_die("no registration data for key $confirm");
   }
-  unless (-d $user) {
-    mkdir $user,0770 or http_die("mkdir $user - $!\n");
+  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");
@@ -98,6 +108,7 @@
   exit;
 }
 
+
 unless ($user or $exuser or $demouser) {
   http_header("200 OK");
   print html_header($head);
@@ -211,13 +222,16 @@
   } else {
     html_error($error,"<code>$exuser</code> is not an email address");
   }
-  if (-f "$exuser/@") {
-    html_error($error,"<code>$exuser</code> does already exist");
-  }
   $user = $exuser;
 } elsif ($demouser) {
   $user = $demouser;
-} elsif (@local_domains) {
+} 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;
@@ -237,6 +251,8 @@
       "Contact $ENV{SERVER_ADMIN} for details."
     );
   }
+} else {
+  html_error($error,"No user type found.");
 }
 
 unless (checkforbidden($user)) {
@@ -265,6 +281,7 @@
   $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";
diff -Nru fex-20140917/cgi-bin/rup fex-20150120/cgi-bin/rup
--- fex-20140917/cgi-bin/rup	2014-05-26 18:16:07.000000000 +0200
+++ fex-20150120/cgi-bin/rup	2015-01-15 17:15:54.000000000 +0100
@@ -128,12 +128,8 @@
       foreach my $file (glob "$oto/$from/*/data") {
         next if $file =~ m:/STDFEX/:;
         $file =~ s:/data$::;
-        if (open $file,'<',"$file/filename") {
-          my $filename = <$file> || '';
-          close $file;
-          if ($filename) {
-            print "\t<option>$filename</option>\n";
-          }
+        if ($filename = filename($file)) {
+          print "\t<option>$filename</option>\n";
         }
       }
     }
@@ -205,34 +201,14 @@
   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";
-  if (open $fkey,'<',"$nto/$from/$fkey/filename") {
-    chomp($filename = <$fkey>||'');
-    close $fkey;
-  }
-  $filename = $fkey unless $filename;
-  $keep = readlink "$nto/$from/$fkey/keep" || 0;
-  if (not $keep and open $fkey,'<',"$nto/$from/$fkey/keep") {
-    chomp($keep = <$fkey>||'');
-    close $fkey;
-  }
-  if (open $fkey,'<',"$nto/$from/$fkey/comment") {
-    chomp($comment = <$fkey>||'');
-    close $fkey;
-    if ($comment eq 'NOMAIL') {
-      $comment = '';
-      unlink "$nto/$from/$fkey/comment";
-    }
-  }
-  notify(
-    status	 => "new",
-    dkey	 => $dkey,
-    filename	 => $filename,
-    keep	 => $keep||$keep_default,
-    comment	 => $comment||'',
-  );
+  $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');
diff -Nru fex-20140917/cgi-bin/sex fex-20150120/cgi-bin/sex
--- fex-20140917/cgi-bin/sex	2013-08-31 22:32:26.000000000 +0200
+++ fex-20150120/cgi-bin/sex	2014-09-19 11:09:12.000000000 +0200
@@ -66,7 +66,9 @@
   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");
@@ -104,17 +106,17 @@
   }
   
   header('200 OK');
-  sexlog($mode);
 
-  $SIG{PIPE} = sub { sleep 1; rmrf($stream); exit; };
+  $B = 0;
+  $shutdown = sub { sexlog($B); rmrf($stream); exit; };
+  $SIG{PIPE} = sub { sleep 1; &$shutdown; };
   # syswrite $fifo,$data if $data;
-  while (sysread(STDIN,$_,$bs)) {
+  while ($b = sysread(STDIN,$_,$bs)) {
+    $B += $b;
     syswrite $fifo,$_ or die $!;
   }
-  
-  rmrf($stream);
-  exit;
 
+  &$shutdown;
 }
 elsif ($mode eq 'POP') {
   $stream =~ s:/STDSTR:/PUBLIC: if $id eq 'public';
diff -Nru fex-20140917/debian/changelog fex-20150120/debian/changelog
--- fex-20140917/debian/changelog	2014-12-15 10:17:32.000000000 +0100
+++ fex-20150120/debian/changelog	2015-01-21 10:20:40.000000000 +0100
@@ -1,3 +1,32 @@
+fex (20150120-2) unstable; urgency=medium
+
+  * Fix fexget perl warning with upstream fix
+
+ -- Kilian Krause <kilian@debian.org>  Wed, 21 Jan 2015 10:20:03 +0100
+
+fex (20150120-1) unstable; urgency=high
+
+  * New upstream release: 20150120 (Closes: #773751)
+   - SECURITY FIX: race condition between fur and fex_cleanup may create
+     internal instead of external user
+   - several small bugs are fixed
+   - fexwall also mails to sub and group users
+   - optional HTTP basic authentication for htdoc/ directory
+   - several SSL/TLS related fixes including default TLS for https connections
+   - locale selection in upload form, too
+   - better SSL configuration for fexsend,fexget,sexsend
+   - autoview option for fexget
+   - save-or-display (MIME) option for download
+   - new config variable $mail_authid to (dis)allow mailing of forgotten
+     auth-IDs
+  * Update lintian override to ignore :sexsend:sexget: symlink which is
+    interpreted by fexsrv directly
+  * Recommend ca-certificates to verify remote server in fex-utils
+  * Don't fail in postinst while looking up fex in trusted_users
+    (Closes: #774854)
+
+ -- Kilian Krause <kilian@debian.org>  Tue, 20 Jan 2015 15:56:05 +0100
+
 fex (20140917-2) unstable; urgency=high
 
   * Re-add symlinks in htdocs/download - avoid otherwise broken symlinks in
diff -Nru fex-20140917/debian/control fex-20150120/debian/control
--- fex-20140917/debian/control	2014-12-15 10:17:32.000000000 +0100
+++ fex-20150120/debian/control	2015-01-21 10:20:40.000000000 +0100
@@ -10,7 +10,8 @@
 
 Package: fex
 Architecture: all
-Depends: ${misc:Depends}, ${perl:Depends}, adduser, xinetd | inet-superserver, libdigest-md5-file-perl, ucf, libjs-jquery, exim4 | postfix | mail-transport-agent
+Depends: ${misc:Depends}, ${perl:Depends}, adduser, xinetd | inet-superserver,
+ libdigest-md5-file-perl, ucf, libjs-jquery, exim4 | postfix | mail-transport-agent
 Recommends: perl-modules, libnet-dns-perl, fex-utils, libsocket6-perl, wget
 Description: web service for transferring very large files
  F*EX (Frams's Fast File EXchange) is a service that can be used to allow
@@ -46,7 +47,8 @@
 Package: fex-utils
 Architecture: all
 Depends: ${misc:Depends}, ${perl:Depends}
-Recommends: libdigest-md5-file-perl, libnet-sslglue-perl, libnet-inet6glue-perl
+Recommends: libdigest-md5-file-perl, libnet-sslglue-perl,
+ libnet-inet6glue-perl, ca-certificates
 Suggests: wget, fex
 Description: web service for transferring very large files (utils)
  F*EX (Frams's Fast File EXchange) is a service that can be used to allow
diff -Nru fex-20140917/debian/fex.lintian-overrides fex-20150120/debian/fex.lintian-overrides
--- fex-20140917/debian/fex.lintian-overrides	2014-12-15 10:17:32.000000000 +0100
+++ fex-20150120/debian/fex.lintian-overrides	2015-01-21 10:20:40.000000000 +0100
@@ -2,3 +2,6 @@
 # the default configuration without any localisation
 # Thus the recursive symlink is required and cannot be avoided
 fex binary: symlink-is-self-recursive usr/share/fex/locale/english ..
+# This symlink is interpreted by the fexsrv daemon and therefore not usable as
+# file system path
+fex binary: file-in-unusual-dir :sexsend:sexget:
diff -Nru fex-20140917/debian/fex.postinst fex-20150120/debian/fex.postinst
--- fex-20140917/debian/fex.postinst	2014-12-15 10:17:32.000000000 +0100
+++ fex-20150120/debian/fex.postinst	2015-01-21 10:20:40.000000000 +0100
@@ -200,8 +200,8 @@
     fi
     if [ -f /etc/exim/exim.conf -o -f /var/lib/exim4/config.autogenerated ]; then
         # exim4 found...
-        [ ! -f /var/lib/exim4/config.autogenerated ]||ISTRUSTED=$(egrep '^\s*(MAIN_TRUSTED_USERS|trusted_users)\s*=.*fex' /var/lib/exim4/config.autogenerated)
-        [ ! -f /etc/exim/exim.conf ]||ISTRUSTED=$(egrep '^\s*(MAIN_TRUSTED_USERS|trusted_users)\s*=.*fex' /etc/exim/exim.conf)
+        [ ! -f /var/lib/exim4/config.autogenerated ]||ISTRUSTED=$(egrep '^\s*(MAIN_TRUSTED_USERS|trusted_users)\s*=.*fex' /var/lib/exim4/config.autogenerated||true)
+        [ ! -f /etc/exim/exim.conf ]||ISTRUSTED=$(egrep '^\s*(MAIN_TRUSTED_USERS|trusted_users)\s*=.*fex' /etc/exim/exim.conf||true)
         [ -z "$ISTRUSTED" ]||echo "You're running exim4 and fex isn't in the trusted_users list. Consider adding or email notifications may not work!"
     fi
     
diff -Nru fex-20140917/debian/htdocs.md5/20141219-1 fex-20150120/debian/htdocs.md5/20141219-1
--- fex-20140917/debian/htdocs.md5/20141219-1	1970-01-01 01:00:00.000000000 +0100
+++ fex-20150120/debian/htdocs.md5/20141219-1	2015-01-21 10:20:40.000000000 +0100
@@ -0,0 +1,24 @@
+89b404d0404eb3b0eba54a662e04c8ce  htdocs/FAQ/admin.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/admin.html
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/all.html
+91e99f12ccb9f7cc3c399d5c3b0de1aa  htdocs/FAQ/faq.pl
+18ea97a73b75ac6a09cd6176405575c9  htdocs/FAQ/local.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/local.html
+9957852ccdef1f1196b55abf18fe5f61  htdocs/FAQ/meta.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/meta.html
+8efac8c29f2493f7cf587397a3383573  htdocs/FAQ/misc.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/misc.html
+736fe1c5be22c469b1bb973230cdd29d  htdocs/FAQ/user.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/user.html
+8fef1010d65fcae7afcc991d0a889378  htdocs/SEX.html
+1f3d7acc70377496f95c5adddaf4ca7b  htdocs/action-fex-camel.gif
+9518c02523c765d590465393659bfa13  htdocs/dynamic.html
+d41d8cd98f00b204e9800998ecf8427e  htdocs/favicon.ico
+0341cffa891dc5bb3221fbf3edf95202  htdocs/features.html
+54c81afa02df999d3f096685caa5258a  htdocs/fup_template.html
+bdf9506feb34a5f22eb302e48ba9d9df  htdocs/index.html
+ad8a95bba8dd1a61d70bd38611bc2059  htdocs/logo.jpg
+f71d20196d4caf35b6a670db8c70b03d  htdocs/robots.txt
+968a8facfcdd185ad696b86b67ec63ff  htdocs/small_logo.jpg
+863744e12ec319a227c113b3c189c41f  htdocs/sup.html
+9c4136f2a7158d704e9999f052104377  htdocs/tools.html
diff -Nru fex-20140917/debian/htdocs.md5/20150120-1 fex-20150120/debian/htdocs.md5/20150120-1
--- fex-20140917/debian/htdocs.md5/20150120-1	1970-01-01 01:00:00.000000000 +0100
+++ fex-20150120/debian/htdocs.md5/20150120-1	2015-01-21 10:20:40.000000000 +0100
@@ -0,0 +1,26 @@
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/FAQ.html
+bcb051e62706c3e156077b9368de91cd  htdocs/FAQ/admin.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/admin.html
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/all.html
+91e99f12ccb9f7cc3c399d5c3b0de1aa  htdocs/FAQ/faq.pl
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/index.html
+6f7e1a56ba9a8e5a42def936729e2089  htdocs/FAQ/local.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/local.html
+9957852ccdef1f1196b55abf18fe5f61  htdocs/FAQ/meta.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/meta.html
+8efac8c29f2493f7cf587397a3383573  htdocs/FAQ/misc.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/misc.html
+736fe1c5be22c469b1bb973230cdd29d  htdocs/FAQ/user.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/user.html
+8fef1010d65fcae7afcc991d0a889378  htdocs/SEX.html
+1f3d7acc70377496f95c5adddaf4ca7b  htdocs/action-fex-camel.gif
+9518c02523c765d590465393659bfa13  htdocs/dynamic.html
+d41d8cd98f00b204e9800998ecf8427e  htdocs/favicon.ico
+0341cffa891dc5bb3221fbf3edf95202  htdocs/features.html
+54c81afa02df999d3f096685caa5258a  htdocs/fup_template.html
+bdf9506feb34a5f22eb302e48ba9d9df  htdocs/index.html
+ad8a95bba8dd1a61d70bd38611bc2059  htdocs/logo.jpg
+f71d20196d4caf35b6a670db8c70b03d  htdocs/robots.txt
+968a8facfcdd185ad696b86b67ec63ff  htdocs/small_logo.jpg
+863744e12ec319a227c113b3c189c41f  htdocs/sup.html
+9c4136f2a7158d704e9999f052104377  htdocs/tools.html
diff -Nru fex-20140917/debian/htdocs.md5/20150120-2 fex-20150120/debian/htdocs.md5/20150120-2
--- fex-20140917/debian/htdocs.md5/20150120-2	1970-01-01 01:00:00.000000000 +0100
+++ fex-20150120/debian/htdocs.md5/20150120-2	2015-01-21 10:20:40.000000000 +0100
@@ -0,0 +1,26 @@
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/FAQ.html
+bcb051e62706c3e156077b9368de91cd  htdocs/FAQ/admin.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/admin.html
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/all.html
+91e99f12ccb9f7cc3c399d5c3b0de1aa  htdocs/FAQ/faq.pl
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/index.html
+6f7e1a56ba9a8e5a42def936729e2089  htdocs/FAQ/local.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/local.html
+9957852ccdef1f1196b55abf18fe5f61  htdocs/FAQ/meta.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/meta.html
+8efac8c29f2493f7cf587397a3383573  htdocs/FAQ/misc.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/misc.html
+736fe1c5be22c469b1bb973230cdd29d  htdocs/FAQ/user.faq
+6d3b691d1e3b1786c0bf735604fb9817  htdocs/FAQ/user.html
+8fef1010d65fcae7afcc991d0a889378  htdocs/SEX.html
+1f3d7acc70377496f95c5adddaf4ca7b  htdocs/action-fex-camel.gif
+9518c02523c765d590465393659bfa13  htdocs/dynamic.html
+d41d8cd98f00b204e9800998ecf8427e  htdocs/favicon.ico
+0341cffa891dc5bb3221fbf3edf95202  htdocs/features.html
+54c81afa02df999d3f096685caa5258a  htdocs/fup_template.html
+bdf9506feb34a5f22eb302e48ba9d9df  htdocs/index.html
+ad8a95bba8dd1a61d70bd38611bc2059  htdocs/logo.jpg
+f71d20196d4caf35b6a670db8c70b03d  htdocs/robots.txt
+968a8facfcdd185ad696b86b67ec63ff  htdocs/small_logo.jpg
+863744e12ec319a227c113b3c189c41f  htdocs/sup.html
+9c4136f2a7158d704e9999f052104377  htdocs/tools.html
diff -Nru fex-20140917/debian/patches/03_fexget_search_ca.patch fex-20150120/debian/patches/03_fexget_search_ca.patch
--- fex-20140917/debian/patches/03_fexget_search_ca.patch	1970-01-01 01:00:00.000000000 +0100
+++ fex-20150120/debian/patches/03_fexget_search_ca.patch	2015-01-21 10:20:40.000000000 +0100
@@ -0,0 +1,123 @@
+Backported from http://fex.rus.uni-stuttgart.de:8080/download/fexget to avoid perl warning
+--- a/bin/fexget
++++ b/bin/fexget
+@@ -30,7 +30,7 @@ our $SH;
+ our ($fexhome,$idf,$tmpdir,$windoof,$useragent);
+ our ($xv,%autoview);
+ our $bs = 2**16; # blocksize for tcp-reading and writing file
+-our $version = 20150120;
++our $version = 20150121;
+ our $CTYPE = 'ISO-8859-1';
+ our $fexsend = $ENV{FEXSEND} || 'fexsend';
+ 
+@@ -157,48 +157,7 @@ if ($opt_H) {
+   exit;
+ }
+ 
+-# 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;
+-    }
+-  }
+-}
++&get_ssl_env;
+ 
+ my $ffl = "$tmpdir/fexget"; 		# F*EX files list (cache)
+ 
+--- a/htdocs/download/fexget
++++ b/htdocs/download/fexget
+@@ -30,7 +30,7 @@ our $SH;
+ our ($fexhome,$idf,$tmpdir,$windoof,$useragent);
+ our ($xv,%autoview);
+ our $bs = 2**16; # blocksize for tcp-reading and writing file
+-our $version = 20150120;
++our $version = 20150121;
+ our $CTYPE = 'ISO-8859-1';
+ our $fexsend = $ENV{FEXSEND} || 'fexsend';
+ 
+@@ -157,48 +157,7 @@ if ($opt_H) {
+   exit;
+ }
+ 
+-# 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;
+-    }
+-  }
+-}
++&get_ssl_env;
+ 
+ my $ffl = "$tmpdir/fexget"; 		# F*EX files list (cache)
+ 
diff -Nru fex-20140917/debian/patches/series fex-20150120/debian/patches/series
--- fex-20140917/debian/patches/series	2014-12-15 10:17:32.000000000 +0100
+++ fex-20150120/debian/patches/series	2015-01-21 10:20:40.000000000 +0100
@@ -1,2 +1,3 @@
 01_xinetd.patch
 02_fex.ph_no_newrelease.patch
+03_fexget_search_ca.patch
diff -Nru fex-20140917/debian/rules fex-20150120/debian/rules
--- fex-20140917/debian/rules	2014-12-15 10:17:32.000000000 +0100
+++ fex-20150120/debian/rules	2015-01-21 10:20:40.000000000 +0100
@@ -47,6 +47,8 @@
 	dh_installdocs
 	cp doc/new debian/fex/usr/share/doc/fex/NEWS
 	echo "fex_$(DEBVERSION)" >debian/fex/usr/share/fex/htdocs/version
+	# update file system paths in FAQ
+	sed -i -e 's,/home/fex/,/var/lib/fex/,g' debian/fex/usr/share/fex/htdocs/FAQ/*
 	@(cd debian/fex/usr/share/fex/;find htdocs/ -type f|grep -v -e version -e FAQ/jquery.js -e download/ |LC_ALL=C sort|xargs -n 1 md5sum >../../../../fex.md5.check)
 	if diff -q debian/fex.md5.check debian/htdocs.md5/$(DEB_NOEPOCH_VERSION) >/dev/null;then \
 		echo "Correct htdocs md5sum found."; \
diff -Nru fex-20140917/doc/Changes fex-20150120/doc/Changes
--- fex-20140917/doc/Changes	2014-09-17 21:34:21.000000000 +0200
+++ fex-20150120/doc/Changes	2015-01-17 11:44:54.000000000 +0100
@@ -1,5 +1,50 @@
+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
+           fixed bug wrong result for recipients with NOTIFICATION=no
+2015-01-13 fexsend: added option -N resend notification email
+           resending notification email deletes download ip restriction
+           fup: fixed bug sending to groups broken
+2015-01-10 fexsend: added option -S show server/user settings
+           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
+           fexget,fexsend,sexsend: use TLS, not SSL
+2014-12-23 fexsend: $HOME/.fex/config with $opt_* and %alias variables
+           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
+           fexwall: also mail to sub and group users
+2014-12-03 fup: remove file after upload if restricted user has set NOMAIL
+           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
+           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
+           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)
@@ -32,7 +77,7 @@
 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 e-mails for @remote_domains
+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
diff -Nru fex-20140917/doc/concept fex-20150120/doc/concept
--- fex-20140917/doc/concept	2014-09-11 11:05:43.000000000 +0200
+++ fex-20150120/doc/concept	2015-01-17 11:29:28.000000000 +0100
@@ -132,11 +132,13 @@
 
 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).
+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).
+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
@@ -155,8 +157,8 @@
 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 = 1;
-$force_https = 1;
+$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
@@ -225,22 +227,26 @@
 	fup.log				log of file uploads
 	fur.log				log of user self registrations
 	sex.log				log of stream exchanges
-	$from/@				regular user auth-ID
-	$from/@SUBUSER			subuser addresses and IDs
-	$from/@ALLOWED_RECIPIENTS	recipients restrictions for this user
-	$from/@ADDRESS_BOOK		users recipient address book
-	$from/@GROUP			directory of F*EX user groups
-	$from/@OKEY			directory with one time upload keys
-	$from/@QUOTA			sender and recipient quotas
-	$from/@AUTODELETE		autodelete default
-	$from/@KEEP			keep default
-	$from/@LOCALE			locale default
+	$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/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
@@ -251,6 +257,7 @@
 	$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
 
@@ -287,7 +294,7 @@
 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.
+notification email. 
 
 XKEY is an optional extra download key to have a short download URL in
 shape http://YOURFEXSERVER//XKEY
@@ -366,6 +373,10 @@
 - 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:
@@ -433,8 +444,12 @@
 
 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
 
diff -Nru fex-20140917/doc/Contribs fex-20150120/doc/Contribs
--- fex-20140917/doc/Contribs	2013-07-09 17:59:00.000000000 +0200
+++ fex-20150120/doc/Contribs	2014-12-26 00:18:59.000000000 +0100
@@ -26,6 +26,11 @@
 Daniel Dieckmann <Daniel_Dieckmann@genua.de>
   - fexget proxy support
 
+Kilian Krause <kilian@debian.org>
+  - Debian package maintainer
+  - SSL security enhancements
+  - annoying, but useful requests ;-)
+
 Hanno Hirsch <superhanno@gmx.de>:
   - bug hunting
 
diff -Nru fex-20140917/doc/installation fex-20150120/doc/installation
--- fex-20140917/doc/installation	2014-08-28 23:21:51.000000000 +0200
+++ fex-20150120/doc/installation	2014-09-23 23:19:46.000000000 +0200
@@ -45,12 +45,13 @@
 
 echo "fex 80/tcp" >> /etc/services
 echo "fex stream tcp nowait fex /home/fex/bin/fexsrv fexsrv" >> /etc/inetd.conf
-# now restart inetd
+# restart inetd or reboot
 useradd -s /bin/bash -c "File EXchange" -m fex
-pwd # --> FEXSOURCEDIR
+cd FEXSOURCEDIR
+chown -R fex .
 su - fex
 cd FEXSOURCEDIR
-cp -av bin cgi-bin lib etc htdocs doc $HOME
+rsync -av bin cgi-bin lib etc htdocs doc $HOME
 cd $HOME
 mkdir spool
 chmod 700 spool
diff -Nru fex-20140917/doc/newfeatures fex-20150120/doc/newfeatures
--- fex-20140917/doc/newfeatures	2014-08-06 00:37:11.000000000 +0200
+++ fex-20150120/doc/newfeatures	2015-01-14 08:53:59.000000000 +0100
@@ -1,6 +1,27 @@
 New features for users
 ----------------------
 
+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
diff -Nru fex-20140917/doc/SSL fex-20150120/doc/SSL
--- fex-20140917/doc/SSL	2013-06-20 20:44:26.000000000 +0200
+++ fex-20150120/doc/SSL	2015-01-07 15:15:10.000000000 +0100
@@ -19,6 +19,10 @@
 execargs = perl -T /home/fex/bin/fexsrv stunnel
 EOD
 
+case $(lsb_release -a 2>/dev/null) in 
+  *CentOS*) echo 'fips = no' >>stunnel.conf;;
+esac
+
 chown -R fex .
 
 stunnel=$(which stunnel4)
diff -Nru fex-20140917/doc/version fex-20150120/doc/version
--- fex-20140917/doc/version	2014-09-17 22:07:21.000000000 +0200
+++ fex-20150120/doc/version	2015-01-20 10:59:25.000000000 +0100
@@ -1 +1 @@
-fex-20140917
+fex-20150120
diff -Nru fex-20140917/htdocs/download/fexget fex-20150120/htdocs/download/fexget
--- fex-20140917/htdocs/download/fexget	1970-01-01 01:00:00.000000000 +0100
+++ fex-20150120/htdocs/download/fexget	2015-01-19 13:59:57.000000000 +0100
@@ -0,0 +1,1074 @@
+#!/usr/bin/perl -w
+
+# CLI client for the FEX service for retrieving files
+#
+# see also: fexsend
+#
+# Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
+#
+# Perl Artistic Licence
+
+use 5.006;
+use strict qw'vars subs';
+use Config;
+use POSIX;
+use Encode;
+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 = 20150120;
+our $CTYPE = 'ISO-8859-1';
+our $fexsend = $ENV{FEXSEND} || 'fexsend';
+
+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;
+} 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 = <<EOD;
+usage: $0 [-v] [-m limit] [-s filename] [-o] [-k] [-X] [-P proxy:port] F*EX-URL(s)
+   or: $0 [-v] -d F*EX-URL(s)
+   or: $0 [-v] -f F*EX-URL(s) e-mail-address
+   or: $0 [-v] -a
+   or: $0 -l [-i tag]
+   or: $0 -H
+options: -v verbose mode
+         -m limit kB/s
+         -s save to filename (-s- means: write to STDOUT/pipe)
+         -o overwrite existing file
+  	 -k keep on server after download
+  	 -X do not extract archive files or autoview file
+  	 -d delete without download
+  	 -f forward a file to another recipient
+         -a get all files (implies -X)
+  	 -l list files on server
+         -i tag alternate server/account, see: $fexsend -h
+         -P use Proxy for connection to the F*EX server
+         -H show hints and examples
+argument: F*EX-URL may be file number (see: $0 -l)
+EOD
+
+my $hints = <<'EOD';
+When you download a file with extension .jpg .gif .png or .tif an image viewer
+will be started. This can be xv or xdg-open.
+In $HOME/.fex/config.pl you can set your prefered autoview applications:
+
+%autoview = (
+  '\.(gif|jpg|png|tiff?)' => '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('hvVHlLdkzoaXf+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
+}
+
+print "Version: $version\n" if $opt_V;
+die $usage                  if $opt_h;
+if ($opt_H) {
+  print $hints;
+  exit;
+}
+
+# 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;
+    }
+  }
+}
+
+my $ffl = "$tmpdir/fexget"; 		# F*EX files list (cache)
+
+my @rcamel = (
+'
+(_*)  _  _     
+   \\\\/ \\/ \\
+    \  __  )=*
+    //\\\\//\\\\   
+',
+'     \\\\/\\\\/ 
+',
+'    //\\\\//\\\\
+');
+
+# 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 = <STDIN>);
+        if ($url =~ /^http/) {
+          @ARGV = ($url);
+          last;
+        }
+      }
+    } else {
+      die $usage;
+    }
+  }
+}
+
+my ($file,%files,$download,$server,$port,$fop);
+
+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+)}) {
+    $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",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\"? ";
+      $_ = <STDIN>||'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);
+        $_ = <STDIN>||'';
+        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
+      if (my $xv = $xv || pathsearch('xv') || pathsearch('xdg-open')) {
+        printf "run \"%s %s\" [Yn] ? ",basename($xv),basename($download);
+        $_ = <STDIN>||'';
+        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/\.[^.]+$//;
+    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";
+  system(split(' ',$x),$download);
+}
+
+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);
+  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;
+  
+  unless (/^HTTP.*200/) {
+    s/^HTTP.... \d+ //;
+    die "$0: $_";
+  }
+  
+  while (<$SH>) {
+    s/\r//;
+    last if /^\n/; # ignore HTML output
+    $dkey = $1 if /^Location:.*\/(\w+)\/.+/;
+    warn "<-- $_" if $opt_v;
+  }
+
+  $cmd = 'fexsend -l >/dev/null 2>&1';
+  print "$cmd\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);
+  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;
+    } else {
+      $download = $file.'.tmp';
+      $seek = -s $download || 0;
+    }
+  } else {
+    # ask server for real file name
+    serverconnect($server, $port);
+    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;
+  }
+
+  push @hh,"GET $proxy_prefix$fop$opt_k HTTP/1.1",
+           "User-Agent: $useragent",
+           "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) {
+      $t0 = time;
+      my $n = 0;
+      print STDERR "checking storage...\r";
+      $buf = '.' x M;
+      while (-s $download < $checkstorage) {
+        syswrite X,$buf or do {
+          unlink $download;
+          die "\n$0: cannot write $download - $!\n";
+        };
+        $n++;
+        print STDERR "checking storage... ".$n." MB\r";
+      }
+      close X or do {
+        unlink $download;
+        die "\n$0: cannot write $download - $!\n";
+      };
+      print STDERR "checking storage... ".$n." MB ok!\n";
+      unlink $download;
+      if (time-$t0 < 25) {
+        open X,'>',$download or die "$0: cannot write to \"$download\" - $!\n";
+      } else {
+        # retry after timeout
+        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";
+  }
+}
+
+    
+sub quote {
+  local $_ = shift;
+  s/([^\w¡-ÿ_%\/=~:.,-])/\\$1/g;
+  return $_;
+}
+
+    
+{
+  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;
+        foreach my $a (split("",$default)) { ioctl($tty,&TIOCSTI,$a) } 
+        chomp($_ = <STDIN>||'');
+      } else {
+        $prompt =~ s/([\?:=]\s*)/ [$default]$1/ or $prompt .= " [$default]";
+        print $prompt;
+        chomp($_ = <STDIN>||'');
+        $_ = $default unless length;
+      }
+    } else {
+      print $prompt;
+      chomp($_ = <STDIN>||'');
+    }
+
+    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 ($opt_v and $port == 443 and %SSL) {
+    foreach my $v (keys %SSL) {
+      printf "%s => %s\n",$v,$SSL{$v};
+    }
+  }
+  
+  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,%SSL);
+    }
+  } else {
+    tcpconnect($server,$port);
+  }
+#  if ($port == 443 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 ($port == 443) {
+    # eval "use IO::Socket::SSL qw(debug3)";
+    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',
+    );
+  }
+  
+  if ($SH) {
+    autoflush $SH 1;
+  } else {
+    die "$0: cannot connect $server:$port - $@\n";
+  }
+  
+  print "TCPCONNECT to $server:$port\n" if $opt_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;
+}
+
+
+# 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;
+}
diff -Nru fex-20140917/htdocs/download/fexsend fex-20150120/htdocs/download/fexsend
--- fex-20140917/htdocs/download/fexsend	1970-01-01 01:00:00.000000000 +0100
+++ fex-20150120/htdocs/download/fexsend	2015-01-16 15:52:53.000000000 +0100
@@ -0,0 +1,3055 @@
+#!/usr/bin/perl -w
+
+# CLI client for the F*EX service (send, list, delete)
+#
+# see also: fexget
+#
+# Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
+#
+# 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 qw'abs_path';
+use Fcntl qw':flock :mode';
+use Digest::MD5 qw'md5_hex';  # encrypted ID / SID
+use Time::HiRes qw'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,$useragent,$editor,$nomail);
+our ($anonymous,$public);
+our ($tpid,$frecipient);
+our ($FEXID,$FEXXX,$HOME);
+our (%alias);
+our $chunksize = 0;
+our $version = 20150120;
+our $_0 = $0;
+our $DEBUG;
+
+my %SSL = (SSL_version => 'TLSv1');
+my $sigpipe;
+
+if ($Config{osname} =~ /^mswin/i) {
+  $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;
+} else {
+  $0 =~ s:.*/::;
+  $HOME = (getpwuid($<))[7]||$ENV{HOME};
+  $fexhome = $HOME.'/.fex';
+  $tmpdir = $ENV{FEXTMP} || "$fexhome/tmp";
+  $idf = "$fexhome/id";
+  $editor = $ENV{EDITOR} || 'vi';
+  $_ = `(lsb_release -d||uname -a)2>/dev/null`||'';
+  chomp;
+  s/^Description:\s+//;
+  $useragent = "fexsend-$version ($_)";
+  chmod 0600,$idf;
+}
+
+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);
+my $proxy = '';
+my $proxy_prefix = '';
+my $features = ''; 
+my $timeout = 30; 	# server timeout
+my $fexlist = "$tmpdir/fexlist";
+my ($usage,$hints);
+my $xx = $0 =~ /^xx/;
+
+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 = <<EOD;
+usage: $0 [options] file(s) [@] recipient(s)
+   or: $0 [special options]
+   or: $0 -f \# recipient(s)
+   or: $0 -x \# [-C -k -D -K -S]
+options: -v           verbose mode
+         -d           delete file on fex server
+         -c           compress file
+         -g           encrypt file with gpg
+         -m limit     limit throughput (kB/s)
+         -i tag       use ID data [tag] from ID file
+         -C comment   add comment to notification e-mail
+         -k max       keep file max days on fex server
+         -D           delay auto-delete after download
+         -K           no auto-delete after download
+         -M           MIME-file (to be displayed in recipient\'s webbrowser)
+         -o           overwrite mode, do not resume
+         -a archive   put files in archive (.zip .7z .tar .tgz)
+         -s stream    read data from pipe and upload it with stream name
+special options: -I      initialize ID file or show ID
+                 -I tag  add alternate ID data (secondary logins) to ID file
+                 -l      list sent files numbered (# needed for -f -x -d -N)
+                 -f \#    forward already uploaded file to another recipient
+                 -x \#    modify options -C -k -D -K for already uploaded file
+                 -d \#    delete file on fex server
+                 -N \#    resend notification e-mail
+                 -Q      check quotas
+                 -A      edit server address book (aliases)
+                 -S      show server/user settings and auth-ID
+                 -H      show hints, examples and more options
+                 -V      show version
+                 (\# is a file number, see output from $0 -l)
+examples: $0 visualization.mpg framstag\@rus.uni-stuttgart.de
+          $0 -a images.zip *.jpg webmaster\@flupp.org,metoo
+          lshw | $0 -s hardware.list admin\@flupp.org
+EOD
+#   or: $0 -R FEX-URL e-mail
+#         -R FEX mail  self-register your e-mail address at FEX server
+
+  $hints = <<EOD;
+$0 hints and more options:
+  
+usage: $0 [options] file recipient(s)
+
+Recipient can be a comma separated address list. Example:
+  $0 big.file framstag\@rus.uni-stuttgart.de,webmaster\@flupp.org
+
+Recipient can be an alias from your server address book 
+(use "$0 -A" to edit it). Example:
+  $0 big.file framstag
+
+Recipient can be a SKEY URL, which you have received from a regular F*EX user.
+When using this URL you are a subuser of this full user and the file will be 
+sent to him. Example:
+  $0 big.file http://fex.rus.uni-stuttgart.de/fup?skey=4285f8cdd881626524fba686d5f0a83a
+
+Recipient can be a GKEY URL, which you have received from a regular F*EX user.
+Using this URL you are a member of his group and the file will be sent to all
+members of this group. Example:
+  $0 big.file http://fex.rus.uni-stuttgart.de/fup?gkey=50d26547b1e8c1110beb8748fc1d9444
+
+When you use "FEX-URL/anonymous" as recipient and your F*EX administrator has 
+allowed anonymous upload for your IP address then no auth-ID is needed.
+    
+"." as recipient means fex to yourself and show immediately the download URL 
+(no notification e-mail will be sent). Example:
+  $0 software.tar .
+
+"//" as recipient means fex to yourself and create extra short download URL.
+Example:
+  $0 software.tar //
+
+If you want a Bcc of the notification e-mail then add '!bcc!' to the comment:
+fexsend -C '!bcc! for me and you' ...
+
+Additional special options:
+
+  -. sends a short instead of a detailed notification e-mail
+  -/ does not upload the file, but tells the server to link it
+  -= uses an alias name as file name
+  -# excludes files (# is list separator) from archive -a
+  -n sends no notification e-mail, but shows the download URL immediately
+  -q is quiet mode
+  -r ADDRESS sets e-mail Reply-To ADDRESS
+  -F activates female mode
+  -U show authorized URL
+  -+ is an undocumented feature - test it :-)
+    
+To manage your subuser and groups or forward or redirect files, use a 
+webbrowser with the URL from "$0 -U", e.g.:  firefox \$($0 -U)
+
+If you want to copy-forward an already uploaded file to another recipient,
+then you first have to query the file number with:
+  $0 -l
+and then copy-forward it with:
+  $0 -b # other\@address
+Where # is the file number.
+
+If you want to modify the keep time, comment or auto-delete behaviour of an
+already uploaded file then you first have to query the file number with:
+  $0 -l
+and then for example set the keep time to 30 days with:
+  $0 -x # -k 30
+Where # is the file number.
+
+With option -a you can send several files or whole directories within a single
+archive file. The archive types tar and tgz are build on-the-fly (streaming) 
+whereas archive types zip and 7z need a temporary archive file on local disk.
+
+With option -s you can send any data coming from a pipe (STDIN) as a file
+without wasting local disc space.
+ 
+With option -X you can specify any parameter, e.g.: -X autodelete=yes
+
+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
+  
+Partner program xx is an internet clipboard. See: xx -h
+  
+Partner program fexget is for downloading. See: fexget -h
+  
+For temporary usage of a HTTP proxy use: 
+  $0 -P your_proxy:port:chunksize_in_MB file recipient
+Example:
+  $0 -P wwwproxy.uni-stuttgart.de.de:8080:1024 4GB.tar .
+  
+For temporary usage of an alternative F*EX server or user use: 
+  FEXID="FEXSERVER USER AUTHID" $0 file recipient
+Example:
+  FEXID="fex.flupp.org gaga\@flupp.org blubb" $0 big.file framstag\@rus.uni-stuttgart.de
+
+You can define aliases (and optional fexsend options) in \$HOME/.fex/config.pl:
+  %alias = (
+    'alias1' => '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*_)
+    / \/ \//
+ *=(  __  /
+    \\\\/\\\\/
+',
+'    \\\\/\\\\/ 
+',
+'   //\\\\//\\\\
+');
+
+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);
+
+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 {
+  $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 = '';
+  $_ = "$fexhome/config.pl"; require if -f;
+  getopts('hHvcdognVDKlILUARWMFzZqQS@!+./r:m:k:u:f:a:s:C:i:b:P:x:X:N:=:#:') 
+    or die $usage;
+
+  if ($opt_H) {
+    print $hints;
+    exit;
+  }
+  
+  if ($opt_V) {
+    print "Version: $version\n";
+  }
+  
+  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) {
+  &register;
+  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 (@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 (0 and $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"; 
+}
+
+$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 }
+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 = <STDIN>;
+  $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;
+    $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 = <STDIN>;
+  $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): ";
+    $_ = <STDIN>;
+    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 = <STDIN>;
+      $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 = <STDIN>;
+      $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>;
+    $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();
+
+  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";
+
+}
+
+
+sub send_xx {
+  my $transferfile = shift;
+  my $file = '';
+  my (@r,@tar);
+  
+  $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) {
+        my ($dir,$file);
+        # 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,$n);
+  local $_;
+
+  female_mode("list spooled files?") if $opt_F;
+
+  if ($opt_l and $n = shift @ARGV and $n =~ /^\d+$/) {
+    open $fexlist,$fexlist or die "$0: $fexlist - $!\n";
+    while (<$fexlist>) {
+      if (/^\s*(\d+)\) (\w+) (.+)/ and $1 eq $n) {
+        serverconnect($server,$port) unless $SH;
+        sendheader(
+          "$server:$port",
+          "GET $proxy_prefix/fop/$2/$2?LIST HTTP/1.1",
+          "User-Agent: $useragent",
+        );
+        $_ = <$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 \#$n not found in fexlist\n";
+  } else {
+    @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 /<pre>/ or $data;
+      $data = 1;
+      last if m:</pre>:;
+      if (/<a href=".*dkey=(\w+).*?">/) { $dkey = $1 }
+      else                              { $dkey = '' }
+#      $_ = encode_utf8($_);
+      s/<.*?>//g;
+      if (/^(to .* :)/) {
+        print "\n$1\n";
+        print {$fexlist} "\n$1\n";
+      } elsif (m/(\d+) MB (.+)/) {
+        $n++;
+        printf "%4s) %8d MB %s\n","#$n",$1,$2;
+        printf {$fexlist} "%3d) %s %s\n",$n,$dkey,$2;
+      }
+    }
+    close $fexlist;
+  } 
+  
+  # list received files
+  if ($opt_L) {
+    foreach (@r) {
+      next unless /<pre>/ or $data;
+      $data = 1;
+      next if m:<pre>:;
+      last if m:</pre>:;
+      if (/(from .* :)/) {
+        print "\n$1\n";
+      }
+      if (m{(\d+) (MB.*)<a href="(https?://.*/fop/\w+/.+)">(.+)</a>( ".*")?}) {
+        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 {
+  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",
+          "User-Agent: $useragent",
+        );
+        $_ = <$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 send_fex {
+  my @to;
+  my $file = '';
+  my @files = ();
+  my ($data,$aname,$alias);
+  my (@r,$r);
+  my $ma = $HOME.'/.mutt/aliases';
+  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 and open $ma,$ma) {
+          $alias = $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 = $alias\n";
+                last;
+              }
+              if (/@/) {
+                $alias = $_;
+                warn "$0: found mutt alias $to = $alias\n";
+                last;
+              }
+            }
+          }
+          close $ma;
+          $to = $alias;
+        }
+      }
+    }
+  
+    $to = join(',',grep /./,@to) or exit;
+    warn "Server/User: $fexcgi/$from\n" unless $opt_q;
+  
+    if (
+      not $skey and not $gkey
+      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 [ENTER] to send file for file:\n";
+    $opt_a = <STDIN>;
+    $opt_a =~ s/^\s+//;
+    $opt_a =~ s/\s+$//;
+  }
+
+  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);
+      } 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);
+        @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";
+    }
+    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";
+      } else {
+        $r =~ s/.*?:\s*//;
+        $r =~ s/<.+?>//g;
+        die "$0: server error: $r\n";
+      }
+    }
+    if (($r) = grep /<h3>\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,$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";
+            print "$location\n";
+          }
+        }
+      }
+    }
+  }
+  
+  # delete transfer tmp file
+  unlink $transferfile if $transferfile;
+}
+
+
+sub forward {
+  my (@r);
+  my ($to,$n,$dkey,$file,$req);
+  my $status = 1;
+  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 '.';
+
+  open $fexlist,$fexlist or die "$0: $fexlist - $!\n";
+  while (<$fexlist>) {
+    if (/^\s*(\d+)\) (\w+) \[\d+ d\] (.+)/ and $1 eq $opt_f) {
+      $n = $1;
+      $dkey = $2;
+      $file = $3;
+      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();
+  while (<$SH>) { 
+    if ($opt_v) {
+      print;
+      $status = 0 if /\Q"$file"/;
+    } else {
+      if (/\Q"$file"/) {
+        print;
+        $status = 0;
+      }
+    }
+  }
+  
+  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+) \[\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+) \[\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] ";
+      $_ = <STDIN>;
+    }
+    if (/^n/i) {
+      print "keeping $transferfile\n";
+    } else {
+      system("tar xvf $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,$filesize,$length,$buf,$file,$fpsize,$resume,$seek);
+  my ($flink);
+  my (@hh,@hb,@r,@pv,$to);
+  my ($bytes,$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 $connection = '';
+  my $pct = '';
+  my ($tar,$aname,$atype,$tarlist,$tarerror,$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;
+      $tarlist  = "$tmpdir/$aname.list";
+      $tarerror = "$tmpdir/$aname.error";
+      $tar = 'tar -cv';
+      $tar .= 'z' if $atype eq 'tgz';
+      if (`tar --help 2>/dev/null` =~ /--index-file/) {
+        $tar .= " --index-file=$tarlist -f-";
+      } else {
+        $tar .= " -f-";
+      }
+      if (${'opt_#'}) {
+        foreach my $x (split('#',${'opt_#'})) {
+          $tar .= " --exclude=$x";
+        }
+      }
+      foreach (@ARGV) {
+        $file = $_;
+        $file =~ s/([^\w\-\@\#%,.=+~_:])/\\$1/g;
+        $tar .= ' '.$file;
+      }
+      # print "calculating archive size... ";
+      open $tar,"$tar 2>$tarerror|" 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 $tarerror,$tarerror) {
+          local $/;
+          $_ = <$tarerror>;
+          close $tarerror;
+        }
+        unlink $tarlist,$tarerror;
+        die "$0: tar error:\n$_";
+      }
+      $file = "$aname.$atype";
+      $filename = encode_utf8($file);
+      undef $SH; # force reconnect (timeout!)
+    } 
+    
+    # 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) {
+      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;
+  }
+  
+  $P{id} = $sid; # ugly hack!
+  
+  # ask server if this file has been already sent
+  if ($file and not $xx and not 
+      ($opt_s or $opt_g or $opt_o 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 $file;
+    } 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});
+    }
+  }
+  
+  # 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 $tarlist,$tarlist) {
+              # print "\n$tar|\n"; system "ls -l $tarlist";
+              while ($tarlist) {
+                while (<$tarlist>) {
+                  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);
+        }
+      } else {
+        if ($opt_g) {
+          my $fileq = $file;
+          $fileq =~ s/([^\w\-\@\#%,.=+~_:])/\\$1/g;
+          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_+'};
+
+      while (my $b = read $file,$buf,$bs) {
+        print {$SH} $buf or &sigpipehandler;
+        $bytes += $b;
+        if ($filesize > 0 and $bytes+$seek > $filesize) {
+          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; # or die "$0: error while reading $file - $!\n";
+      $tt = ($t2-$t0)||1;
+      
+      print $rcamel[2] if ${'opt_+'};
+      
+      # terminate tar verbose output job
+      if ($tpid) {
+        sleep 2;
+        kill 9,$tpid;
+        unlink $tarlist;
+      }
+    
+      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)) {
+          print STDERR "waiting for server ok..."
+        }
+      }
+    }
+    
+    autoflush $SH 1;
+    print {$SH} "\r\n--$boundary--\r\n";
+
+    # 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);
+  local $_;
+  
+  $to =~ s/,.*//;
+  $to =~ s/:\w+=.*//;
+  $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 }
+  }
+
+  # return true seek only if file is identified
+  $seek = 0 if $qfileid and $qfileid ne $fileid;
+  
+  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) {
+    return if $features;    # early return if we know enough
+    $req = "OPTIONS FEX HTTP/1.1";
+  } elsif ($proxy) {
+    return if $features;    # early return if we know enough
+    $req = "GET $proxy_prefix/SID HTTP/1.1";
+  } else {
+    $req = "GET SID HTTP/1.1";
+  }
+
+  sendheader("$server:$port",$req,"User-Agent: $useragent");
+  $_ = <$SH>;
+  unless (defined $_ and /\w/) {
+    print "\n" if $opt_v;
+    die "$0: no response from server\n";
+  }
+  s/\r//;
+  print "<-- $_" if $opt_v;
+    
+  if (/^HTTP.* [25]0[01] /) {
+    if (not $proxy and $port ne 443 and /^HTTP.* 201 (.+)/) {
+      $sid = 'MD5H:'.md5_hex($id.$1);
+    }
+    while (<$SH>) {
+      s/\r//;
+      print "<-- $_" if $opt_v;
+      $features = $1 if /^X-Features: (.+)/;
+      $timeout = $1  if /^X-Timeout: (\d+)/;
+      last if /^\n/;
+    }
+  } 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","User-Agent: $useragent");
+  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 F,">$save" or die "$0: cannot write to $save - $!\n";
+  binmode F;
+  
+  $t0 = $t1 = int(time);
+  $tso = '';
+  
+  while ($b = read($SH,$_,$bs)) {
+    $B += $b;
+    print F;
+    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 F;
+}
+
+
+# transfer status
+sub ts {
+  my ($b,$tb) = @_;
+  return sprintf("transferred: %d MB (%d%%)",int($b/M),int($b/$tb*100));
+}
+  
+
+sub sigpipehandler {
+  $SIG{ALRM} = sub { };
+  if (fileno $SH) {
+    alarm(1);
+    @_ = <$SH>;
+    alarm(0);
+    kill 9,$tpid if $tpid;
+    if (@_ and $opt_v) {
+      die "\n$0: ($$) server error: @_\n";
+    }
+    if (@_ and $_[0] =~ /^HTTP.* \d+ (.*)/) {
+      die "\n$0: server error: $1\n";
+    }
+  }
+  $timeout *= 2;
+  warn "\n$0: connection to $server died\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 /) {
+    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 = <STDIN>);
+    $file =~ s/^\"//;
+    $file =~ s/\"$//;
+    last if -e $file;
+    warn "$file does not exist\n";
+  }
+  print "recipient (e-mail address): ";
+  chomp($to = <STDIN>);
+  die $usage unless $to;
+  unless ($opt_n) {
+    print "comment: ";
+    chomp($opt_C = <STDIN>);
+  }
+  @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; 
+  }
+}
+
+
+# fileid is inode and mtime
+sub fileid {
+  my @s = stat(shift);
+  return @s ? $s[1].$s[9] : int(time);
+}
+
+
+# collect file meta data (filename, inode, mtime)
+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 .= $file.fileid($dir);
+          } else {
+            $fmd .= fmd("$dir/$file");
+          }
+        }
+        closedir $dir;
+      }
+    } else {
+      $fmd .= $file.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//;
+  # 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.]+//;
+    if ($opt_v) {
+      print "<-- $_";
+      print "<-- $_" while <$SH>;
+    }
+    die "$0: server error: $error\n";
+  }
+
+  print "<-- $_\n" if $opt_v;
+  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";
+  $_ = <$0>;
+  close $0;
+  s/.*\n$cfb\n//s;
+  $cfc = $_;
+  
+  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 $0 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 ($opt_v and $port == 443 and %SSL) {
+    foreach my $v (keys %SSL) {
+      printf "%s => %s\n",$v,$SSL{$v};
+    }
+  }
+  
+  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,%SSL);
+    }
+  } else {
+    tcpconnect($server,$port);
+  }
+#  if ($port == 443 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 ($port == 443) {
+    # eval "use IO::Socket::SSL qw(debug3)";
+    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',
+    );
+  }
+  
+  if ($SH) {
+    autoflush $SH 1;
+  } else {
+    die "$0: cannot connect $server:$port - $@\n";
+  }
+  
+  print "TCPCONNECT to $server:$port\n" if $opt_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;
+}
+
+
+# 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;
+}
diff -Nru fex-20140917/htdocs/download/sexget fex-20150120/htdocs/download/sexget
--- fex-20140917/htdocs/download/sexget	1970-01-01 01:00:00.000000000 +0100
+++ fex-20150120/htdocs/download/sexget	2015-01-19 13:59:57.000000000 +0100
@@ -0,0 +1,723 @@
+#!/usr/bin/perl -w
+
+# client for stream exchange of the FEX service
+#
+# Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
+#
+# 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 = 20150120;
+
+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') {
+  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 = 1;
+  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\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 (<F>) {
+      next if /,/;
+      if (/^alias $to\s/i) {
+        chomp;
+        s/\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 ($opt_v and $port == 443 and %SSL) {
+    foreach my $v (keys %SSL) {
+      printf "%s => %s\n",$v,$SSL{$v};
+    }
+  }
+  
+  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,%SSL);
+    }
+  } else {
+    tcpconnect($server,$port);
+  }
+#  if ($port == 443 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 ($port == 443) {
+    # eval "use IO::Socket::SSL qw(debug3)";
+    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',
+    );
+  }
+  
+  if ($SH) {
+    autoflush $SH 1;
+  } else {
+    die "$0: cannot connect $server:$port - $@\n";
+  }
+  
+  print "TCPCONNECT to $server:$port\n" if $opt_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;
+}
+
+
+# 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;
+}
diff -Nru fex-20140917/htdocs/download/sexsend fex-20150120/htdocs/download/sexsend
--- fex-20140917/htdocs/download/sexsend	1970-01-01 01:00:00.000000000 +0100
+++ fex-20150120/htdocs/download/sexsend	2015-01-19 13:59:57.000000000 +0100
@@ -0,0 +1,723 @@
+#!/usr/bin/perl -w
+
+# client for stream exchange of the FEX service
+#
+# Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
+#
+# 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 = 20150120;
+
+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') {
+  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 = 1;
+  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\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 (<F>) {
+      next if /,/;
+      if (/^alias $to\s/i) {
+        chomp;
+        s/\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 ($opt_v and $port == 443 and %SSL) {
+    foreach my $v (keys %SSL) {
+      printf "%s => %s\n",$v,$SSL{$v};
+    }
+  }
+  
+  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,%SSL);
+    }
+  } else {
+    tcpconnect($server,$port);
+  }
+#  if ($port == 443 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 ($port == 443) {
+    # eval "use IO::Socket::SSL qw(debug3)";
+    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',
+    );
+  }
+  
+  if ($SH) {
+    autoflush $SH 1;
+  } else {
+    die "$0: cannot connect $server:$port - $@\n";
+  }
+  
+  print "TCPCONNECT to $server:$port\n" if $opt_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;
+}
+
+
+# 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;
+}
diff -Nru fex-20140917/htdocs/FAQ/admin.faq fex-20150120/htdocs/FAQ/admin.faq
--- fex-20140917/htdocs/FAQ/admin.faq	2014-08-25 09:15:02.000000000 +0200
+++ fex-20150120/htdocs/FAQ/admin.faq	2014-12-19 16:31:01.000000000 +0100
@@ -19,6 +19,9 @@
      /home/fex/bin/fac -u memyselfandi@my.do.main secret-auth-id
    </pre>
    Then log in using the web interface: http://YOURFEXSERVER/
+   
+   ... and join the F*EX mailing list! &#9786;
+   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
@@ -83,6 +86,12 @@
      /home/fex/bin/fac -R framstag@rus.uni-stuttgart.de
    </pre>
 
+Q: How can I change user settings like quota, restrictions or keep time?
+A: Use <code>/home/fex/bin/fac</code>
+
+Q: How can I delete or temporarly disable a user?
+A: Use <code>/home/fex/bin/fac</code>
+
 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:
@@ -125,7 +134,7 @@
 
 Q: I need ACLs for group access, a file browser and integration in my
    native file system.
-A: This is beyond the scope of F*EX, which is designed for file transfer.
+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 <framstag@rus.uni-stuttgart.de>
diff -Nru fex-20140917/htdocs/FAQ/faq.pl fex-20150120/htdocs/FAQ/faq.pl
--- fex-20140917/htdocs/FAQ/faq.pl	2014-04-03 15:32:58.000000000 +0200
+++ fex-20150120/htdocs/FAQ/faq.pl	2014-11-17 18:27:32.000000000 +0100
@@ -13,7 +13,7 @@
 printf "Frequently Asked Questions: %s</h1>\n",ucfirst($faq);
 
 if ($faq ne 'local') {
-  print "<h3>Section: \n";
+  print "<h3>Sections: ";
   foreach $s (@sections,'All') {
     if ($s =~ /$faq/i) {
       print "<b>$s</b>\n";
@@ -41,8 +41,10 @@
     };
     ($q,$a) = split /A:\s*/;
     $q =~ s/[\s\n]+$//;
+    $q =~ s/^\s+//;
     $q =~ s! (/\w[\S]+/[\S]+)! <code>$1</code>!g;
     $a =~ s/[\s\n]+$/\n/;
+    $a =~ s/^\s+//;
     while ($a =~ s/^(\s*)\*/$1<ul>\n$1<li>/m) { 
       while ($a =~ s/(<li>.*\n\s*)\*/$1<li>/g) {}
       $a =~ s:(.*\n)(\s*)(<li>[^\n]+\n):$1$2$3$2</ul>\n:s
@@ -72,8 +74,13 @@
   $t = $s if $faq eq 'all';
 
   for ($n = 0; $n < scalar(@{$Q{$c}}); $n++) {
-    printf "<tr valign=top><th align=left>%s&nbsp;Q%d:<td> <a href=\"#%s%d\">%s</tr>\n",
-           $s,$n+1,$t,$n+1,${Q{$c}[$n]};
+    $q = ${Q{$c}[$n]};
+    $qa = anchor($q);
+    printf '<tr valign=top><th align=left>'.
+           '<a href="#%s%d" style="text-decoration: none">'.
+           '<font color="black">%s&nbsp;Q%d</a>:'.
+           '<td><a href="#%s">%s</a></tr>'."\n",
+           $t,$n+1,$s,$n+1,$qa,$q;
   }
 }
 
@@ -88,10 +95,15 @@
   $t = $s if $faq eq 'all';
 
   for ($n = 0; $n < scalar(@{$Q{$c}}); $n++) {
+    $q = ${Q{$c}[$n]};
+    $qa = anchor($q);
     print "<p>\n";
     print "<table>\n";
-    printf "<tr valign=top><th><a name=\"%s%d\">%s&nbsp;Q%d:</a><td><b>%s</b></tr>\n",
-           $t,$n+1,$s,$n+1,${Q{$c}[$n]};
+    printf "<tr valign=top><th>".
+           "<a name=\"%s%d\">%s&nbsp;Q%d:</a>".
+           "<a name=\"%s\"></a>".
+           "<td><b>%s</b></tr>\n",
+           $t,$n+1,$s,$n+1,$qa,$q;
     printf "<tr valign=top><th>%s&nbsp;A%d:<td>\n%s</tr>\n",
            $s,$n+1,${A{$c}[$n]};
     print "</table>\n";
@@ -119,3 +131,12 @@
   s/\s+$//;
   return "<pre>$_</pre>\n";
 }
+
+sub anchor {
+  local $_ = shift;
+  s/<.+?>//g;
+  s/\(.+?\)//g;
+  s/\W/_/g;
+  s/_+$//;
+  return $_;
+}
diff -Nru fex-20140917/htdocs/FAQ/meta.faq fex-20150120/htdocs/FAQ/meta.faq
--- fex-20140917/htdocs/FAQ/meta.faq	2014-08-25 09:21:25.000000000 +0200
+++ fex-20150120/htdocs/FAQ/meta.faq	2014-12-19 16:31:42.000000000 +0100
@@ -3,7 +3,7 @@
    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 limit of 2 GB or even less.
+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.
@@ -64,9 +64,9 @@
    * 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 (French National Center for Scientific Research) http://bigfiles.cnrs-gif.fr
    * Institut Pasteur http://dl.pasteur.fr
    * Palo Alto Research Center (Xerox PARC) http://parcftp.parc.com
-   * Open Computing Facility University of California at Berkeley http://fex.ocf.berkeley.edu
    * Baden-Württembergs extended LAN http://fex.belwue.de
    * Deutsche Kinemathek Museum f&uuml;r Film und Fernsehen http://upload.deutsche-kinemathek.de
 
diff -Nru fex-20140917/htdocs/FAQ/user.faq fex-20150120/htdocs/FAQ/user.faq
--- fex-20140917/htdocs/FAQ/user.faq	2014-09-03 16:38:17.000000000 +0200
+++ fex-20150120/htdocs/FAQ/user.faq	2014-12-16 12:21:30.000000000 +0100
@@ -18,6 +18,17 @@
 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.rus.uni-stuttgart.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
@@ -27,6 +38,9 @@
    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.
+
 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.
@@ -46,7 +60,7 @@
 
 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/]
+   But there is one exception: axel http://axel.alioth.debian.org/
 
 Q: When I hit [ESC] in firefox the upload is canceled. Why?
 A: This is a built-in feature of firefox: ESC terminates the current operation.
@@ -67,8 +81,15 @@
 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, I need more. How can I set it?
-A: Use fexsend, ask your fexmaster or read the source code :-)
+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: 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).
@@ -100,3 +121,16 @@
 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 <code>SSL3_GET_SERVER_CERTIFICATE:certificate verify failed</code>?
+A: Set the environment variable <code>SSLVERIFY=0</code>
+
+   Rationale: 
+   Your openssl library cannot resolve the SSL certification path. 
+   With <code>SSLVERIFY=0</code> you tell openssl to ignore certification verification.
+   Yes, this is a crude workaround :-}
diff -Nru fex-20140917/htdocs/features.html fex-20150120/htdocs/features.html
--- fex-20140917/htdocs/features.html	2014-08-25 09:36:16.000000000 +0200
+++ fex-20150120/htdocs/features.html	2014-12-17 16:02:39.000000000 +0100
@@ -51,6 +51,7 @@
   <li>optional authentification by LDAP, RADIUS, POP, IMAP, mailman
   <li>server available for UNIX and Windows hosts
   <li>about 10 times faster than apache
+  <li><b>very</b> low memory usage
   <li>(reverse) proxy support
   <li>F*EX is a HTTP web-service and needs no firewall-tunnels
   <li>works with NAT or DHCP clients, too
diff -Nru fex-20140917/htdocs/version fex-20150120/htdocs/version
--- fex-20140917/htdocs/version	2014-09-17 22:07:21.000000000 +0200
+++ fex-20150120/htdocs/version	2015-01-20 10:59:25.000000000 +0100
@@ -1 +1 @@
-fex-20140917
+fex-20150120
diff -Nru fex-20140917/install fex-20150120/install
--- fex-20140917/install	2014-08-27 19:16:27.000000000 +0200
+++ fex-20150120/install	2014-12-17 09:41:40.000000000 +0100
@@ -83,11 +83,14 @@
   $premiss++;
 }
 
-if ( -x '/usr/lib/sendmail') {
-  print "found /usr/lib/sendmail\n";
-} elsif ( -x '/usr/sbin/sendmail') {
-  print "found /usr/sbin/sendmail\n";
-} else {
+foreach (qw'/usr/lib/sendmail /usr/sbin/sendmail') {
+  if (-x) {
+    $sendmail = $_;
+    print "found $sendmail\n";
+    last;
+  }
+}
+unless ($sendmail) {
   print "sendmail NOT found\n";
   $premiss++;  
 }
@@ -171,7 +174,7 @@
 if  (-d "$FEXHOME/spool") {
   warn "checking spool ...\n";
   &convert_spool;
-  system "chown -R fex $spooldir";
+  system "chown -R fex $spooldir/";
 } else {
   $newinstall = $FEXHOME;
   chmod 0700,$FEXHOME;
@@ -365,23 +368,33 @@
   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 features on $hostname' ".
+  print "$FEXHOME/bin/fexwall 'new F*EX features on $hostname' ".
         "< $FEXHOME/doc/newfeatures\n";
 }
 
 if (@local_rdomains and not @local_rhosts) {
-  print "WARNING:\n";
+  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` =~ /exim/ and 
+    `grep trusted_users /etc/exim4/exim4.conf 2>/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 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";
diff -Nru fex-20140917/lib/dop fex-20150120/lib/dop
--- fex-20140917/lib/dop	2014-09-11 00:08:33.000000000 +0200
+++ fex-20150120/lib/dop	2014-12-20 11:41:20.000000000 +0100
@@ -54,8 +54,7 @@
       "Connection: close",
       ""
     );
-    exec($FEXHOME.'/bin/fexsrv') if $ENV{KEEP_ALIVE};
-    exit; 
+    &reexec;
   }
 
   # watchdog documents
@@ -74,6 +73,7 @@
   my ($var,$env,$con);
   my @files;
   my $htmldoc = '';
+  my $htauth;
   my @s;
   my $s = 0;
   my $b = 0;
@@ -86,6 +86,8 @@
   }
 
   security_check($file);
+  $htauth = dirname($file).'/.htauth';
+  require_auth($htauth,$file) if -f $htauth;
 
   if (-f $file) {
     # normal file
@@ -337,6 +339,7 @@
   my @files = ();
   my $uri = $ENV{REQUEST_URI};
   my $allowed;
+  my ($htindex,$htauth);
   local $_;
   
   $uri =~ s:/+$::;
@@ -344,7 +347,11 @@
 
   security_check($dir);
   
-  open my $htindex,"$dir/.htindex" or http_error(403);
+  $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>||'.');
@@ -536,6 +543,49 @@
     
 }
 
+# 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(
+      '<h3><code>$htauth</code> missing</h3>'
+      '</body></html>'
+    ));
+    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 <<perl-code>> inside HTML documents
 sub out {
   $__ .= join('',@_);
diff -Nru fex-20140917/lib/fex.ph fex-20150120/lib/fex.ph
--- fex-20140917/lib/fex.ph	2014-08-16 12:13:02.000000000 +0200
+++ fex-20150120/lib/fex.ph	2015-01-17 11:43:35.000000000 +0100
@@ -87,7 +87,10 @@
 
 ## Allow or disallow 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);
diff -Nru fex-20140917/lib/fex.pp fex-20150120/lib/fex.pp
--- fex-20140917/lib/fex.pp	2014-09-14 01:16:50.000000000 +0200
+++ fex-20150120/lib/fex.pp	2015-01-17 11:41:00.000000000 +0100
@@ -54,6 +54,10 @@
 $mailmode = 'auto';
 $bcc = 'fex';
 $default_locale = '';
+$fop_auth = 0;
+$mail_authid = 'yes';
+$force_https = 0;
+$debug = 0;
 
 $FHS = -f '/etc/fex/fex.ph' and -d '/usr/share/fex/lib';
 # Debian FHS
@@ -74,6 +78,11 @@
 # 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;
+  
 # check for name based virtual host
 $vhost = vhost($ENV{'HTTP_HOST'});
 
@@ -132,6 +141,8 @@
   }
 }
 
+$default_locale ||= 'english';
+
 unless ($durl) {
   my $host = '';
   my $port = 0;
@@ -649,6 +660,7 @@
   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 = quotemeta;
@@ -754,11 +766,16 @@
 
   if (open $file,'<',"$file/filename") {
     $filename = <$file>||'';
-    close $file;
     chomp $filename;
+    close $file;
   }
   
-  return $filename ? $filename : '???';
+  unless ($filename) {
+    $filename = $file;
+    $filename =~ s:.*/::;
+  }
+  
+  return $filename;
 }
 
 
@@ -843,15 +860,14 @@
 sub faillog {
   my $request = shift;
   my $n = 1;
-  my $ra = $ENV{REMOTE_ADDR};
 
-  if ($faillog and $max_fail_handler and open $ra,"+>>$faillog") {
-    flock($ra,LOCK_EX);
-    seek $ra,0,SEEK_SET;
-    $n++ while <$ra>;
-    printf {$ra} "%s %s\n",isodate(time),$request;
-    close $ra;
-    &$max_fail_handler($ra) if $n > $max_fail;
+  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;
   }
 }
 
@@ -915,7 +931,7 @@
   my $sender = shift;
   my $squota = $sender_quota||0;
   my $du = 0;
-  my ($file,@file,$size,%size,$qf,$qs);
+  my ($file,$size,%file,$data);
   local $_;
   
   if (open $qf,'<',"$sender/\@QUOTA") {
@@ -925,15 +941,22 @@
     }
     close $qf;
   }
-  $qs = "*/$sender/*";
-  if (glob $qs and open $qs,untaint("du $qs 2>/dev/null|")) {
-    while (<$qs>) {
-      $du += $1 if /^(\d+)/;
+  
+  foreach $file (glob "*/$sender/*") {
+    $data = "$file/data";
+    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 "$file/upload" and $size = readlink "$file/size") {
+      $du += $size;
     }
-    close $qs;
   }
   
-  return($squota,int($du/1024));
+  return($squota,int($du/1024/1024));
 }
 
 
@@ -942,6 +965,7 @@
   my $recipient = shift;
   my $rquota = $recipient_quota||0;
   my $du = 0;
+  my ($file,$size);
   local $_;
   
   if (open my $qf,'<',"$recipient/\@QUOTA") {
@@ -951,9 +975,12 @@
     }
     close $qf;
   }
-  foreach my $data (glob("$recipient/*/*/data $recipient/*/*/upload")) {
-    unless (-l $data) {
-      $du += -s $data||0;
+  
+  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;
     }
   }
   
@@ -1142,6 +1169,50 @@
   }
 }
 
+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} ||= \&notify;
+  }
+  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
@@ -1348,6 +1419,7 @@
   print {$sendmail} $header,"\n",$body;
   close $sendmail
     or $! and http_die("cannot send notification e-mail (sendmail error $!)\n");
+  return $to;
 }
 
 
diff -Nru fex-20140917/lib/fup.pl fex-20150120/lib/fup.pl
--- fex-20140917/lib/fup.pl	2013-05-09 12:13:09.000000000 +0200
+++ fex-20150120/lib/fup.pl	2014-11-07 13:01:11.000000000 +0100
@@ -10,7 +10,7 @@
 After download or after $keep_default days the server deletes the file.
 F*EX is not an archive!
 <p>
-See also <a href="/FAQ/FAQ.html">questions & answers</a> and
+See also <a href="/FAQ/">questions & answers</a> and
 <a href="http://fex.rus.uni-stuttgart.de/usecases/";>use cases</a>.
 <p><hr><p>
 <address>
@@ -26,12 +26,12 @@
 <em>NOTE: Many web browsers cannot upload files > 2 GB!</em><br>
 If your file is larger you have to use a special <a href="/fuc?show=tools">F*EX client</a>
 or Firefox or Google Chrome which have no size limit.<br>
-You also need a F*EX client for resuming interrupted uploads. Your web browser cannot do this.
+You also need a <a href="/fuc?show=tools">F*EX client</a> for resuming interrupted uploads. Your web browser cannot do this.
 <p>
 If you want to send more than one file, then put them in a zip or tar archive, 
 e.g. with <a href="http://www.7-zip.org/download.html";>7-Zip</a>.
 <p>
-See also the <a href="/FAQ/FAQ.html">FAQ<a> and
+See also the <a href="/FAQ/user.html">FAQ<a> and
 <a href="http://fex.rus.uni-stuttgart.de/usecases/";>use cases</a>.
 <p><hr><p>
 <address>
diff -Nru fex-20140917/locale/czech/htdocs/FAQ.html fex-20150120/locale/czech/htdocs/FAQ.html
--- fex-20140917/locale/czech/htdocs/FAQ.html	2012-09-28 19:03:08.000000000 +0200
+++ fex-20150120/locale/czech/htdocs/FAQ.html	1970-01-01 01:00:00.000000000 +0100
@@ -1,271 +0,0 @@
-<HTML>
-This FAQ has 3 parts:</p>
-<ul>
-  <li><a href="#Meta">Meta</a>
-  <li><a href="#User">User</a>
-  <li><a href="#Admin">Admin</a>
-</ul>
-<p>
-<PRE>
-<a name="meta">
-<a name="Meta">
-Meta questions:
-===============
-
-<a name="1"><a href="#1">Q</a>: Why name "F*EX" and not shortly "FEX"?
-
-A: At publication time there was already an (older) program named "FEX" on
-   freshmeat.net. 
-
-
-<a name="2"><a href="#2">Q</a>: Why not use one of the commercial services like
-   DropLoad, ALLPeers, YouSendIt, etc?
-
-A: They have a limit of 2 GB or even less.
-   Their security and privacy status is unknown.
-   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.
- 
-
-<a name="3"><a href="#3">Q</a>: 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
-   <a href="http://fex.rus.uni-stuttgart.de/Vortrag/tosa.html";>http://fex.rus.uni-stuttgart.de/Vortrag/tosa.html</a>
-
-
-<a name="4"><a href="#4">Q</a>: Where can I get the F*EX sources?
-
-A: <a href="http://fex.rus.uni-stuttgart.de/fex.html";>http://fex.rus.uni-stuttgart.de/fex.html</a>
-
-
-<a name="5"><a href="#5">Q</a>: What do I need to install F*EX?
-
-A: A UNIX host with a DNS entry and smtp for outgoing e-mail.
-   And you must be root on this host.
-
-
-<a name="6"><a href="#6">Q</a>: What is DNS and smtp?
-
-A: Do not install F*EX. It is beyond your horizon.
-
-
-<a name="7"><a href="#7">Q</a>: Who is the author?
-
-A: Ulli Horlacher &lt;<a href="mailto:framstag@rus.uni-stuttgart.de";>framstag@rus.uni-stuttgart.de</a>>
-
-
-<a name="8"><a href="#8">Q</a>: Which licence does F*EX have?
-
-A: Perl Artistic free software, see <a href="http://fex.rus.uni-stuttgart.de/doc/Licence";>http://fex.rus.uni-stuttgart.de/doc/Licence</a>
-
-
-<a name="9"><a href="#9">Q</a>: Is there a F*EX mailing list?
-
-A: <a href="https://listserv.uni-stuttgart.de/mailman/listinfo/fex";>https://listserv.uni-stuttgart.de/mailman/listinfo/fex</a>
-
-
-<a name="10"><a href="#10">Q</a>: Where can I get commercial support for F*EX?   
-
-A: Contact <a href="mailto:fex@nepustil.net";>fex@nepustil.net</a> <a href="http://www.nepustil.net/";>http://www.nepustil.net/</a>
-
-
-<a name="11"><a href="#11">Q</a>: I have more/other questions than in this document!
-
-A: Ask the author &lt;<a href="mailto:framstag@rus.uni-stuttgart.de";>framstag@rus.uni-stuttgart.de</a>>
-
-
-<a name="User">
-User questions:
-===============
-
-<a name="12"><a href="#12">Q</a>: 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.
-
-
-<a name="13"><a href="#13">Q</a>: Can I use a HTTP proxy?
-
-A: Yes.
-
-
-<a name="14"><a href="#14">Q</a>: I have uploaded a HUGE file but misspelled my recipient's address. Now I
-   have got an error bounce e-mail. Must I re-upload the HUGE file?
-
-A: No, it is not necessary. You can redirect the file with 
-   <a href="http://$HTTP_HOST$/rup";>http://$HTTP_HOST$/rup</a>
-
-
-<a name="15"><a href="#15">Q</a>: 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 
-   <a href="http://$HTTP_HOST$/foc";>http://$HTTP_HOST$/foc</a>
-
-
-<a name="16"><a href="#16">Q</a>: I cannot upload files > 2 GB with my web browser!?
-
-A: All web browsers I am aware of have bugs in their HTML-FORM
-   implementation. The limit mostly is 2 GB, sometimes 4 GB. 
-   
-   You have to use a special F*EX client to upload files > 2 GB, see
-   <a href="http://$HTTP_HOST$/tools.html";>http://$HTTP_HOST$/tools.html</a>
-
-
-<a name="17"><a href="#17">Q</a>: 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 eg is missing this HTTP feature, you need an other
-   client like opera, wget or fexget.
-
-
-<a name="18"><a href="#18">Q</a>: 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, schwuppdiwupp or F*IX. 
-   See <a href="http://$HTTP_HOST$/tools.html";>http://$HTTP_HOST$/tools.html</a>
-
-
-<a name="19"><a href="#19">Q</a>: My webbrowser cannot start the java client F*IX, it says:
-   "found no java runtime environment, cannot start F*IX upload applet"
-
-A: A java plugin for your webbrowser is missing. On Debian and Ubuntu you
-   can install it with: "sudo aptitude install sun-java6-plugin"
-
-
-<a name="20"><a href="#20">Q</a>: When I hit [ESC] in firefox the upload is canceled. Why?
-
-A: This is a built-in feature of firefox: ESC terminates the current operation.
-   Simple solution: do not hit ESC in Firefox. 
-   Complex solution: ask the Firefox developers to add keyboard configuration.
-
-
-<a name="21"><a href="#21">Q</a>: Sending as a F*EX user is easy, but how to receive files from others,
-   outside?
-
-A: Register them as your subusers or create a F*EX group 
-   with <a href="http://$HTTP_HOST$/fuc";>http://$HTTP_HOST$/fuc</a>
-   
-
-<a name="22"><a href="#22">Q</a>: 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 requests the file
-   several times at once. Otherwise they would report an error to the user.
-
-A: Your fexmaster has set AUTODELETE=DELAY as default, which means that
-   the autodelete cleanup process is called once a day.
-
-A: Power users (use the source, Luke!) can set a "do not delete after
-   download" flag.
-
-
-<a name="23"><a href="#23">Q</a>: The default keep time is too short for me, I need more. How can I set it?
-
-A: Use fexsend, ask your fexmaster or read the source code :-)
-
-
-<a name="24"><a href="#24">Q</a>: 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.
-
-
-
-<a name="Admin">
-Admin questions:
-================
-
-<a name="25"><a href="#25">Q</a>: I cannot install a web server like fexsrv, because I have no root
-   permissions. Is there a pure-CGI-version of F*EX which runs with an
-   apache web server?
-
-A: F*EX is hard bound to fexsrv for several reasons (performance, file
-   size limit, session concept, etc) and cannot be run as CGI under apache. 
-   But you might have a look at
-   <a href="http://gpl.univ-avignon.fr/filez/";>http://gpl.univ-avignon.fr/filez/</a>
-   <a href="http://freshmeat.net/projects/eventh/";>http://freshmeat.net/projects/eventh/</a>
-   <a href="http://www.schaarwaechter.de/sp/projekte/dateiaustausch.html";>http://www.schaarwaechter.de/sp/projekte/dateiaustausch.html</a> (German only!)
-   which implement a file exchange as pure CGIs, but with a 2 GB file size limit.
-
-
-<a name="26"><a href="#26">Q</a>: 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 whether your xinetd is linked with tcp-wrapper and configure
-   it correctly (hosts.allow).
-   F*EX needs port 80/tcp (HTTP) and optional port 443/tcp (HTTPS).
-
-
-<a name="27"><a href="#27">Q</a>: F*EX is too complicated! I need something more simplified.
-
-A: Try <a href="http://www.home.unix-ag.org/simon/woof.html";>http://www.home.unix-ag.org/simon/woof.html</a>
-
-
-<a name="28"><a href="#28">Q</a>: 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 the author <a href="mailto:framstag@rus.uni-stuttgart.de";>framstag@rus.uni-stuttgart.de</a>
-   
-
-<a name="29"><a href="#29">Q</a>: I want that all of my local users can use F*EX automaticly. How?
-
-A: Let them register theirselves with http://yourfexserver/fur
-   You have to edit 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);
-   (Of course you have to add your real local hosts/networks!)
-
-
-<a name="30"><a href="#30">Q</a>: I need more security! How can I enable HTTPS?
-
-A: Read doc/SSL and also look for "fop_auth" in doc/concept 
-
-
-<a name="31"><a href="#31">Q</a>: I need a corporate identity look. How can I configure F*EX in this way?
-
-A: See variable @H1_extra in fex.ph and you can add HTML code to 
-   htdocs/header.html
-
-A: See htdocs/fup_template.html, modify it to your needs and use it as your
-   start-page.
-
-
-<a name="32"><a href="#32">Q</a>: F*EX is too complicated for my tie users. I need a simplified upload form.
-
-A: See htdocs/fup_template.html
-
-
-<a name="33"><a href="#33">Q</a>: I want the Bcc mails to fex (admin user) to be sent to another address.
-
-A: Use procmail or write OTHERADDRESS to /home/fex/.forward
-
-
-<a name="34"><a href="#34">Q</a>: Can I get a localized version in my native languange?
-
-A: With your help, yes. Please contact the author <a href="mailto:framstag@rus.uni-stuttgart.de";>framstag@rus.uni-stuttgart.de</a>
-
-
-Misc questions:
-===============
-
-<a name="35"><a href="#35">Q</a>: F*EX is great! Can I join the developing team? What needs to be done?
-
-A: Contact the author <a href="mailto:framstag@rus.uni-stuttgart.de";>framstag@rus.uni-stuttgart.de</a>
-   Requested features are:
-   
-     - a F*EX plugin for thunderbird or outlook
-     - more (other) languange support
-</PRE></HTML>
diff -Nru fex-20140917/locale/german/htdocs/FAQ.html fex-20150120/locale/german/htdocs/FAQ.html
--- fex-20140917/locale/german/htdocs/FAQ.html	2012-09-28 19:00:04.000000000 +0200
+++ fex-20150120/locale/german/htdocs/FAQ.html	2014-11-26 17:06:53.000000000 +0100
@@ -1,4 +1,6 @@
 <HTML>
+<h3>Dieses Dokument ist veraltet. Bitte benutzen Sie die
+    <a href="/FAQ/meta.html?locale=english">englische FAQ</a>.</h3>
 <PRE>
 Allgemeine Fragen:
 ==================
diff -Nru fex-20140917/locale/italian/htdocs/FAQ.html fex-20150120/locale/italian/htdocs/FAQ.html
--- fex-20140917/locale/italian/htdocs/FAQ.html	2012-09-28 19:01:55.000000000 +0200
+++ fex-20150120/locale/italian/htdocs/FAQ.html	2014-12-02 12:47:54.000000000 +0100
@@ -1,4 +1,7 @@
 <HTML>
+<h3>Questo documento non &egrave; aggiornato. Si prega di utilizzare il
+    <a href="/FAQ/meta.html?locale=english">inglese FAQ</a>.</h3>
+<PRE>
 <PRE>
 Domande Generiche:
 ==================
diff -Nru fex-20140917/locale/spanish/htdocs/FAQ.html fex-20150120/locale/spanish/htdocs/FAQ.html
--- fex-20140917/locale/spanish/htdocs/FAQ.html	2012-09-28 19:00:54.000000000 +0200
+++ fex-20150120/locale/spanish/htdocs/FAQ.html	2014-11-26 16:52:42.000000000 +0100
@@ -1,4 +1,6 @@
 <HTML>
+<h3>Este documento est&aacute; obsoleto. Por favor, use
+   <a href="/FAQ/meta.html?locale=english">FAQ en ingl&eacute;s</a>.</h3>
 <PRE>
 Meta preguntas:
 ===============
@@ -12,11 +14,11 @@
 P: &iquest;Por qu&eacute; no emplear un servicio comercial
    DropLoad, ALLPeers, YouSendIt, etc?
    
-R: Tienen un l&iacute;mite de 2GB e incluso menos.
+R: Tienen un l&iacute;mite de 2GB incluso &oacute; menos.
    Su estado de privacidad y seguridad es desconocido.
    No est&aacute;n basados en software abierto.
    No existe ning&uacute;n cliente UNIX (CLI) para ellos.
-   Necesita java, active-X, flash u otros plugins endemeniados.
+   Necesitan java, active-X, flash u otros plugins endemeniados.
    Se desconoce cuanto durar&aacute;n - DropLoad y ALLPeers
    ha finalizado sus asuntos.
 
diff -Nru fex-20140917/locale/translations fex-20150120/locale/translations
--- fex-20140917/locale/translations	2014-09-15 16:02:51.000000000 +0200
+++ fex-20150120/locale/translations	2015-01-20 10:58:26.000000000 +0100
@@ -179,8 +179,8 @@
 si vous n'avez pas déjà un compte F*EX
 
 You may also use <a href="/fup?from=anonymous&to=$a">anonymous upload</a>
-Sie k&ouml;nnen auch <a href="/fup?from=anonymous&to=$a">anonymen Upload</a> verwenden.
-Du kosch au <a href="/fup?from=anonymous&to=$a">anonymes Nufflada</a> nemma.
+Sie k&ouml;nnen auch <a href="/fup?from=anonymous&to=$a">anonymen Upload</a> verwenden
+Du kosch au <a href="/fup?from=anonymous&to=$a">anonymes Nufflada</a> nemma
 Se tambien puede usar <a href="/fup?from=anonymous&to=$a">anonymous upload</a>
 Tamén pode usar <a href="/fup?from=anonymous&to=$a">o envío anónimo</a>
 Potresti anhe utilizzare <a href="/fup?from=anonymous&to=$a">anonymous upload</a>
@@ -188,13 +188,13 @@
 Vous pouvez aussi utiliser <a href="/fup?from=anonymous&to=$a">l'upload anonyme</a>
 
 You may also use <a href="/sup.html">simple upload</a>
-Sie k&ouml;nnen auch <a href="/sup.html">vereinfachten Upload</a> verwenden.
-Du kosch au <a href="/sup.html">oifachs Nufflada</a> nemma.
-You may also use <a href="/sup.html">simple upload</a>
-You may also use <a href="/sup.html">simple upload</a>
-You may also use <a href="/sup.html">simple upload</a>
-You may also use <a href="/sup.html">simple upload</a>
+Sie k&ouml;nnen auch <a href="/sup.html">vereinfachten Upload</a> verwenden
+Du kosch au <a href="/sup.html">oifachs Nufflada</a> nemma
+Puede tambien usar <a href="/sup.html">subir simplificado</a>
 You may also use <a href="/sup.html">simple upload</a>
+Potresti anche usare <a href="/sup.html">caricamento semplice</a>
+Můşete také pouşít <a href="/sup.html">jednoduché nahrávání</a>.
+Vous pouvez également utiliser <a href="/sup.html">l'upload simple</a>
 
 <code>$file</code> already exists for
 <code>$file</code> existiert bereits f&uuml;r
@@ -295,6 +295,24 @@
 Neodesílat <a href="/fuc?reminder=no&akey=$akey">şádná připomenutí</a> (současné nastavení: <em>odeslat upozornění</em>)
 Ne pas recevoir <a href="/fuc?reminder=no&akey=$akey">les rappels</a> par e-mail (configuration actuelle: <em>rappels envoyés</em>)
 
+Save</a> files after download (current setting: <em>display</em>
+Speichere</a> Dateien nach dem download (aktuelle Einstellung: <em>anzeigen</em>
+Schpeicher</a> die Dateia nochm Ronderlada (aktuelle Eischtellong: <em>ozeiga</em>
+Save</a> downloads (current setting: <em>display</em>
+Save</a> downloads (current setting: <em>display</em>
+Save</a> downloads (current setting: <em>display</em>
+Save</a> downloads (current setting: <em>display</em>
+Save</a> downloads (current setting: <em>display</em>
+
+Display</a> files when downloading with web browser (current setting: <em>save</em>
+Anzeige</a> von Dateien direkt beim download (aktuelle Einstellung: <em>abspeichern</em>
+Ozeiga</a> von Dateia beim Ronderlada (aktuelle Eischtellong: <em>abschpeichra</em>
+Display</a> downloads (current setting: <em>save</em>
+Display</a> downloads (current setting: <em>save</em>
+Display</a> downloads (current setting: <em>save</em>
+Display</a> downloads (current setting: <em>save</em>
+Display</a> downloads (current setting: <em>save</em>
+
 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
@@ -331,6 +349,24 @@
 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
+Downloads 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&ouml;glich)
+Downloads 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&uuml;ckgesetzt
 Dr E-Mail Oh&auml;ngsl isch wieder orginal
@@ -1008,7 +1044,7 @@
 
 delete file after download
 Datei nach dem Download l&ouml;schen
-Datie nochm Ronderlada l&ouml;scha
+Datei nochm Ronderlada l&ouml;scha
 borrar el fichero tras su descarga
 borrar o ficheiro trala s&uacute;a descarga
 cancella il file dopo il download
@@ -1036,11 +1072,11 @@
 delete file $autodelete days after download
 L&ouml;sche Datei $autodelete Tage nach dem Download
 L&ouml;sch Datei $autodelete Dag nochm ronderlada
+borrar archivo $autodelete dias despues del descargar
 delete file $autodelete days after download
-delete file $autodelete days after download
-delete file $autodelete days after download
-delete file $autodelete days after download
-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
@@ -1411,6 +1447,15 @@
 a <
 et <
 
+You are a restricted user and may only fex to these recipients:
+Sie sind ein eingeschr&auml;nkter Benutzer und k&ouml;nnen nur an diese Empf&auml;nger fexen:
+Du bisch a eigeschr&auml;nktr Benutzr ond kosch bloss an die Empf&auml;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
@@ -1780,6 +1825,15 @@
 velikost souboru
 taille du fichier
 
+No file selected
+Keine Datei ausgew&auml;hlt
+Koi Datei ausgw&auml;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?!
@@ -2007,21 +2061,21 @@
 
 your e-mail address
 Ihre E-Mail Adresse
-dei E-Mail Adresss
+dei E-Mail Adress
 s&uacute; direcci&oacute;n de correo electr&oacute;nico
 o s&eacute;u enderezo de correo electr&oacute;nico
 il tuo indirizzo e-mail
 vaše e-mailová adresa
 votre adresse e-mail
 
-Subject: F*EX user registration
-Subject: F*EX-Benutzer Registrierung
-Subject: F*EX-Benutzrregischdrierong
-Sujeto: Registro del usuario de F*EX
-Suxeito: Rexistro do usuario de F*EX
-Oggetto: registrazione utente F*EX
-Předmět: Registrace F*EX uşivatele
-Sujet: Enregistrement F*EX
+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
@@ -2032,14 +2086,14 @@
 $user byl automaticky zaregistrován s
 l'utilisateur $user a été automatiquement enregistré avec
 
-Subject: F*EX user registration request
-Subject: F*EX-Benutzer Registrierungs-Anfrage
-Subject: F*EX-Benutzrregischdrierongsofrog
-Sujeto: Petici&oacute;n de registro de usuario F*EX
-Suxeito: Petici&oacute;n de rexistro de usuario F*EX
-Oggetto: richiesta registrazione utente F*EX
-Předmět: Poşadavek na zaregistrování F*EX uşivatele
-Sujet: Demande d'enregistrement d'utilisateur F*EX
+F*EX user registration request
+F*EX-Benutzer Registrierungs-Anfrage
+F*EX-Benutzrregischdrierongsofrog
+Petici&oacute;n de registro de usuario F*EX
+Petici&oacute;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:
@@ -2089,11 +2143,11 @@
 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
-is not an email address
-is not an email address
-is not an email address
-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
@@ -2365,6 +2419,15 @@
 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&uacute;n correo electr&oacute;nico de notificaci&oacute;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 <b>BYTES</b>?! You are kidding
 Moment... $ndata <b>BYTES</b>?! Das ist wohl ein Witz
 Moment amole $ndata <b>BYTES</b>?! Wilsch me verarsche
@@ -2410,23 +2473,23 @@
 URL pro staşení okopírovat a vloşit
 URL de téléchargement pour copier/coller
 
-Link is valid for $keep days
-Dieser Link ist f&uuml;r $keep Tage g&uuml;ltig
-Sell Link isch fir $keep Dag giltig
-El enlace es válido durante $keep días
-A ligazón é válida durante $keep días
-Il link Ú valido per $keep giorni
-Odkaz je platnÜ $keep dny(ů)
-Le lien restera valide $keep jours
-
-old $file for $to overwritten
-vorhandenes $file f&uuml;r $to &uuml;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.
+Link is valid for $keep{$to} days
+Dieser Link ist f&uuml;r $keep{$to} Tage g&uuml;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 <code>$file</code> for $to overwritten
+vorhandenes <code>$file</code> f&uuml;r $to &uuml;berschrieben
+alts <code>$file</code> fir $to iberschrieba
+El anterior <code>$file</code> para $to se ha sobreescrito
+Sobrescribiuse o anterior <code>$file</code> para $to
+vecchio file <code>$file</code> per $to sovrascritto
+původní soubor <code>$file</code> pro $to byl nahrazen
+<code>$file</code> pour $to reécrit.
 
 $to notified
 $to benachrichtigt
@@ -2437,6 +2500,24 @@
 $to byl informován
 $to prévenu
 
+<code>$file</code> removed because you are a restricted user
+<code>$file</code> wurde gel&ouml;scht weil Sie ein eingeschr&auml;nkter Benutzer sind 
+<code>$file</code> isch wieder gl&ouml;scht worda weil du a bschr&auml;nkter Benutzer bisch
+<code>$file</code> se ha borrado porque usted es un usuario restringido
+<code>$file</code> removed because you are a restricted user
+<code>$file</code> rimosso perchÚ sei un utente limitato
+<code>$file</code> odstraněn, protoşe jste uşivatel s omezením
+<code>$file</code> supprimé car vous êtes un utilisateur restreint
+
+and recipient $to cannot receive e-mail
+und Empf&auml;nger $to keine E-Mail empfangen kann
+ond Empf&auml;ngr $to ko koi E-Mail empfanga
+y el destinatario $to no puede recibir correos electr&oacute;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
@@ -2692,80 +2773,80 @@
 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
-ERROR: no upload received
-ERROR: no upload received
-ERROR: no upload received
-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&ouml;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
-You cannot send to more than one group
-You cannot send to more than one group
-You cannot send to more than one group
-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
-file transfer aborted
-file transfer aborted
-file transfer aborted
-file transfer aborted
+trasferimento file interrotto
+přenos souboru přerušen
+transfert de fichier abandonné
 
 <code>$from</code> is not allowed to upload from IP $ra
 <code>$from</code> darf nicht von IP-Adresse $ra hochladen
 <code>$from</code> darf ned von IP-Adress $ra hochlada
+<code>$from</code> no está permitido a subir de esta dirección IP $ra
 <code>$from</code> is not allowed to upload from IP $ra
-<code>$from</code> is not allowed to upload from IP $ra
-<code>$from</code> is not allowed to upload from IP $ra
-<code>$from</code> is not allowed to upload from IP $ra
-<code>$from</code> is not allowed to upload from IP $ra
+<code>$from</code> non Ú consentito caricarlo da IP $ra
+<code>$from</code> z IP adresy $ra není dovoleno nahrávat soubory
+<code>$from</code> n'est pas autorisé à uploader vers l'IP $ra
 
 Group <code>$to</code> does not exist
 Gruppe <code>$to</code> existiert nicht
 Grupp <code>$to</code> gibts net
+Grupo <code>$to</code> no existe
 Group <code>$to</code> does not exist
-Group <code>$to</code> does not exist
-Group <code>$to</code> does not exist
-Group <code>$to</code> does not exist
-Group <code>$to</code> does not exist
+Il gruppo <code>$to</code> non esiste
+Skupina <code>$to</code> neexistuje
+Le groupe <code>$to</code> n'existe pas
 
 server runs in NOMAIL mode - groups ($to) are not allowed
 Server l&auml;uft im NOMAIL Modus - Gruppen ($to) sind nicht erlaubt
 Server l&auml;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 runs in NOMAIL mode - groups ($to) are not allowed
-server runs in NOMAIL mode - groups ($to) are not allowed
-server runs in NOMAIL mode - groups ($to) are not allowed
-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 not found
-File not found
-File not found
-File not found
+File non trovato
+Soubor nenalezen
+Fichier introuvable
 
 <code>$to</code> is not a valid recipient
 <code>$to</code> ist kein g&uuml;ltiger Empf&auml;nger
 <code>$to</code> isch koi g&uuml;ltigr Empf&auml;ngr
+<code>$to</code> no es un destinario válido
 <code>$to</code> is not a valid recipient
-<code>$to</code> is not a valid recipient
-<code>$to</code> is not a valid recipient
-<code>$to</code> is not a valid recipient
-<code>$to</code> is not a valid recipient
+<code>$to</code> non Ú un destinatario valido
+<code>$to</code> není platnÜ příjemce
+<code>$to</code> 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
-File $file already exists in your outgoing spool
-File $file already exists in your outgoing spool
-File $file already exists in your outgoing spool
-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
diff -Nru fex-20140917/upgrade fex-20150120/upgrade
--- fex-20140917/upgrade	2014-08-27 19:16:27.000000000 +0200
+++ fex-20150120/upgrade	2014-12-17 09:41:40.000000000 +0100
@@ -83,11 +83,14 @@
   $premiss++;
 }
 
-if ( -x '/usr/lib/sendmail') {
-  print "found /usr/lib/sendmail\n";
-} elsif ( -x '/usr/sbin/sendmail') {
-  print "found /usr/sbin/sendmail\n";
-} else {
+foreach (qw'/usr/lib/sendmail /usr/sbin/sendmail') {
+  if (-x) {
+    $sendmail = $_;
+    print "found $sendmail\n";
+    last;
+  }
+}
+unless ($sendmail) {
   print "sendmail NOT found\n";
   $premiss++;  
 }
@@ -171,7 +174,7 @@
 if  (-d "$FEXHOME/spool") {
   warn "checking spool ...\n";
   &convert_spool;
-  system "chown -R fex $spooldir";
+  system "chown -R fex $spooldir/";
 } else {
   $newinstall = $FEXHOME;
   chmod 0700,$FEXHOME;
@@ -365,23 +368,33 @@
   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 features on $hostname' ".
+  print "$FEXHOME/bin/fexwall 'new F*EX features on $hostname' ".
         "< $FEXHOME/doc/newfeatures\n";
 }
 
 if (@local_rdomains and not @local_rhosts) {
-  print "WARNING:\n";
+  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` =~ /exim/ and 
+    `grep trusted_users /etc/exim4/exim4.conf 2>/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 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";

Attachment: signature.asc
Description: Digital signature


--- End Message ---
--- Begin Message ---
Hi,

On Sun, Feb 08, 2015 at 10:07:49PM +0100, Ivo De Decker wrote:
> >  50 files changed, 3001 insertions(+), 1169 deletions(-)
> 
> This change is obviously not appropriate at this stage in the freeze. If you
> can come up with a targeted fix for this issue in the next few days, we might
> be able to allow that. Otherwise, we will have to remove fex from jessie
> (probably before the auto-removal deadline).

Added a removal hint for fex.

Cheers,

Ivo

--- End Message ---

Reply to: