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>
9 BEGIN { ($ENV{PERLINIT}||'') =~ /(.+)/s and eval $1 }
13 use Digest::MD5 qw(md5_hex);
16 ($FEXLIB) = $ENV{FEXLIB} =~ /(.+)/;
17 die "$0: no $FEXLIB\n" unless -d $FEXLIB;
21 our ($mdomain,$admin,$hostname,$sendmail,$akeydir,$skeydir,$docdir,$durl,$bcc);
22 our ($nomail,$faillog);
25 # load common code, local config : $HOME/lib/fex.ph
26 require "$FEXLIB/fex.pp" or die "$0: cannot load $FEXLIB/fex.pp - $!\n";
30 my $error = 'F*EX user config ERROR';
31 my $head = "$ENV{SERVER_NAME} F*EX user config";
36 chdir $spooldir or die "$spooldir - $!\n";
38 my $user = my $id = my $nid = my $ssid = my $comment = '';
39 my $notification = my $reminder = my $disclaimer = '';
40 my $encryption = my $pubkey = my $mime = '';
42 $akey = ''; # delete akey cookie
44 my $qs = $ENV{QUERY_STRING};
46 if ($qs =~ /akey=(\w+)/i) { $akey = $1 }
47 if ($qs =~ /ab=load/) { $ab = 'load' }
50 # look for CGI parameters
53 foreach my $v (keys %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 = $PARAM{$v}{data}:
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 ? $show = checkchars('parameter',$vv):
82 if ($group and $group ne 'NEW') {
84 $group =~ s/[^\w\*%^+=:,.!-]/_/g;
86 $group = '' if $nomail;
87 $user .= '@'.$mdomain if $mdomain and $user !~ /@/;
89 $nomail = $comment if $comment =~ /NOMAIL|!#!/;
91 if ($show and $show eq 'tools') {
94 "Location: /tools.html",
101 if (open $tools,"$docdir/tools.html") {
103 while (/\$([\w_]+)\$/) {
105 my $env = $ENV{$var} || '';
117 # sid is not set with web browser
118 my $idf = "$akeydir/$akey/@";
120 if (open $akey,'<',$idf and $id = getline($akey)) {
124 or http_die("internal server error: no $akey symlink $1");
126 $user = untaint($user);
127 if ($akey ne md5_hex("$user:$id")) {
133 &check_status($user) if $user;
135 if ($user and $akey and $qs and $qs =~ /info=(.+?)&skey=(.+)/) {
138 notify_subuser($user,$subuser,"$fup?skey=$skey",$comment);
139 http_header("200 OK");
140 print html_header($head);
142 'An information e-mail has been sent to your subuser $subuser'
143 '<p><a href="javascript:history.back()">Go back</a>'
151 if (-e "$user/\@CAPTIVE") { html_error($error,"captive user") }
152 unless (open $idf,'<',"$user/@") {
153 faillog("user $from, id $id");
154 html_error($error,"wrong user or auth-ID");
156 $rid = getline($idf);
160 $akey = untaint(md5_hex("$user:$id"));
161 unlink "$akeydir/$akey";
162 symlink "../$user","$akeydir/$akey";
165 faillog("user $from, id $id");
166 html_error($error,"wrong user or auth-ID");
169 my $login = -x "$FEXHOME/login" ? 'login' : 'fup';
171 "HTTP/1.1 302 Found",
172 "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/$login",
180 # empty POST? ==> back to foc
181 if ($ENV{REQUEST_METHOD} eq 'POST' and not
182 ($subuser or $notify or $nid or $ssid or $group or $ab or $gm
183 or $disclaimer or $encryption or $pubkey))
186 "HTTP/1.1 302 Found",
187 "Location: $ENV{PROTO}://$ENV{HTTP_HOST}/foc",
195 unlink $faillog if $faillog;
197 http_header("200 OK");
198 print html_header($head);
199 # foreach $v (keys %ENV) { print $v,' = "',$ENV{$v},"\"<br>\n" };
201 if ($gm and not $group) {
203 '<h2>ERROR: no group name specified</h2>'
213 # create one time upload key
214 if ($subuser and $otuser) {
216 if ($otuser !~ /^[^@]+@[\w.-]+[a-z]$/) {
218 '<code>$otuser</code> is not a valid e-mail address'
219 '<p><a href="javascript:history.back()">Go back</a>'
224 my $okey = randstring(8);
225 my $okeyd = "$user/\@OKEY";
227 symlink $otuser,"$okeyd/$okey"
228 or http_die("cannot create OKEY $okeyd/$okey : $!\n");
229 my $url = "$fup?to=$user&okey=$okey";
231 'A one time upload URL for <code>$otuser</code> has been created:'
236 ¬ify_otuser($user,$otuser,$url,$comment);
239 'and an information e-mail has been sent to this address.'
244 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
250 # direct single subuser entry
251 if ($subuser and not $otuser) {
252 if (-f "$subuser/@") {
254 '<code>$subuser</code> is already a registered F*EX full user'
255 '<p><a href="javascript:history.back()">Go back</a>'
260 if ($subuser !~ /^[^@]+@[\w.-]+[a-z]$/) {
262 '<code>$subuser</code> is not a valid e-mail address'
263 '<p><a href="javascript:history.back()">Go back</a>'
269 if (open $idf,'<',"$user/\@SUBUSER") {
272 if (/^\Q$subuser:/) {
273 $skey = md5_hex("$user:$_");
280 my $url = "$fup?skey=$skey";
283 '$subuser is already your subuser and has access URL:'
289 '<a href=\"/fuc?akey=$akey&info=$subuser&skey=$skey\">$subuser</a>'
290 'is already your subuser and has access URL:'
294 "Click on the subuser's e-mail address link to send him an"
295 "information e-mail by the F*EX server.<p>"
299 my $sid = randstring(8);
300 my $skey = mkskey($user,$subuser,$sid);
301 $url = "$fup?skey=$skey";
302 open $idf,'>>',"$user/\@SUBUSER" or die "$user/\@SUBUSER - $!\n";
303 print {$idf} "$subuser:$sid\n";
306 'Your subuser upload URL is:'
311 ¬ify_subuser($user,$subuser,$url,$comment);
314 'An information e-mail has been sent to $subuser'
318 print "</body></html>\n";
323 if ($user and $akey and defined $ab) {
326 if (open $ab,'<',"$user/\@ADDRESS_BOOK") {
331 $ab = html_quote($_);
333 my $rows = ($ab =~ tr/\n//) + 5;
335 '<h2>Edit address book</h2>'
337 ' <tr align="left"><th>Entry:<th>alias<th>e-mail address<th># optional comment</tr>'
338 ' <tr align="left"><td>Example:<td><code>Framstag</code><td><code>framstag\@rus.uni-stuttgart.de</code><td><code># Ulli Horlacher</code></tr>'
340 '<form action="$ENV{SCRIPT_NAME}"'
342 ' accept-charset="UTF-8"'
343 ' enctype="multipart/form-data">'
344 ' <input type="hidden" name="akey" value="$akey">'
345 ' <textarea name="ab" cols="160" rows="$rows">$ab</textarea><br>'
346 ' <input type="submit" value="submit">'
349 'You may use these alias names as F*EX recipient addresses on '
350 '<a href="/fup?akey=$akey">fup</a>'
352 'Alternatively you can fex a file ADDRESS_BOOK to yourself '
353 '($user) containing your alias definitions.'
355 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
363 foreach (split(/\n/,$ab)) {
366 if (s/\s*(#.*)//) { $comment = $1 }
367 else { $comment = '' }
370 push @options,$1 if s/(autodelete=\w+)//i;
371 push @options,$1 if s/(keep=\d+)//i;
373 if (s/([\S]+)\s+(\S+)//) {
376 $options = join(',',@options);
377 push @abt,"<tr><td>$alias<td>$address<td>$options<td>$comment</tr>\n";
384 print "<h2>ERROR: bad aliases:</h2>\n<ul>";
385 foreach my $ba (@badalias) { print "<li>$ba" }
389 'Not in format: <code>alias e-mail-address</code>'
391 '<a href="javascript:history.back()">Go back</a>'
397 open my $AB,'>',"$user/\@ADDRESS_BOOK"
398 or http_die("cannot open $user/\@ADDRESS_BOOK - $!\n");
402 '<h2><a href ="/fuc?AB=load&akey=$akey">address book</a></h2>'
404 '<tr><th>alias<th>e-mail address<th>options<th>comment</tr>'
408 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
410 '<a href="/fup?akey=$akey">back to fup (F*EX upload)</a>'
417 if ($user and $notification eq 'detailed') {
418 unlink "$user/\@NOTIFICATION";
420 '<h3>Notification e-mails now come in detailed format.<h3>'
422 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
428 if ($user and $mime eq 'yes') {
429 open $mime,'>',"$user/\@MIME" or http_die("cannot write $user/\@MIME - $!\n");
432 '<h3>Downloads will now be displayed (if possible).<h3>'
434 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
440 if ($user and $mime eq 'no') {
441 unlink "$user/\@MIME";
443 '<h3>Downloads will now be saved.<h3>'
445 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
451 if ($user and $notification eq 'short') {
452 unlink "$user/\@NOTIFICATION";
453 symlink "short","$user/\@NOTIFICATION";
455 '<h3>Notification e-mails now come in short format.<h3>'
457 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
463 if ($user and $disclaimer) {
464 my $df = "$user/\@DISCLAIMER";
465 if ($disclaimer =~ /^[\s\"]*DEFAULT[\s\"]*$/i) {
468 '<h3>E-mail disclaimer reset to default.</h3>'
470 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
473 } elsif ($disclaimer eq 'CHANGE') {
474 $disclaimer = slurp($df) || '';
475 $disclaimer =~ s/&/&/g;
476 $disclaimer =~ s/</</g;
478 '<form action="$ENV{SCRIPT_NAME}"'
480 ' accept-charset="UTF-8"'
481 ' enctype="multipart/form-data">'
482 ' <input type="hidden" name="akey" value="$akey">'
484 ' Disclaimer to be sent with download notification e-mail:<br>'
485 ' <textarea name="disclaimer" cols="80" rows="10">$disclaimer</textarea><br>'
486 ' <input type="submit" value="save">'
487 ' or <a href="$ENV{SCRIPT_NAME}?akey=$akey&disclaimer=DEFAULT">'
488 ' reset the disclaimer to default</a>.'
494 $disclaimer =~ s/^\s+//;
495 $disclaimer =~ s/\s+$/\n/;
496 open $df,'>',$df or http_die("cannot write $df - $!\n");
497 print {$df} $disclaimer;
499 $disclaimer =~ s/&/&/g;
500 $disclaimer =~ s/</</g;
502 '<h2>E-mail disclaimer changed to:</h2>'
507 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
515 if ($user and $pubkey) {
516 my $gf = "$user/\@GPG";
521 open $pk,">$gf.pk" or http_die("cannot write $gf.pk - $!\n");
525 system "gpg --batch --no-default-keyring --keyring $gf --import".
526 "< $gf.pk >/dev/null 2>&1";
527 if (`gpg --batch <$gf 2>/dev/null` =~ /^pub\s.*<\Q$user\E>/sm) {
528 $pk = `gpg --batch <$gf 2>&1`;
532 '<h2>E-mails to you will be encrypted with the PGP/GPG key:</h2>'
537 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
540 unlink "$gf.pk","$gf~";
542 $pk = `gpg --batch <$gf.pk 2>&1`;
546 '<h2>Your uploaded file does not contain a PGP/GPG public key for'
547 ' <code>$user</code></h2>'
552 '<a href="javascript:history.back()">back</a>'
559 if ($user and $encryption) {
560 my $gf = "$user/\@GPG";
562 unless(-s "$ENV{HOME}/.gnupg/pubring.gpg") {
563 html_error($error,"no GPG support activated");
566 if ($encryption eq 'DELETE') {
569 '<h3>PGP/GPG key deleted.</h3>'
570 '<h3>E-mails to you will be sent not encrypted.</h3>'
572 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
574 } elsif ($encryption eq 'CHANGE') {
576 '<form action="$ENV{SCRIPT_NAME}"'
578 ' accept-charset="UTF-8"'
579 ' enctype="multipart/form-data">'
580 ' <input type="hidden" name="akey" value="$akey">'
581 ' Select your PGP/GPG public key file(*):<br>'
582 ' <input type="file" name="pubkey" size="80">'
584 ' and <input type="submit" value="upload">'
591 'or <a href="$ENV{SCRIPT_NAME}?akey=$akey&encryption=DELETE">'
592 'delete your already uploaded public key</a>:'
600 '(*) To extract and verify your GPG public key use:'
602 'gpg -a --export $user > pubkey.gpg'
607 print "</body></html>\n";
611 if ($user and $reminder eq 'yes') {
612 unlink "$user/\@REMINDER";
614 '<h3>You will now get reminder notification e-mails.<h3>'
616 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
622 if ($user and $reminder eq 'no') {
623 unlink "$user/\@REMINDER";
624 symlink "no","$user/\@REMINDER";
626 '<h3>You will now get no reminder notification e-mails.<h3>'
628 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
638 $nid = randstring(6) if $nid eq '?';
640 open $idf,'>',"$user/@" or die "$user/@ - $!\n";
641 print {$idf} $nid,"\n";
643 $akey = untaint(md5_hex("$user:$nid"));
644 unlink "$akeydir/$akey";
645 symlink "../$user","$akeydir/$akey";
648 '<h3>new auth-ID "<code>$nid</code>" for $user saved</h3>'
649 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
655 # empty subuser list POST
656 if (defined($PARAM{'ssid'}) and $ssid =~ /^\s*$/) {
657 unlink "$user/\@SUBUSER";
659 '<h2>All subusers deleted</h2>\n<ul>'
660 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
668 my ($subuser,$subid,$skey);
671 if (open $idf,'<',"$user/\@SUBUSER") {
674 if (/(.+\@.+):(.+)/) {
675 ($subuser,$subid) = ($1,$2);
676 $skey = md5_hex("$user:$subuser:$subid");
677 unlink "$skeydir/$skey";
678 unlink "$subuser/\@MAINUSER/$user";
684 $ssid = strip($ssid);
686 # collect (new) subusers
687 foreach (split("\n",$ssid)) {
690 if (/(.+\@[\w.-]+)/) {
692 push @badaddress,$subuser unless checkaddress($subuser);
697 print "<h2>ERROR: bad addresses:</h2>\n<ul>";
698 foreach my $ba (@badaddress) { print "<li>$ba" }
701 '<a href="javascript:history.back()">Go back</a>'
707 if ($ssid =~ /\S\@\w/) {
708 open $idf,'>',"$user/\@SUBUSER" or die "$user/\@SUBUSER - $!\n";
709 print "Your subusers upload URLs are:<p><code>\n";
711 foreach (split("\n",$ssid)) {
714 if (/(\S+\@[\w.-]+)/) {
716 if (/:(.+)/) { $subid = $1 }
717 else { $subid = randstring(8) }
718 print {$idf} "$subuser:$subid\n";
719 $skey = mkskey($user,$subuser,$subid);
720 print " <tr><td><a href=\"/fuc?akey=$akey&info=$subuser&skey=$skey\">$subuser</a> :",
721 "<td>$fup?skey=$skey</tr>\n";
725 "</table>\n</code><p>"
726 "You have to give these URLs to your subusers for fexing files to you."
728 "Or click on the subuser's e-mail address link to send him an"
729 "information e-mail by the F*EX server.<p>"
732 print "<a href=\"/foc?akey=$akey\">back to F*EX operation control</a>\n";
733 print "</body></html>\n";
738 if (open my $subuser,'<',"$user/\@SUBUSER") {
740 $ssid = <$subuser> || '';
744 # display HTML form and request user data
746 '<form action="$ENV{SCRIPT_NAME}"'
748 ' accept-charset="UTF-8"'
749 ' enctype="multipart/form-data">'
750 ' <input type="hidden" name="akey" value="$akey">'
754 # ' <input type="hidden" name="user" value="$user">'
755 # ' <input type="hidden" name="id" value="$id">'
756 # ' Your F*EX account: <b>$user:$id</b><p>'
757 # ' New auth-ID: <input type="text" name="nid" value="$id">'
758 # ' (Remember your auth-ID when you change it!)'
761 if (-s "$user/\@ALLOWED_RECIPIENTS") {
764 ' <input type="submit" value="submit">'
772 $ssid = html_quote(strip($ssid));
777 ' Allow special senders (= subusers) to fex files to you:<br>'
778 ' <textarea name="ssid" cols="60" rows="10">$ssid</textarea><br>'
779 ' <input type="submit" value="save and show upload URLs">'
783 ' <tr align="left"><td>This list has entries in format:<td><e-mail address>:<encryption-ID><td></tr>'
784 ' <tr align="left"><td>Example:<td><code>framstag\@rus.uni-stuttgart.de:schwuppdiwupp</code><td></tr>'
787 'These special senders may fex files <em>only</em> to you!<br>'
788 'It is not necessary to add regular fex users to your list,'
789 'because they already can fex.'
791 'The encryption-ID is necessary to generate a unique upload URL for this subuser.<br>'
792 'If you omit the encryption-ID a random one will be used.'
798 '<h3 title="A F*EX group is similar to a mailing list, but for files">'
799 'Edit your F*EX groups:</h3>'
803 foreach $group (glob "$user/\@GROUP/*") {
804 if (-f $group and not -l $group and $group !~ /~$/) {
806 print " <li><a href=\"$ENV{SCRIPT_NAME}?akey=$akey&group=$group\">\@$group</a>\n";
811 ' <li><a href="$ENV{SCRIPT_NAME}?akey=$akey&group=NEW"><em>new group</em></a>'
818 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
828 s/\s*[\r\n]+\s*/\n/g;
833 my ($user,$otuser,$url,$comment) = @_;
834 my $server = $hostname || $mdomain;
839 $user .= '@'.$mdomain if $mdomain and $user !~ /@/;
840 $sf = $sender_from ? $sender_from : $user;
841 open my $mail,'|-',$sendmail,'-f',$sf,$otuser,$bcc
842 or http_die("cannot start sendmail - $!\n");
844 'From: $sf ($user via F*EX service $server)'
846 'Subject: Your upload URL'
849 'This is an automatically generated e-mail.'
855 'to upload one file to $user'
859 'Questions? ==> F*EX admin: $admin'
862 or http_die("cannot send notification e-mail (sendmail error $!)\n");
867 my ($user,$subuser,$url,$comment) = @_;
868 my $server = $hostname || $mdomain;
873 $user .= '@'.$mdomain if $mdomain and $user !~ /@/;
874 $sf = $sender_from ? $sender_from : $user;
875 open my $mail,'|-',$sendmail,'-f',$sf,$subuser,$user,$bcc
876 or http_die("cannot start sendmail - $!\n");
878 'From: $sf ($user via F*EX service $server)'
881 'Subject: Your F*EX account on $server'
884 'This is an automatically generated e-mail.'
886 'A F*EX (File EXchange) account has been created for you on $server'
891 'to upload files to $user'
893 'See http://$ENV{HTTP_HOST}/index.html for more information about F*EX.'
897 'Questions? ==> F*EX admin: $admin'
900 or http_die("cannot send notification e-mail (sendmail error $!)\n");
904 sub notify_groupmember {
905 my ($user,$gm,$group,$id,$url) = @_;
906 my $server = $hostname || $mdomain;
909 $user .= '@'.$mdomain if $mdomain and $user !~ /@/;
910 $sf = $sender_from ? $sender_from : $user;
911 open my $mail,'|-',$sendmail,'-f',$sf,$gm,$user,$bcc
912 or http_die("cannot start sendmail - $!\n");
914 'From: $sf ($user via F*EX service $hostname)'
917 'Subject: Your F*EX account on $server'
920 'A F*EX (File EXchange) account has been created for you on $server'
925 'to upload files to F*EX group "$group"'
927 'See http://$ENV{HTTP_HOST}/index.html for more information about F*EX.'
929 'Questions? ==> F*EX admin: $admin'
932 or http_die("cannot send notification e-mail (sendmail error $!)\n");
937 my ($user,$subuser,$id) = @_;
938 my $skey = md5_hex("$user:$subuser:$id");
940 open my $skf,'>',"$skeydir/$skey" or die "$skeydir/$skey - $!\n";
941 print {$skf} "from=$subuser\n",
944 close $skf or die "$skeydir/$skey - $!\n";
945 mkdirp("$subuser/\@MAINUSER");
946 symlink $skey,"$subuser/\@MAINUSER/$user";
952 my ($user,$group,$gm,$id) = @_;
953 my $gkey = untaint(md5_hex("$user:$group:$gm:$id"));
955 open my $gkf,'>',"$gkeydir/$gkey" or die "$gkeydir/$gkey - $!\n";
956 print {$gkf} "from=$gm\n",
960 close $gkf or die "$gkeydir/$gkey - $!\n";
966 my ($gf,$gd,$gl,$gid,$gkey);
969 $group =~ s:[/&<>]::g;
971 # $notify is group member
973 $gf = untaint("$notify/\@GROUP/$group");
974 unless ($_ = readlink $gf) {
976 '<h2>ERROR: cannot read $gf - $!</h2>'
981 if (m{([^/]+\@[\w.-]+)/}) {
985 '<h2>INTERNAL ERROR: groupfile = $gf</h2>'
990 if (open $gf,'<',$gf) {
992 if (/\Q$notify\E:(\S+)/i) {
1000 '<h2>ERROR: cannot open $gf - $!</h2>'
1007 '<h2>ERROR: $notify not found in $gf</h2>'
1012 $gkey = untaint(md5_hex("$user:$group:$notify:$gid"));
1018 # "$ENV{PROTO}://$ENV{HTTP_HOST}/fup?from=$notify&to=\@$group"
1022 '<h2>Notification e-mail to $notify has been sent</h2>'
1023 '<p><a href="javascript:history.back()">Go back</a>'
1029 $gf = untaint("$user/\@GROUP/$group");
1033 foreach (split /\n/,$gm) {
1039 if (/(.+@[\w\.-]+)/ and checkaddress($_)) {
1042 push @badaddress,$_;
1049 print "<h2>ERROR: lines not in format <e-mail address>:<encryption-ID></h2>\n<ul>";
1050 foreach my $ba (@badformat) { print "<li>$ba" }
1054 print "<h2>ERROR: bad addresses:</h2>\n<ul>";
1055 foreach my $ba (@badaddress) { print "<li>$ba" }
1058 if (@badformat or @badaddress) {
1060 '<a href="javascript:history.back()">Go back</a>'
1065 $gd = "$user/\@GROUP";
1066 unless (-d $gd or mkdir $gd,0700) {
1067 print "<h2>ERROR: cannot create $gd - $!</h2>\n";
1068 print "</body></html>\n";
1072 if ($_ = readlink $gf and m{([^/]+\@[\w.-]+)/}) {
1075 '<h2>ERROR: you are already in group \@$group owned by $user</h2>'
1076 '<a href="javascript:history.back()">Go back</a>'
1077 'and enter another group name'
1081 print "<h2>INTERNAL ERROR: $gf is a symlink. but not readable</h2>\n";
1082 print "</body></html>\n";
1087 if (open $gf,'<',$gf) {
1088 # delete old group links and gkeys
1091 if (/(.+\@.+):(.+)/) {
1092 $gkey = untaint(md5_hex("$user:$group:$1:$2"));
1093 unlink "$gkeydir/$gkey";
1094 unlink "$1/\@GROUP/$group" if -l "$1/\@GROUP/$group";
1099 # write new group file and gkeys
1100 if (open $gf,'>',$gf) {
1101 $gm =~ s/[\r\n]+/\n/g;
1102 foreach (split /\n/,$gm) {
1106 if (/^\s*([^\/]+):(.+)/) {
1107 mkgkey(lc $user,$group,lc $1,$2);
1112 print "<h2>ERROR: cannot write $gf - $!</h2>\n";
1113 print "</body></html>\n";
1118 next if $gm eq $user;
1119 unless (-d $gm or mkdir $gm,0700) {
1120 print "<h2>ERROR: cannot create $gm - $!</h2>\n";
1121 print "</body></html>\n";
1124 $gd = "$gm/\@GROUP";
1125 unless (-d $gd or mkdir $gd,0700) {
1126 print "<h2>ERROR: cannot create $gd - $!</h2>\n";
1127 print "</body></html>\n";
1130 $gl = "$gm/\@GROUP/$group";
1131 unless (-l $gl or symlink "../../$user/\@GROUP/$group",$gl) {
1132 print "<h2>ERROR: cannot create $gl - $!</h2>\n";
1133 print "</body></html>\n";
1138 '<h2>Group \@$group has members:</h2>'
1143 print " <li><a href=\"$ENV{SCRIPT_NAME}?akey=$akey&group=$group¬ify=$gm\">$gm</a>\n";
1148 '(click address to send a notification e-mail to this user)'
1151 print "<h2>Group \@$group has no members</h2>\n";
1155 '<a href="/foc?akey=$akey">back to F*EX operation control</a>'
1157 print "</body></html>\n";
1160 # no group members -> delete group file
1166 '<h2>Edit F*EX group</h2>'
1167 'A F*EX group is similar to a mailing list, but for files:<br>'
1168 'When a member fexes a file to this list, '
1169 'then all other members will receive it.'
1171 '<form action="$ENV{SCRIPT_NAME}"'
1173 ' accept-charset="UTF-8"'
1174 ' enctype="multipart/form-data">'
1175 ' <input type="hidden" name="akey" value="$akey">'
1177 if ($group eq 'NEW') {
1179 ' <font color="red">'
1180 ' New group name: <input type="text" name="group"> (You MUST fill out this field!)'
1183 $gm = $user.':'.randstring(8);
1185 if (open $gf,'<',$gf) {
1191 ' <input type="hidden" name="group" value="$group">'
1192 ' F*EX group <b>\@$group</b>:'
1195 my $rows = ($gm =~ tr/\n//) + 5;
1197 ' <br><textarea name="gm" cols="80" rows="$rows">$gm</textarea><br>'
1198 ' <input type="submit" value="submit">'
1202 ' <tr align="left"><td>This list must have entries in format:<td><e-mail address>:<encryption-ID><td></tr>'
1203 ' <tr align="left"><td>Example:<td><code>framstag\@rus.uni-stuttgart.de:schwuppdiwupp</code><td></tr>'
1206 'The encryption-ID is necessary to generate a unique upload URL for this subuser.'
1207 'You can name any existing e-mail address.'
1209 if (open my $ab,'<',"$user/\@ADDRESS_BOOK") {
1212 "<h3>Your address book:</h3>"
1217 print "$1\n" if /([\S]+\@[\S]+)/;
1222 print "</body></html>\n";