3 # FEX CGI for user control
4 # (subuser, groups, address book, one time upload key, auth-ID, etc)
6 # Author: Ulli Horlacher <framstag@rus.uni-stuttgart.de>
10 use CGI::Carp qw(fatalsToBrowser);
12 use Digest::MD5 qw(md5_hex);
14 $CGI::LIST_CONTEXT_WARN = 0;
15 $CGI::LIST_CONTEXT_WARN = 0;
18 ($FEXLIB) = $ENV{FEXLIB} =~ /(.+)/;
19 die "$0: no $FEXLIB\n" unless -d $FEXLIB;
23 our ($mdomain,$admin,$hostname,$sendmail,$akeydir,$skeydir,$docdir,$durl,$bcc);
24 our ($nomail,$faillog);
27 # load common code, local config : $HOME/lib/fex.ph
28 require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n";
32 my $error = 'F*EX user config ERROR';
33 my $head = "$ENV{SERVER_NAME} F*EX user config";
38 chdir $spooldir or die "$spooldir - $!\n";
40 my $user = my $id = my $nid = my $ssid = my $comment = '';
41 my $notification = my $reminder = my $disclaimer = '';
42 my $encryption = my $pubkey = my $mime = '';
44 $akey = ''; # delete akey cookie
46 my $qs = $ENV{QUERY_STRING};
48 if ($qs =~ /akey=(\w+)/i) { $akey = $1 }
49 if ($qs =~ /ab=load/) { $ab = 'load' }
52 # look for CGI POST parameters
53 foreach my $v (param) {
55 debuglog("Param: $v=\"$vv\"");
56 if ($v =~ /^akey$/i) {
57 $akey = $1 if $vv =~ /^(\w+)$/;
61 $v =~ /^user$/i ? $user = normalize_email($vv):
62 $v =~ /^subuser$/i ? $subuser = normalize_email($vv):
63 $v =~ /^otuser$/i ? $otuser = normalize_email($vv):
64 $v =~ /^notify$/i ? $notify = normalize_email($vv):
65 $v =~ /^notification$/i ? $notification = checkchars('parameter',$vv):
66 $v =~ /^disclaimer$/i ? $disclaimer = $vv:
67 $v =~ /^encryption$/i ? $encryption = checkchars('parameter',$vv):
68 $v =~ /^pubkey$/i ? $pubkey = $vv:
69 $v =~ /^reminder$/i ? $reminder = checkchars('parameter',$vv):
70 $v =~ /^mime$/i ? $mime = checkchars('parameter',$vv):
71 $v =~ /^comment$/i ? $comment = decode_utf8(normalize($vv)):
72 $v =~ /^id$/i ? $id = checkchars('auth-ID',$vv):
73 $v =~ /^nid$/i ? $nid = checkchars('auth-ID',$vv):
74 $v =~ /^ssid$/i ? $ssid = $vv:
75 $v =~ /^group$/i ? $group = checkchars('group',$vv):
76 $v =~ /^ab$/i ? $ab = $vv:
77 $v =~ /^gm$/i ? $gm = $vv:
78 $v =~ /^show$/i ? $tools = checkchars('parameter',$vv):
82 $group = lc $group if $group and $group ne 'NEW';
83 $group = '' if $nomail;
84 $user .= '@'.$mdomain if $mdomain and $user !~ /@/;
86 $nomail = $comment if $comment =~ /NOMAIL|!#!/;
90 # sid is not set with web browser
91 my $idf = "$akeydir/$akey/@";
93 if (open $akey,'<',$idf and $id = getline($akey)) {
97 or http_die("internal server error: no $akey symlink $1");
99 $user = untaint($user);
100 if ($akey ne md5_hex("$user:$id")) {
106 &check_status($user) if $user;
108 if ($user and $akey and $qs and $qs =~ /info=(.+?)&skey=(.+)/) {
111 notify_subuser($user,$subuser,"$fup?skey=$skey",$comment);
112 http_header("200 OK");
113 print html_header($head);
115 'An information e-mail has been sent to your subuser $subuser'
116 '<p><a href="javascript:history.back()">Go back</a>'
124 if (-e "$user/\@CAPTIVE") { html_error($error,"captive user") }
125 unless (open $idf,'<',"$user/@") {
126 faillog("user $from, id $id");
127 html_error($error,"wrong user or auth-ID");
129 $rid = getline($idf);
133 $akey = untaint(md5_hex("$user:$id"));
134 unlink "$akeydir/$akey";
135 symlink "../$user","$akeydir/$akey";
138 faillog("user $from, id $id");
139 html_error($error,"wrong user or auth-ID");
142 my $login = -x "$FEXHOME/login" ? 'login' : 'fup';
144 "HTTP/1.1 302 Found",
145 "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/$login",
153 # empty POST? ==> back to foc
154 if ($ENV{REQUEST_METHOD} eq 'POST' and not
155 ($subuser or $notify or $nid or $ssid or $group or $ab or $gm or $tools
156 or $disclaimer or $encryption or $pubkey))
159 "HTTP/1.1 302 Found",
160 "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/foc",
168 unlink $faillog if $faillog;
170 http_header("200 OK");
171 print html_header($head);
172 # foreach $v (keys %ENV) { print $v,' = "',$ENV{$v},"\"<br>\n" };
174 if ($gm and not $group) {
176 '<h2>ERROR: no group name specified</h2>'
184 'To use one of the following F*EX clients you must configure them after'
188 ' <tr><th align=left>F*EX server:<td><code>$ENV{PROTO}://$ENV{HTTP_HOST}</code></tr>'
189 ' <tr><th align=left>Proxy:<td>(your web proxy address, may be empty)</tr>'
190 ' <tr><th align=left>User:<td><code>$user</code></tr>'
191 ' <tr><th align=left>Auth-ID:<td><code>$id</code></tr>'
194 if (open $tools,"$docdir/tools.html") {
196 while (/\$([\w_]+)\$/) {
198 my $env = $ENV{$var} || '';
211 # create one time upload key
212 if ($subuser and $otuser) {
214 if ($otuser !~ /^[^@]+@[\w.-]+[a-z]$/) {
216 '<code>$otuser</code> is not a valid e-mail address'
217 '<p><a href="javascript:history.back()">Go back</a>'
222 my $okey = randstring(8);
223 my $okeyd = "$user/\@OKEY";
225 symlink $otuser,"$okeyd/$okey"
226 or http_die("cannot create OKEY $okeyd/$okey : $!\n");
227 my $url = "$fup?to=$user&okey=$okey";
229 'A one time upload URL for <code>$otuser</code> has been created:'
234 ¬ify_otuser($user,$otuser,$url,$comment);
237 'and an information e-mail has been sent to this address.'
242 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
248 # direct single subuser entry
249 if ($subuser and not $otuser) {
250 if (-f "$subuser/@") {
252 '<code>$subuser</code> is already a registered F*EX full user'
253 '<p><a href="javascript:history.back()">Go back</a>'
258 if ($subuser !~ /^[^@]+@[\w.-]+[a-z]$/) {
260 '<code>$subuser</code> is not a valid e-mail address'
261 '<p><a href="javascript:history.back()">Go back</a>'
267 if (open $idf,'<',"$user/\@SUBUSER") {
270 if (/^\Q$subuser:/) {
271 $skey = md5_hex("$user:$_");
278 my $url = "$fup?skey=$skey";
281 '$subuser is already your subuser and has access URL:'
287 '<a href=\"/fuc?akey=$akey&info=$subuser&skey=$skey\">$subuser</a>'
288 'is already your subuser and has access URL:'
292 "Click on the subuser's e-mail address link to send him an"
293 "information e-mail by the F*EX server.<p>"
297 my $sid = randstring(8);
298 my $skey = mkskey($user,$subuser,$sid);
299 $url = "$fup?skey=$skey";
300 open $idf,'>>',"$user/\@SUBUSER" or die "$user/\@SUBUSER - $!\n";
301 print {$idf} "$subuser:$sid\n";
304 'Your subuser upload URL is:'
309 ¬ify_subuser($user,$subuser,$url,$comment);
312 'An information e-mail has been sent to $subuser'
316 print "</body></html>\n";
321 if ($user and $akey and defined $ab) {
324 if (open $ab,'<',"$user/\@ADDRESS_BOOK") {
329 $ab = html_quote($_);
331 my $rows = ($ab =~ tr/\n//) + 5;
333 '<h2>Edit address book</h2>'
335 ' <tr align="left"><th>Entry:<th>alias<th>e-mail address<th># optional comment</tr>'
336 ' <tr align="left"><td>Example:<td><code>Framstag</code><td><code>framstag\@rus.uni-stuttgart.de</code><td><code># Ulli Horlacher</code></tr>'
338 '<form action="$ENV{SCRIPT_NAME}"'
340 ' accept-charset="UTF-8"'
341 ' enctype="multipart/form-data">'
342 ' <input type="hidden" name="akey" value="$akey">'
343 ' <textarea name="ab" cols="160" rows="$rows">$ab</textarea><br>'
344 ' <input type="submit" value="submit">'
347 'You may use these alias names as F*EX recipient addresses on '
348 '<a href="/fup?akey=$akey">fup</a>'
350 'Alternatively you can fex a file ADDRESS_BOOK to yourself '
351 '($user) containing your alias definitions.'
353 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
360 foreach (split(/\n/,$ab)) {
363 if (s/\s*(#.*)//) { $comment = $1 }
364 else { $comment = '' }
367 push @options,$1 if s/(autodelete=\w+)//i;
368 push @options,$1 if s/(keep=\d+)//i;
370 if (s/([\S]+)\s+(\S+)//) {
373 $options = join(',',@options);
374 push @abt,"<tr><td>$alias<td>$address<td>$options<td>$comment</tr>\n";
381 print "<h2>ERROR: bad aliases:</h2>\n<ul>";
382 foreach my $ba (@badalias) { print "<li>$ba" }
386 'Not in format: <code>alias e-mail-address</code>'
388 '<a href="javascript:history.back()">Go back</a>'
394 open my $AB,'>',"$user/\@ADDRESS_BOOK"
395 or http_die("cannot open $user/\@ADDRESS_BOOK - $!\n");
399 '<h2><a href ="/fuc?AB=load&akey=$akey">address book</a></h2>'
401 '<tr><th>alias<th>e-mail address<th>options<th>comment</tr>'
405 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
407 '<a href="/fup?akey=$akey">back to fup (F*EX upload)</a>'
414 if ($user and $notification eq 'detailed') {
415 unlink "$user/\@NOTIFICATION";
417 '<h3>Notification e-mails now come in detailed format.<h3>'
419 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
425 if ($user and $mime eq 'yes') {
426 open $mime,'>',"$user/\@MIME" or http_die("cannot write $user/\@MIME - $!\n");
429 '<h3>Downloads will now be displayed (if possible).<h3>'
431 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
437 if ($user and $mime eq 'no') {
438 unlink "$user/\@MIME";
440 '<h3>Downloads will now be saved.<h3>'
442 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
448 if ($user and $notification eq 'short') {
449 unlink "$user/\@NOTIFICATION";
450 symlink "short","$user/\@NOTIFICATION";
452 '<h3>Notification e-mails now come in short format.<h3>'
454 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
460 if ($user and $disclaimer) {
461 my $df = "$user/\@DISCLAIMER";
462 if ($disclaimer =~ /^[\s\"]*DEFAULT[\s\"]*$/i) {
465 '<h3>E-mail disclaimer reset to default.</h3>'
467 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
470 } elsif ($disclaimer eq 'CHANGE') {
471 $disclaimer = slurp($df) || '';
472 $disclaimer =~ s/&/&/g;
473 $disclaimer =~ s/</</g;
475 '<form action="$ENV{SCRIPT_NAME}"'
477 ' accept-charset="UTF-8"'
478 ' enctype="multipart/form-data">'
479 ' <input type="hidden" name="akey" value="$akey">'
481 ' Disclaimer to be sent with download notification e-mail:<br>'
482 ' <textarea name="disclaimer" cols="80" rows="10">$disclaimer</textarea><br>'
483 ' <input type="submit" value="save">'
484 ' or <a href="$ENV{SCRIPT_NAME}?akey=$akey&disclaimer=DEFAULT">'
485 ' reset the disclaimer to default</a>.'
491 $disclaimer =~ s/^\s+//;
492 $disclaimer =~ s/\s+$/\n/;
493 open $df,'>',$df or http_die("cannot write $df - $!\n");
494 print {$df} $disclaimer;
496 $disclaimer =~ s/&/&/g;
497 $disclaimer =~ s/</</g;
499 '<h2>E-mail disclaimer changed to:</h2>'
504 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
512 if ($user and $pubkey) {
513 my $gf = "$user/\@GPG";
518 open $gf,">$gf.pk" or http_die("cannot write $gf - $!\n");
519 print {$gf} <$pubkey>;
522 system "gpg --batch --no-default-keyring --keyring $gf --import".
523 "< $gf.pk >/dev/null 2>&1";
524 if (`gpg --batch <$gf 2>/dev/null` =~ /^pub\s.*<\Q$user\E>/sm) {
525 $pk = `gpg --batch <$gf 2>&1`;
529 '<h2>E-mails to you will be encrypted with the PGP/GPG key:</h2>'
534 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
537 unlink "$gf.pk","$gf~";
539 $pk = `gpg --batch <$gf.pk 2>&1`;
543 '<h2>Your uploaded file does not contain a PGP/GPG public key for'
544 ' <code>$user</code></h2>'
549 '<a href="javascript:history.back()">back</a>'
556 if ($user and $encryption) {
557 my $gf = "$user/\@GPG";
559 unless(-s "$ENV{HOME}/.gnupg/pubring.gpg") {
560 html_error($error,"no GPG support activated");
563 if ($encryption eq 'DELETE') {
566 '<h3>PGP/GPG key deleted.</h3>'
567 '<h3>E-mails to you will be sent not encrypted.</h3>'
569 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
572 } elsif ($encryption eq 'CHANGE') {
574 '<form action="$ENV{SCRIPT_NAME}"'
576 ' accept-charset="UTF-8"'
577 ' enctype="multipart/form-data">'
578 ' <input type="hidden" name="akey" value="$akey">'
579 ' Select your PGP/GPG public key file(*):<br>'
580 ' <input type="file" name="pubkey" size="80">'
582 ' and <input type="submit" value="upload">'
589 'or <a href="$ENV{SCRIPT_NAME}?akey=$akey&encryption=DELETE">'
590 'delete your already uploaded public key</a>:'
595 '(*) To extract and verify your GPG public key use:'
597 'gpg -a --export $user > pubkey.gpg'
602 print "</body></html>\n";
609 if ($user and $reminder eq 'yes') {
610 unlink "$user/\@REMINDER";
612 '<h3>You will now get reminder notification e-mails.<h3>'
614 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
620 if ($user and $reminder eq 'no') {
621 unlink "$user/\@REMINDER";
622 symlink "no","$user/\@REMINDER";
624 '<h3>You will now get no reminder notification e-mails.<h3>'
626 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
636 $nid = randstring(6) if $nid eq '?';
638 open $idf,'>',"$user/@" or die "$user/@ - $!\n";
639 print {$idf} $nid,"\n";
641 $akey = untaint(md5_hex("$user:$nid"));
642 unlink "$akeydir/$akey";
643 symlink "../$user","$akeydir/$akey";
646 '<h3>new auth-ID "<code>$nid</code>" for $user saved</h3>'
647 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
653 # empty subuser list POST
654 if (defined(param('ssid')) and $ssid =~ /^\s*$/) {
655 unlink "$user/\@SUBUSER";
657 '<h2>All subusers deleted</h2>\n<ul>'
658 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
666 my ($subuser,$subid,$skey);
669 if (open $idf,'<',"$user/\@SUBUSER") {
672 if (/(.+\@.+):(.+)/) {
673 ($subuser,$subid) = ($1,$2);
674 $skey = md5_hex("$user:$subuser:$subid");
675 unlink "$skeydir/$skey";
676 unlink "$subuser/\@MAINUSER/$user";
682 $ssid = strip($ssid);
684 # collect (new) subusers
685 foreach (split("\n",$ssid)) {
688 if (/(.+\@[\w.-]+)/) {
690 push @badaddress,$subuser unless checkaddress($subuser);
695 print "<h2>ERROR: bad addresses:</h2>\n<ul>";
696 foreach my $ba (@badaddress) { print "<li>$ba" }
699 '<a href="javascript:history.back()">Go back</a>'
705 if ($ssid =~ /\S\@\w/) {
706 open $idf,'>',"$user/\@SUBUSER" or die "$user/\@SUBUSER - $!\n";
707 print "Your subusers upload URLs are:<p><code>\n";
709 foreach (split("\n",$ssid)) {
712 if (/(\S+\@[\w.-]+)/) {
714 if (/:(.+)/) { $subid = $1 }
715 else { $subid = randstring(8) }
716 print {$idf} "$subuser:$subid\n";
717 $skey = mkskey($user,$subuser,$subid);
718 print " <tr><td><a href=\"/fuc?akey=$akey&info=$subuser&skey=$skey\">$subuser</a> :",
719 "<td>$fup?skey=$skey</tr>\n";
723 "</table>\n</code><p>"
724 "You have to give these URLs to your subusers for fexing files to you."
726 "Or click on the subuser's e-mail address link to send him an"
727 "information e-mail by the F*EX server.<p>"
730 print "<a href=\"/foc?akey=$akey\">back to F*EX operation control</a>\n";
731 print "</body></html>\n";
736 if (open my $subuser,'<',"$user/\@SUBUSER") {
738 $ssid = <$subuser> || '';
742 # display HTML form and request user data
744 '<form action="$ENV{SCRIPT_NAME}"'
746 ' accept-charset="UTF-8"'
747 ' enctype="multipart/form-data">'
748 ' <input type="hidden" name="akey" value="$akey">'
752 # ' <input type="hidden" name="user" value="$user">'
753 # ' <input type="hidden" name="id" value="$id">'
754 # ' Your F*EX account: <b>$user:$id</b><p>'
755 # ' New auth-ID: <input type="text" name="nid" value="$id">'
756 # ' (Remember your auth-ID when you change it!)'
759 if (-s "$user/\@ALLOWED_RECIPIENTS") {
762 ' <input type="submit" value="submit">'
770 $ssid = html_quote(strip($ssid));
775 ' Allow special senders (= subusers) to fex files to you:<br>'
776 ' <textarea name="ssid" cols="60" rows="10">$ssid</textarea><br>'
777 ' <input type="submit" value="save and show upload URLs">'
781 ' <tr align="left"><td>This list has entries in format:<td><e-mail address>:<encryption-ID><td></tr>'
782 ' <tr align="left"><td>Example:<td><code>framstag\@rus.uni-stuttgart.de:schwuppdiwupp</code><td></tr>'
785 'These special senders may fex files <em>only</em> to you!<br>'
786 'It is not necessary to add regular fex users to your list,'
787 'because they already can fex.'
789 'The encryption-ID is necessary to generate a unique upload URL for this subuser.<br>'
790 'If you omit the encryption-ID a random one will be used.'
796 '<h3 title="A F*EX group is similar to a mailing list, but for files">'
797 'Edit your F*EX groups:</h3>'
801 foreach $group (glob "$user/\@GROUP/*") {
802 if (-f $group and not -l $group and $group !~ /~$/) {
804 print " <li><a href=\"$ENV{SCRIPT_NAME}?akey=$akey&group=$group\">\@$group</a>\n";
809 ' <li><a href="$ENV{SCRIPT_NAME}?akey=$akey&group=NEW"><em>new group</em></a>'
816 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
826 s/\s*[\r\n]+\s*/\n/g;
831 my ($user,$otuser,$url,$comment) = @_;
832 my $server = $hostname || $mdomain;
837 $user .= '@'.$mdomain if $mdomain and $user !~ /@/;
838 $sf = $sender_from ? $sender_from : $user;
839 open my $mail,'|-',$sendmail,'-f',$sf,$otuser,$bcc
840 or http_die("cannot start sendmail - $!\n");
842 'From: $sf ($user via F*EX service $server)'
844 'Subject: Your upload URL'
847 'This is an automatically generated e-mail.'
853 'to upload one file to $user'
857 'Questions? ==> F*EX admin: $admin'
860 or http_die("cannot send notification e-mail (sendmail error $!)\n");
865 my ($user,$subuser,$url,$comment) = @_;
866 my $server = $hostname || $mdomain;
871 $user .= '@'.$mdomain if $mdomain and $user !~ /@/;
872 $sf = $sender_from ? $sender_from : $user;
873 open my $mail,'|-',$sendmail,'-f',$sf,$subuser,$user,$bcc
874 or http_die("cannot start sendmail - $!\n");
876 'From: $sf ($user via F*EX service $server)'
879 'Subject: Your F*EX account on $server'
882 'This is an automatically generated e-mail.'
884 'A F*EX (File EXchange) account has been created for you on $server'
889 'to upload files to $user'
891 'See http://$ENV{HTTP_HOST}/index.html for more information about F*EX.'
895 'Questions? ==> F*EX admin: $admin'
898 or http_die("cannot send notification e-mail (sendmail error $!)\n");
902 sub notify_groupmember {
903 my ($user,$gm,$group,$id,$url) = @_;
904 my $server = $hostname || $mdomain;
907 $user .= '@'.$mdomain if $mdomain and $user !~ /@/;
908 $sf = $sender_from ? $sender_from : $user;
909 open my $mail,'|-',$sendmail,'-f',$sf,$gm,$user,$bcc
910 or http_die("cannot start sendmail - $!\n");
912 'From: $sf ($user via F*EX service $hostname)'
915 'Subject: Your F*EX account on $server'
918 'A F*EX (File EXchange) account has been created for you on $server'
923 'to upload files to F*EX group "$group"'
925 'See http://$ENV{HTTP_HOST}/ for more information about F*EX.'
927 'Questions? ==> F*EX admin: $admin'
930 or http_die("cannot send notification e-mail (sendmail error $!)\n");
935 my ($user,$subuser,$id) = @_;
936 my $skey = md5_hex("$user:$subuser:$id");
938 open my $skf,'>',"$skeydir/$skey" or die "$skeydir/$skey - $!\n";
939 print {$skf} "from=$subuser\n",
942 close $skf or die "$skeydir/$skey - $!\n";
943 mkdirp("$subuser/\@MAINUSER");
944 symlink $skey,"$subuser/\@MAINUSER/$user";
950 my ($user,$group,$gm,$id) = @_;
951 my $gkey = untaint(md5_hex("$user:$group:$gm:$id"));
953 open my $gkf,'>',"$gkeydir/$gkey" or die "$gkeydir/$gkey - $!\n";
954 print {$gkf} "from=$gm\n",
958 close $gkf or die "$gkeydir/$gkey - $!\n";
964 my ($gf,$gd,$gl,$gid,$gkey);
967 $group =~ s:[/&<>]::g;
969 # $notify is group member
971 $gf = untaint("$notify/\@GROUP/$group");
972 unless ($_ = readlink $gf) {
974 '<h2>ERROR: cannot read $gf - $!</h2>'
979 if (m{([^/]+\@[\w.-]+)/}) {
983 '<h2>INTERNAL ERROR: groupfile = $gf</h2>'
988 if (open $gf,'<',$gf) {
990 if (/\Q$notify\E:(\S+)/i) {
998 '<h2>ERROR: cannot open $gf - $!</h2>'
1005 '<h2>ERROR: $notify not found in $gf</h2>'
1010 $gkey = untaint(md5_hex("$user:$group:$notify:$gid"));
1016 # "$ENV{PROTO}://$ENV{HTTP_HOST}/fup?from=$notify&to=\@$group"
1020 '<h2>Notification e-mail to $notify has been sent</h2>'
1021 '<p><a href="javascript:history.back()">Go back</a>'
1027 $gf = untaint("$user/\@GROUP/$group");
1031 foreach (split /\n/,$gm) {
1037 if (/(.+@[\w\.-]+)/ and checkaddress($_)) {
1040 push @badaddress,$_;
1047 print "<h2>ERROR: lines not in format <e-mail address>:<encryption-ID></h2>\n<ul>";
1048 foreach my $ba (@badformat) { print "<li>$ba" }
1052 print "<h2>ERROR: bad addresses:</h2>\n<ul>";
1053 foreach my $ba (@badaddress) { print "<li>$ba" }
1056 if (@badformat or @badaddress) {
1058 '<a href="javascript:history.back()">Go back</a>'
1063 $gd = "$user/\@GROUP";
1064 unless (-d $gd or mkdir $gd,0700) {
1065 print "<h2>ERROR: cannot create $gd - $!</h2>\n";
1066 print "</body></html>\n";
1070 if ($_ = readlink $gf and m{([^/]+\@[\w.-]+)/}) {
1073 '<h2>ERROR: you are already in group \@$group owned by $user</h2>'
1074 '<a href="javascript:history.back()">Go back</a>'
1075 'and enter another group name'
1079 print "<h2>INTERNAL ERROR: $gf is a symlink. but not readable</h2>\n";
1080 print "</body></html>\n";
1085 if (open $gf,'<',$gf) {
1086 # delete old group links and gkeys
1089 if (/(.+\@.+):(.+)/) {
1090 $gkey = untaint(md5_hex("$user:$group:$1:$2"));
1091 unlink "$gkeydir/$gkey";
1092 unlink "$1/\@GROUP/$group" if -l "$1/\@GROUP/$group";
1097 # write new group file and gkeys
1098 if (open $gf,'>',$gf) {
1099 $gm =~ s/[\r\n]+/\n/g;
1100 foreach (split /\n/,$gm) {
1104 if (/^\s*([^\/]+):(.+)/) {
1105 mkgkey(lc $user,$group,lc $1,$2);
1110 print "<h2>ERROR: cannot write $gf - $!</h2>\n";
1111 print "</body></html>\n";
1116 next if $gm eq $user;
1117 unless (-d $gm or mkdir $gm,0700) {
1118 print "<h2>ERROR: cannot create $gm - $!</h2>\n";
1119 print "</body></html>\n";
1122 $gd = "$gm/\@GROUP";
1123 unless (-d $gd or mkdir $gd,0700) {
1124 print "<h2>ERROR: cannot create $gd - $!</h2>\n";
1125 print "</body></html>\n";
1128 $gl = "$gm/\@GROUP/$group";
1129 unless (-l $gl or symlink "../../$user/\@GROUP/$group",$gl) {
1130 print "<h2>ERROR: cannot create $gl - $!</h2>\n";
1131 print "</body></html>\n";
1136 '<h2>Group \@$group has members:</h2>'
1141 print " <li><a href=\"$ENV{SCRIPT_NAME}?akey=$akey&group=$group¬ify=$gm\">$gm</a>\n";
1146 '(click address to send a notification e-mail to this user)'
1149 print "<h2>Group \@$group has no members</h2>\n";
1153 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
1158 # no group members -> delete group file
1164 '<h2>Edit F*EX group</h2>'
1165 'A F*EX group is similar to a mailing list, but for files:<br>'
1166 'When a member fexes a file to this list, '
1167 'then all other members will receive it.'
1169 '<form action="$ENV{SCRIPT_NAME}"'
1171 ' accept-charset="UTF-8"'
1172 ' enctype="multipart/form-data">'
1173 ' <input type="hidden" name="akey" value="$akey">'
1175 if ($group eq 'NEW') {
1177 ' <font color="red">'
1178 ' New group name: <input type="text" name="group"> (You MUST fill out this field!)'
1182 if (open $gf,'<',$gf) {
1188 ' <input type="hidden" name="group" value="$group">'
1189 ' F*EX group <b>\@$group</b>:'
1192 my $rows = ($gm =~ tr/\n//) + 5;
1194 ' <br><textarea name="gm" cols="80" rows="$rows">$gm</textarea><br>'
1195 ' <input type="submit" value="submit">'
1199 ' <tr align="left"><td>This list must have entries in format:<td><e-mail address>:<encryption-ID><td></tr>'
1200 ' <tr align="left"><td>Example:<td><code>framstag\@rus.uni-stuttgart.de:schwuppdiwupp</code><td></tr>'
1203 'The encryption-ID is necessary to generate a unique upload URL for this subuser.'
1204 'You can name any existing e-mail address.'
1206 if (open my $ab,'<',"$user/\@ADDRESS_BOOK") {
1209 "<h3>Your address book:</h3>"
1214 print "$1\n" if /([\S]+\@[\S]+)/;
1219 print "</body></html>\n";