--- loncom/publisher/loncfile.pm 2002/07/28 02:16:59 1.12 +++ loncom/publisher/loncfile.pm 2023/07/14 23:20:15 1.127 @@ -8,9 +8,8 @@ # and requests confirmation. The second phase commits the action # and displays a page showing the results of the action. # - # -# $Id: loncfile.pm,v 1.12 2002/07/28 02:16:59 foxr Exp $ +# $Id: loncfile.pm,v 1.127 2023/07/14 23:20:15 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -34,42 +33,21 @@ # # http://www.lon-capa.org/ # -# -# (Handler to retrieve an old version of a file -# -# (Publication Handler -# -# (TeX Content Handler -# -# 05/29/00,05/30,10/11 Gerd Kortemeyer) -# -# 11/28,11/29,11/30,12/01,12/02,12/04,12/23 Gerd Kortemeyer -# 03/23 Guy Albertelli -# 03/24,03/29 Gerd Kortemeyer) -# -# 03/31,04/03,05/02,05/09,06/23,06/24 Gerd Kortemeyer) -# -# 06/23 Gerd Kortemeyer -# 05/07/02 Ron Fox: -# - Added Debug log output so that I can trace what the heck this -# undocumented thingy does. -# 05/28/02 Ron Fox: -# - Started putting in pod in standard format. =pod =head1 NAME -Apache::loncfile - Construction space file management. +Apache::loncfile - Authoring space file management. =head1 SYNOPSIS - - Content handler for buttons on the top frame of the construction space + + Content handler for buttons on the top frame of the construction space directory. =head1 INTRODUCTION - loncfile is invoked when buttons in the top frame of the construction -space directory listing are clicked. All operations procede in two phases. + loncfile is invoked when buttons in the top frame of the construction +space directory listing are clicked. All operations proceed in two phases. The first phase describes to the user exactly what will be done. If the user confirms the operation, the second phase commits the operation and indicates completion. When the user dismisses the output of phase2, they are returned to @@ -86,10 +64,15 @@ package Apache::loncfile; use strict; use Apache::File; +use File::Basename; use File::Copy; +use HTML::Entities(); use Apache::Constants qw(:common :http :methods); -use Apache::loncacc; -use Apache::Log (); +use Apache::lonnet; +use Apache::loncommon(); +use Apache::lonlocal; +use LONCAPA qw(:DEFAULT :match); + my $DEBUG=0; my $r; # Needs to be global for some stuff RF. @@ -98,38 +81,43 @@ my $r; # Needs to be global for some =item Debug($request, $message) - If debugging is enabled puts out a debuggin message determined by the + If debugging is enabled puts out a debugging message determined by the caller. The debug message goes to the Apache error log file. Debugging - is enabled by ssetting the module global DEBUG variable to nonzero (TRUE). + is enabled by setting the module global DEBUG variable to nonzero (TRUE). Parameters: =over 4 - -=item $request - The curretn request operation. -=item $message - The message to put inthe log file. +=item $request - The current request operation. + +=item $message - The message to put in the log file. =back - + Returns: nothing. =cut sub Debug { - - # Marshall the parameters. - - my $r = shift; - my $log = $r->log; - my $message = shift; - - # Put out the indicated message butonly if DEBUG is false. - - if ($DEBUG) { - $log->debug($message); - } + # Put out the indicated message but only if DEBUG is true. + if ($DEBUG) { + my ($r,$message) = @_; + $r->log_reason($message); + } +} + +sub done { + my ($destfn) = @_; + return + '

' + .&Apache::lonhtmlcommon::confirm_success(&mt("Done")) + .'
'.&mt("Continue").'' + .'' + .'

'; } =pod @@ -137,7 +125,7 @@ sub Debug { =item URLToPath($url) Convert a URL to a file system path. - + In order to manipulate the construction space objects, it is necessary to access url identified objects a filespace objects. This function translates a construction space URL to a file system path. @@ -146,14 +134,14 @@ sub Debug { =over 4 =item Url - string [in] The url to convert. - + =back - + Returns: =over 4 -=item The corresponing file system path. +=item The corresponding file system path. =back @@ -168,139 +156,106 @@ Global References =cut sub URLToPath { - my $Url = shift; - &Debug($r, "UrlToPath got: $Url"); - $Url=~ s/^http\:\/\/[^\/]+\/\~(\w+)/\/home\/$1\/public_html/; - $Url=~ s/^http\:\/\/[^\/]+//; - &Debug($r, "Returning $Url \n"); - return $Url; + my $Url = shift; + &Debug($r, "UrlToPath got: $Url"); + $Url=~ s{^https?\://[^/]+}{}; + $Url=~ s{//+}{/}g; + $Url=~ s{^/}{}; + $Url=$Apache::lonnet::perlvar{'lonDocRoot'}."/$Url"; + &Debug($r, "Returning $Url \n"); + return $Url; } -=pod - -=item PublicationPath($domain, $user, $dir, $file) - - Determines the filesystem path corersponding to a published resource - specification. The returned value is the path. -Parameters: - -=over 4 - -=item $domain - string [in] Name of the domain within which the resource is - stored. - -=item $user - string [in] Name of the user asking about the resource. - -=item $dir - Directory pathr elatvie to the top of the resource space0 - -=item $file - name of the resource file itself without path info. - -=back - -=over 4 - -Returns: - -=item string - full path to the file if it exists in publication space. - -=back - -=cut - -sub PublicationPath -{ - my ($domain, $user, $dir, $file)=@_; - - return '/home/httpd/html/res/'.$domain.'/'.$user.'/'.$dir.'/'. - $file; +sub url { + my ($fn,$context) = @_; + my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; + $fn=~ s/^\Q$londocroot\E//; + $fn=~s{/\./}{/}g; + if ($context eq 'js') { + &js_escape(\$fn); + } else { + $fn=&HTML::Entities::encode($fn,'\'<>"&'); + } + return $fn; } -=pod - -=item ConstructionPath($domain, $user, $dir, $file) - - Determines the filesystem path corersponding to a construction space - resource specification. The returned value is the path -Parameters: - -=over 4 - -=item $user - string [in] Name of the user asking about the resource. - -=item $dir - Directory path relatvie to the top of the resource space - -=item $file - name of the resource file itself without path info. - -Returns: - -=item string - full path to the file if it exists in Construction space. - -=back - -=cut - -sub ConstructionPath { - my ($user, $dir, $file) = @_; - - return '/home/'.$user.'/public_html/'.$dir.'/'.$file; - +sub display { + my $fn=shift; + my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; + $fn=~s/^\Q$londocroot\E//; + $fn=~s{/\./}{/}g; + return ''.$fn.''; } -=pod - -=item ConstructionPathFromRelative($user, $relname) - - Determines the path to a construction space file given -the username and the path relative to the root of construction space. - -Parameters: - -=over 4 - -=item $user - string [in] Name of the user in whose construction space the - file [will] live. - -=item $relname - string[in] Path to the file relative to the root of the - construction space. - -=back - -Returns: - -=over 4 -=item string - Full path to the file. -=back - -=cut - -sub ConstructionPathFromRelative { - - my ($user, $relname) = @_; - return '/home/'.$user.'/public_html'.$relname; +# see if the file is +# a) published (return 0 if not) +# b) if, so obsolete (return 0 if not) + +sub obsolete_unpub { + my ($user,$domain,$construct)=@_; + my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; + my $published=$construct; + $published=~s{^\Q$londocroot/priv/\E}{$londocroot/res/}; + if (-e $published) { + if (&Apache::lonnet::metadata($published,'obsolete')) { + return 1; + } + return 0; + } else { + return 1; + } +} +# see if directory is empty +# ignores any .meta, .save, .bak, and .log files created for a previously +# published file, which has since been marked obsolete and deleted. +# ignores a .DS_Store file put there when viewing directory via webDAV on MacOS. +sub empty_directory { + my ($dirname,$phase) = @_; + if (opendir DIR, $dirname) { + my @files = grep(!/^\.\.?$/, readdir(DIR)); # ignore . and .. + if (@files) { + my @orphans = grep(/\.(meta|save|log|bak|DS_Store)$/,@files); + if (scalar(@files) - scalar(@orphans) > 0) { + return 0; + } else { + if (($phase eq 'Delete2') && (@orphans > 0)) { + foreach my $file (@orphans) { + if ($file =~ /\.(meta|save|log|bak)$/) { + unlink($dirname.$file); + } + } + } + } + } + closedir(DIR); + return 1; + } + return 0; } =pod -=item exists($user, $domain, $directory, $file) +=item exists($user, $domain, $file) - Determine if a resource file name has been publisehd or exists + Determine if a resource filename has been published or exists in the construction space. Parameters: =over 4 -=item $user - string [in] - Name of the user for which to check. +=item $user - string [in] - Name of the user for which to check. -=item $domain - string [in] - Name of the domain in which the resource +=item $domain - string [in] - Name of the domain in which the resource might have been published. -=item $dir - string [in] - Path relative to construction or resource space - in which the resource might live. +=item $file - string [in] - Name of the file. -=item $file - string [in] - Name of the file. +=item $creating - string [in] - optional, type of object being created, + either 'directory' or 'file'. Defaults to + 'file' if unspecified. =back @@ -308,41 +263,57 @@ Returns: =over 4 +=item string - Either undef, 'warning' or 'error' depending on the + type of problem + =item string - Either where the resource exists as an html string that can be embedded in a dialog or an empty string if the resource does not exist. - + =back =cut sub exists { - my ($user, $domain, $dir, $file) = @_; - - # Create complete paths in publication and construction space. + my ($user, $domain, $construct, $creating) = @_; + $creating ||= 'file'; - my $published = &PublicationPath($domain, $user, $dir, $file); - my $construct = &ConstructionPath($user, $dir, $file); - - # If the resource exists in either space indicate this fact. - # Note that the check for existence in resource space is stricter. + my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; + my $published=$construct; + $published=~s{^\Q$londocroot/priv/\E}{$londocroot/res/}; + my ($type,$result); + if ( -d $construct ) { + return ('error','

'.&mt('Error: destination for operation is an existing directory.').'

'); + + } - my $result; - if ( -e $published) { - $result.='

Warning: target file exists, and has been published!

'; - } - elsif ( -e $construct) { - $result.='

Warning: target file exists!

'; - } + if ( -e $published) { + if ( -e $construct ) { + $type = 'warning'; + $result.='

'.&mt('Warning: target file exists, and has been published!').'

'; + } else { + my $published_type = (-d $published) ? 'directory' : 'file'; - return $result; + if ($published_type eq $creating) { + $type = 'warning'; + $result.='

'.&mt("Warning: a published $published_type of this name exists.").'

'; + } else { + $type = 'error'; + $result.='

'.&mt("Error: a published $published_type of this name exists.").'

'; + } + } + } elsif ( -e $construct) { + $type = 'warning'; + $result.='

'.&mt('Warning: target file exists!').'

'; + } + return ($type,$result); } =pod =item checksuffix($old, $new) - + Determine if a resource filename suffix (the stuff after the .) would change as a result of this operation. @@ -360,7 +331,7 @@ as a result of this operation. =over 4 -=item Empty string if everythikng worked. +=item Empty string if everything worked. =item String containing an error message if there was a problem. @@ -375,12 +346,81 @@ sub checksuffix { my $newsuffix; if ($new=~m:(.*/*)([^/]+)\.(\w+)$:) { $newsuffix=$3; } if ($old=~m:(.*)/+([^/]+)\.(\w+)$:) { $oldsuffix=$3; } - if ($oldsuffix ne $newsuffix) { + if (lc($oldsuffix) ne lc($newsuffix)) { $result.= - '

Warning: change of MIME type!

'; + '

'.&mt('Warning: change of MIME type!').'>

'; } return $result; } + +sub cleanDest { + my ($dest,$subdir,$fn,$uname,$udom)=@_; + #remove bad characters + my $foundbad=0; + my $warnings; + my $error=''; + if ($subdir && $dest =~/\./) { + $foundbad=1; + $dest=~s/\.//g; + } + $dest =~ s/(\s+$|^\s+)//g; + if ($dest=~/[\#\?&%\":]/) { + $foundbad=1; + $dest=~s/[\#\?&%\":]//g; + } + if ($dest=~m|/|) { + my ($newpath)=($dest=~m|(.*)/|); + ($newpath,$error)=&relativeDest($fn,$newpath,$uname,$udom); + if (! -d "$newpath") { + $warnings = '

' + .&mt("You have requested to create file in directory [_1] which doesn't exist. The requested directory path has been removed from the requested filename." + ,&display($newpath)) + .'

'; + $dest=~s|.*/||; + } + } + if ($dest =~ /\.(\d+)\.(\w+)$/) { + $warnings .= '

' + .&mt('Bad filename [_1]',&display($dest)) + .'
' + .&mt('[_1](name).(number).(extension)[_2] not allowed.','','') + .'
' + .&mt('Removing the [_1].number.[_2] from requested filename.','','') + .'

'; + $dest =~ s/\.(\d+)(\.\w+)$/$2/; + } + if ($foundbad) { + $warnings .= '

' + .&mt('Invalid characters in requested name have been removed.') + .'

'; + } + return ($dest,$error,$warnings); +} + +sub relativeDest { + my ($fn,$newfilename,$uname,$udom)=@_; + my $error = ''; + if ($newfilename=~/^\//) { +# absolute, simply add path + my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; + $newfilename="$londocroot/res/$udom/$uname/"; + } else { + my $dir=$fn; + $dir=~s{/[^/]+$}{}; + $newfilename=$dir.'/'.$newfilename; + } + $newfilename=~s{//+}{/}g; # remove duplicate / + while ($newfilename=~m{/\.\./}) { + $newfilename=~ s{/[^/]+/\.\./}{/}g; #remove dir/.. + } + my ($authorname,$authordom)=&Apache::lonnet::constructaccess($newfilename); + unless (($authorname) && ($authordom)) { + my $otherdir = &display($newfilename); + $error = &mt('Access denied to [_1]',$otherdir); + } + return ($newfilename,$error); +} + =pod =item CloseForm1($request, $user, $file) @@ -393,27 +433,17 @@ Parameters: =item $request - Apache Request Object [in] - Apache server request object. -=item $user - string [in] - Name of the user initiating the request. - -=item $file - A filename. +=item $cancelurl - the url to go to on cancel. =back =cut sub CloseForm1 { - my ($request, $user, $file) = @_; - my $url = "/priv/".$file; - - - $url =~ s/public_html\///; - $url =~ s/\/home//; - $url =~ s/\/\//\//; - - $request->print('

'); - $request->print('

'); - + my ($request, $fn) = @_; + $request->print(''); + $request->print('
'. + '
'); } @@ -433,7 +463,7 @@ Parameters: =item $user - string [in] - Name of the user that is initiating the request. -=item $directory - string [in] - Directory in which the operation is +=item $directory - string [in] - Directory in which the operation is being done relative to the top level construction space directory. @@ -442,22 +472,21 @@ Parameters: =cut sub CloseForm2 { - my ($request, $user, $directory) = @_; - - $request->print('

Done

'); + my ($request, $user, $fn) = @_; + $request->print(&done($fn)); } =pod =item Rename1($request, $filename, $user, $domain, $dir) - + Perform phase 1 processing of the file rename operation. Parameters: =over 4 -=item $request - Apache Request Object [in] The request object for the +=item $request - Apache Request Object [in] The request object for the current request. =item $filename - The filename relative to construction space. @@ -480,34 +509,87 @@ new filename relative to the current dir =back -=cut +=cut sub Rename1 { - my ($request, $filename, $user, $domain, $dir) = @_; - &Debug($request, "Username - ".$user." filename: ".$filename."\n"); - my $conspace = $filename; - - - if(-e $conspace) { - if($ENV{'form.newfilename'}) { - my $newfilename = $ENV{'form.newfilename'}; - $request->print(&checksuffix($filename, $newfilename)); - $request->print(&exists($user, $domain, $dir, $newfilename)); - $request->print('

Rename '.$filename.' to '. - $dir.'/'.$newfilename.'?

'); - &CloseForm1($request, $user, $filename); + my ($request, $user, $domain, $fn, $newfilename, $style) = @_; + + if(-e $fn) { + if($newfilename) { + # is dest a dir + if ($style eq 'move') { + if (-d $newfilename) { + if ($fn =~ m|/([^/]*)$|) { $newfilename .= '/'.$1; } + } + } + if ($newfilename =~ m|/[^\.]+$|) { + #no extension add on original extension + if ($fn =~ m|/[^\.]*\.([^\.]+)$|) { + $newfilename.='.'.$1; + } + } + $request->print(&checksuffix($fn, $newfilename)); + #renaming a dir, delete the trailing / + #remove second to last element for current dir + if (-d $fn) { + $newfilename=~/\.(\w+)$/; + if (&Apache::loncommon::fileembstyle($1) eq 'ssi') { + $request->print('

'. + &mt('Cannot change MIME type of a directory.'). + ''. + '
'.&mt('Cancel').'

'); + return; + } + $newfilename=~s/\/[^\/]+\/([^\/]+)$/\/$1/; + } + $newfilename=~s://+:/:g; # remove duplicate / + while ($newfilename=~m:/\.\./:) { + $newfilename=~ s:/[^/]+/\.\./:/:g; #remove dir/.. + } + my ($type, $return)=&exists($user, $domain, $newfilename); + $request->print($return); + if ($type eq 'error') { + $request->print('
'.&mt('Cancel').''); + return; + } + unless (&obsolete_unpub($user,$domain,$fn)) { + $request->print('

' + .&mt('Cannot rename or move non-obsolete published file.') + .'
' + .''.&mt('Cancel').'

' + ); + return; + } + my $action; + if ($style eq 'rename') { + $action='Rename'; + } else { + $action='Move'; + } + $request->print('' + .'

' + .&mt($action.' [_1] to [_2]?', + &display($fn), + &display($newfilename)) + .'

' + ); + &CloseForm1($request, $fn); } else { - $request->print('

No new filename specified

'); + $request->print('

'.&mt('No new filename specified.').'

'); return; } } else { - $request->print('

No such File

'); + $request->print('

' + .&mt('No such file: [_1]', + &display($fn)) + .'

' + ); return; } - + } + =pod =item Delete1 @@ -522,26 +604,57 @@ Parameters: =item $request - Apache Request Object [in] request object for the current request. -=item $user - string [in] Name of session user. +=item $user - string [in] Name of the user initiating the request. + +=item $domain - string [in] Domain the initiating user is logged in as -=item $filename - string [in] Name fo the file to be deleted: - Filename is the full filesystem path to the file. +=item $filename - string [in] Source filename. =back =cut sub Delete1 { - my ($request, $user, $filename) = @_; + my ($request, $user, $domain, $fn) = @_; - if( -e $filename) { - $request->print(''); - $request->print('

Delete '.$filename.'?

'); - &CloseForm1($request, $user, $filename); - } else { - $request->print('

No Such file: '.$filename.'

'); - } + if( -e $fn) { + $request->print(''); + if (-d $fn) { + unless (&empty_directory($fn,'Delete1')) { + $request->print('

' + .'' + .&mt('Only empty directories may be deleted.') + .'
' + .&mt('You must delete the contents of the directory first.') + .'

' + .'

'.&mt('Cancel').'

' + ); + return; + } + } else { + unless (&obsolete_unpub($user,$domain,$fn)) { + $request->print('

' + .&mt('Cannot delete non-obsolete published file.') + .'
' + .''.&mt('Cancel').'

' + ); + return; + } + } + $request->print('

' + .&mt('Delete [_1]?', + &display($fn)) + .'

' + ); + &CloseForm1($request, $fn); + } else { + $request->print('

' + .&mt('No such file: [_1]', + &display($fn)) + .'

' + ); + } } =pod @@ -549,23 +662,21 @@ sub Delete1 { =item Copy1($request, $user, $domain, $filename, $newfilename) Performs phase 1 processing of the construction space copy command. - Ensure that the source fil eexists. Ensure that a destination exists, - also warn if the detination already exists. + Ensure that the source file exists. Ensure that a destination exists, + also warn if the destination already exists. Parameters: =over 4 -=item $request - Apache Request Object [in] request object for the current +=item $request - Apache Request Object [in] request object for the current request. =item $user - string [in] Name of the user initiating the request. =item $domain - string [in] Domain the initiating user is logged in as -=item $dir - string [in] Directory path. - -=item $filename - string [in] Source filename. +=item $fn - string [in] Source filename. =item $newfilename-string [in] Destination filename. @@ -574,26 +685,62 @@ Parameters: =cut sub Copy1 { - my ($request, $user, $domain, $dir, $filename, $newfilename) = @_; - + my ($request, $user, $domain, $fn, $newfilename) = @_; - if(-e $filename) { - $request->print(&checksuffix($filename,$newfilename)); - $request->print(&exists($user, $domain, $dir, $newfilename)); - $request->print('

Copy '.$filename.' to'. - ''.$dir.'/'.$newfilename.'/?

'); - &CloseForm1($request, $user, $filename); - } else { - $request->print('

No such file '.$filename.'

'); - } + if(-e $fn) { + # is dest a dir + if (-d $newfilename) { + if ($fn =~ m|/([^/]*)$|) { $newfilename .= '/'.$1; } + } + if ($newfilename =~ m|/[^\.]+$|) { + #no extension add on original extension + if ($fn =~ m|/[^\.]*\.([^\.]+)$|) { $newfilename.='.'.$1; } + } + $newfilename=~s://+:/:g; # remove duplicate / + while ($newfilename=~m:/\.\./:) { + $newfilename=~ s:/[^/]+/\.\./:/:g; #remove dir/.. + } + $request->print(&checksuffix($fn,$newfilename)); + my ($type,$return)=&exists($user, $domain, $newfilename); + $request->print($return); + if ($type eq 'error') { + $request->print('
'.&mt('Cancel').''); + return; + } +# Check if there is enough space. + my @fileinfo = stat($fn); + my ($dir,$fname) = ($fn =~ m{^(.+/)([^/]+)$}); + my $filesize = $fileinfo[7]; + $filesize = int($filesize/1000); #expressed in kb + my $output = &Apache::loncommon::excess_filesize_warning($user,$domain,'author', + $fname,$filesize,'copy'); + if ($output) { + $request->print($output.'
'.&mt('Cancel').''); + return; + } + $request->print( + '' + .'

' + .&mt('Copy [_1] to [_2]?', + &display($fn), + &display($newfilename)) + .'

' + ); + &CloseForm1($request, $fn); + } else { + $request->print('

' + .&mt('No such file: [_1]', + &display($fn)) + .'

' + ); + } } =pod =item NewDir1 - + Does all phase 1 processing of directory creation: Ensures that the user provides a new directory name, and that the directory does not already exist. @@ -603,13 +750,15 @@ Parameters: =over 4 =item $request - Apache Request Object [in] - Server request object for the - current url.. + current url. =item $username - Name of the user that is requesting the directory creation. -=item $path - current directory relative to construction spacee. +=item $domain - Domain user is in + +=item $fn - source file. -=item $newdir - Name of the directory to be created; path relative to the +=item $newdir - Name of the directory to be created; path relative to the top level of construction space. =back @@ -627,24 +776,169 @@ causes the newdir operation to transitio =cut -sub NewDir1 -{ - my ($request, $username, $path, $newdir) = @_; - - my $fullpath = '/home/'.$username.'/public_html/'. - $path.'/'.$newdir; - Debug($request, "Full path is : ".$fullpath); - - if(-e $fullpath) { - $request->print('

Directory exists.

'); - } - else { - $request->print('

Make new directory '. - $path."/".$newdir.'?

'); - &CloseForm1($request, $username, $newdir); +sub NewDir1 { + my ($request, $username, $domain, $fn, $newfilename, $mode) = @_; + + my ($type, $result)=&exists($username,$domain,$newfilename,'directory'); + $request->print($result); + if ($type eq 'error') { + $request->print(''); + } else { + if (($mode eq 'testbank') || ($mode eq 'imsimport')) { + $request->print(''."\n". + ''); + } + $request->print('' + .'

' + .&mt('Make new directory [_1]?', + &display($newfilename)) + .'

' + ); + &CloseForm1($request, $fn); + } +} + + +sub Decompress1 { + my ($request, $user, $domain, $fn) = @_; + if( -e $fn) { + $request->print(''); + $request->print('

' + .&mt('Decompress [_1]?', + &display($fn)) + .'

' + ); + &CloseForm1($request, $fn); + } else { + $request->print('

' + .&mt('No such file: [_1]', + &display($fn)) + .'

' + ); + } +} + +=pod + +=item NewFile1 + + Does all phase 1 processing of file creation: + Ensures that the user provides a new filename, adds proper extension + if needed and that the file does not already exist, if it is a html, + problem, page, or sequence, it then creates a form link to hand the + actual creation off to the proper handler. + +Parameters: + +=over 4 + +=item $request - Apache Request Object [in] - Server request object for the + current url. + +=item $username - Name of the user that is requesting the directory creation. + +=item $domain - Name of the domain of the user + +=item $fn - Source filename + +=item $newfilename + - Name of the file to be created; no path information + +=item $warnings - Information about changes to filename made by cleanDest(). + +=back + +Side Effects: + +=over 4 + +=item 2 new forms are displayed. Clicking on the confirmation button +causes the browser to attempt to load the specfied URL, allowing the +proper handler to take care of file creation. There is also a Cancel +button which returns you to the directory listing you came from + +=back + +=cut + +sub NewFile1 { + my ($request, $user, $domain, $fn, $newfilename, $warnings) = @_; + return if (&filename_check($newfilename,$warnings) ne 'ok'); + + if ($env{'form.action'} =~ /new(.+)file/) { + my $extension=$1; + if ($newfilename !~ /\Q.$extension\E$/) { + if ($newfilename =~ m|/[^/.]*\.(?:[^/.]+)$|) { + #already has an extension strip it and add in expected one + $newfilename =~ s|(/[^./])\.(?:[^.]+)$|$1|; + } + $newfilename.=".$extension"; + } + } + my ($type, $result)=&exists($user,$domain,$newfilename); + if ($type eq 'error') { + $request->print($warnings.$result); + $request->print(''); + } else { + my $extension; + + if ($newfilename =~ m{[^/.]+\.([^/.]+)$}) { + $extension = $1; + } + + my @okexts = qw(xml html xhtml htm xhtm problem page sequence rights sty task library js css txt); + if (($extension eq '') || (!grep(/^\Q$extension\E/,@okexts))) { + my $validexts = '.'.join(', .',@okexts); + $request->print($warnings.$result); + $request->print('

'. + &mt('Invalid filename: ').&display($newfilename).'

'. + &mt('The name of the new file needs to end with an appropriate file extension to indicate the type of file to create.').'
'. + &mt('The following are valid extensions: [_1].',$validexts). + '

'. + '

'. + ''. + ''. + ''.&mt('Enter a filename: ').' '. + '

'. + '

'); + } elsif (($type ne 'warning') && ($warnings eq '') && ($result eq '')) { + my $query = ""; + $query .= "?mode=" . $env{'form.mode'} unless (!exists($env{'form.mode'}) || !length($env{'form.mode'})); + $request->print(' + '); + } else { + $request->print($warnings.$result); + $request->print('

'.&mt('Make new file').' '.&display($newfilename).'?

'); + $request->print(''); + $request->print('

'); + $request->print('

'); + } + } + return; +} - } +sub filename_check { + my ($newfilename) = @_; + ##Informs User (name).(number).(extension) not allowed + if($newfilename =~ /\.(\d+)\.(\w+)$/){ + $r->print(''.$newfilename. + ' - '.&mt('Bad Filename').'
('.&mt('name').').('.&mt('number').').('.&mt('extension').') '. + ' '.&mt('Not Allowed').'
'); + return; + } + if($newfilename =~ /(\:\:\:|\&\&\&|\_\_\_)/){ + $r->print(''.$newfilename. + ' - '.&mt('Bad Filename').'
('.&mt('Must not include').' '.$1.') '. + ' '.&mt('Not Allowed').'
'); + return; + } + return 'ok'; } =pod @@ -655,7 +949,7 @@ sub NewDir1 are returned if the request cannot be performed (e.g. attempts to manipulate files that are nonexistent). If the operation can be performed, what is about to be done will be presented to the user for confirmation. If the -user confirms the request, then phase two is executed, the action +user confirms the request, then phase two is executed, the action performed and reported to the user. Parameters: @@ -664,59 +958,105 @@ performed and reported to the user. =item $r - request object [in] - The Apache request being executed. -=item $fn = string [in] - The filename being manipulated by the +=item $fn = string [in] - The filename being manipulated by the request. =item $uname - string [in] Name of user logged in and doing this action. -=item $udom - string [in] Domain nmae under which the user logged in. +=item $udom - string [in] Domain name under which the user logged in. =back =cut sub phaseone { - my ($r,$fn,$uname,$udom)=@_; - - $fn=~m:(.*)/([^/]+)\.(\w+)$:; - my $dir=$1; - my $main=$2; - my $suffix=$3; - - # my $conspace=ConstructionPathFromRelative($uname, $fn); - - - $r->print('
'. - ''. - ''. - ''); - - if ($ENV{'form.action'} eq 'rename') { - - &Rename1($r, $fn, $uname, $udom, $dir); - - } elsif ($ENV{'form.action'} eq 'delete') { - - &Delete1($r, $uname, $fn); - - } elsif ($ENV{'form.action'} eq 'copy') { - if($ENV{'form.newfilename'}) { - my $newfilename = $ENV{'form.newfilename'}; - &Copy1($r, $uname, $udom, $dir, $fn, $newfilename); - }else { - $r->print('

No new filename specified.

'); - } - } elsif ($ENV{'form.action'} eq 'newdir') { - &NewDir1($r, $uname, $dir, $ENV{'form.newfilename'}); - } - + my ($r,$fn,$uname,$udom)=@_; + + my $doingdir=0; + if ($env{'form.action'} eq 'newdir') { $doingdir=1; } + my ($newfilename,$error,$warnings) = + &cleanDest($env{'form.newfilename'},$doingdir,$fn,$uname,$udom); + unless ($error) { + ($newfilename,$error)=&relativeDest($fn,$newfilename,$uname,$udom); + } + if ($error) { + my $dirlist; + if ($fn=~m{^(.*/)[^/]+$}) { + $dirlist=$1; + } else { + $dirlist=$fn; + } + if ($warnings) { + $r->print($warnings); + } + $r->print('
'.$error.'
'. + '

'.&mt('Return to Directory'). + '

'); + return; + } + $r->print('
'. + ''. + ''. + ''); + + if ($env{'form.action'} eq 'newfile' || + $env{'form.action'} eq 'newhtmlfile' || + $env{'form.action'} eq 'newproblemfile' || + $env{'form.action'} eq 'newpagefile' || + $env{'form.action'} eq 'newsequencefile' || + $env{'form.action'} eq 'newrightsfile' || + $env{'form.action'} eq 'newstyfile' || + $env{'form.action'} eq 'newtaskfile' || + $env{'form.action'} eq 'newlibraryfile' || + $env{'form.action'} eq 'Select Action') { + my $empty=&mt('Type Name Here'); + if (($newfilename!~/\/$/) && ($newfilename!~/$empty$/)) { + &NewFile1($r, $uname, $udom, $fn, $newfilename, $warnings); + } else { + if ($warnings) { + $r->print($warnings); + } + $r->print('

' + .&mt('No new filename specified.') + .'

' + ); + } + } else { + if ($warnings) { + $r->print($warnings); + } + if ($env{'form.action'} eq 'rename') { + &Rename1($r, $uname, $udom, $fn, $newfilename, 'rename'); + } elsif ($env{'form.action'} eq 'move') { + &Rename1($r, $uname, $udom, $fn, $newfilename, 'move'); + } elsif ($env{'form.action'} eq 'delete') { + &Delete1($r, $uname, $udom, $fn); + } elsif ($env{'form.action'} eq 'decompress') { + &Decompress1($r, $uname, $udom, $fn); + } elsif ($env{'form.action'} eq 'copy') { + if ($newfilename) { + &Copy1($r, $uname, $udom, $fn, $newfilename); + } else { + $r->print('

' + .&mt('No new filename specified.') + .'

' + ); + } + } elsif ($env{'form.action'} eq 'newdir') { + my $mode = ''; + if (exists($env{'form.callingmode'}) ) { + $mode = $env{'form.callingmode'}; + } + &NewDir1($r, $uname, $udom, $fn, $newfilename, $mode); + } + } } =pod =item Rename2($request, $user, $directory, $oldfile, $newfile) -Performs phase 2 procesing of a rename reequest. This is where the +Performs phase 2 processing of a rename reequest. This is where the actual rename is performed. Parameters @@ -748,31 +1088,68 @@ Returns: sub Rename2 { - my ($request, $user, $directory, $oldfile, $newfile) = @_; + my ($request, $user, $directory, $oldfile, $newfile) = @_; - &Debug($request, "Rename2 directory: ".$directory." old file: ".$oldfile. - " new file ".$newfile."\n"); - &Debug($request, "Target is: ".$directory.'/'. - $newfile); - - if(-e $oldfile) { - unless(rename($oldfile, - $directory.'/'.$newfile)) { - $request->print('Error: '.$!.''); - return 0; - } else {} - } else { - $request->print("

No such file: /home".$user.'/public_html'. - $oldfile.'

'); - return 0; - } - return 1; + &Debug($request, "Rename2 directory: ".$directory." old file: ".$oldfile. + " new file ".$newfile."\n"); + &Debug($request, "Target is: ".$directory.'/'. + $newfile); + if (-e $oldfile) { + + my $oRN=$oldfile; + my $nRN=$newfile; + unless (rename($oldfile,$newfile)) { + $request->print(''.&mt('Error').': '.$!.''); + return 0; + } + ## If old name.(extension) exits, move under new name. + ## If it doesn't exist and a new.(extension) exists + ## delete it (only concern when renaming over files) + my $tmp1=$oRN.'.meta'; + my $tmp2=$nRN.'.meta'; + if(-e $tmp1){ + unless(rename($tmp1,$tmp2)){ } + } elsif(-e $tmp2){ + unlink $tmp2; + } + $tmp1=$oRN.'.save'; + $tmp2=$nRN.'.save'; + if(-e $tmp1){ + unless(rename($tmp1,$tmp2)){ } + } elsif(-e $tmp2){ + unlink $tmp2; + } + $tmp1=$oRN.'.log'; + $tmp2=$nRN.'.log'; + if(-e $tmp1){ + unless(rename($tmp1,$tmp2)){ } + } elsif(-e $tmp2){ + unlink $tmp2; + } + $tmp1=$oRN.'.bak'; + $tmp2=$nRN.'.bak'; + if(-e $tmp1){ + unless(rename($tmp1,$tmp2)){ } + } elsif(-e $tmp2){ + unlink $tmp2; + } + } else { + $request->print( + '

' + .&mt('No such file: [_1]', + &display($oldfile)) + .'

' + ); + return 0; + } + return 1; } + =pod =item Delete2($request, $user, $filename) - Performs phase two of a delete. The user has confirmed that they want + Performs phase two of a delete. The user has confirmed that they want to delete the selected file. The file is deleted and the results of the delete attempt are indicated. @@ -786,8 +1163,8 @@ Parameters: =item $user - string [in] The name of the user initiating the delete request. -=item $filename - string [in] The name of the file, relative to construction space, - to delete. +=item $filename - string [in] The name of the file, relative to construction + space, to delete. =back @@ -798,25 +1175,41 @@ Returns: =cut sub Delete2 { - my ($request, $user, $filename) = @_; - - if(-e $filename) { - unless(unlink($filename)) { - $request->print('Error: '.$!.''); - return 0; + my ($request, $user, $filename) = @_; + if (-d $filename) { + unless (&empty_directory($filename,'Delete2')) { + $request->print(''.&mt('Error: Directory Non Empty').''); + return 0; + } else { + if(-e $filename) { + unless(rmdir($filename)) { + $request->print(''.&mt('Error').': '.$!.''); + return 0; + } + } else { + $request->print('

'.&mt('No such file').'

'); + return 0; + } + } + } else { + if(-e $filename) { + unless(unlink($filename)) { + $request->print(''.&mt('Error').': '.$!.''); + return 0; + } + } else { + $request->print('

'.&mt('No such file').'

'); + return 0; + } } - } else { - $request->print('

No such file. print(''.&mt('Warning').': '.&mt('Name of new file is the same as name of old file').' - '.&mt('no action taken').'.'); + return 1; + } unless (copy($oldfile, $newfile)) { - $request->print(' Error: '.$!.''); + $request->print(''.&mt('copy Error').': '.$!.''); + return 0; + } elsif (!chmod(0660, $newfile)) { + $request->print(''.&mt('chmod error').': '.$!.''); + return 0; + } elsif (-e $oldfile.'.meta' && + !copy($oldfile.'.meta', $newfile.'.meta') && + !chmod(0660, $newfile.'.meta')) { + $request->print(''.&mt('copy metadata error'). + ': '.$!.''); return 0; } else { return 1; } } else { - $request->print('

No such file

'); + $request->print('

'.&mt('No such file').'

'); return 0; } return 1; } + =pod =item NewDir2($request, $user, $newdirectory) @@ -879,17 +1286,28 @@ Returns 0 - failure 1 - success. =cut sub NewDir2 { - my ($request, $user, $newdirectory) = @_; - - unless(mkdir($newdirectory, 02770)) { - $request->print('Error: '.$!.''); - return 0; - } - unless(chmod(02770, ($newdirectory))) { - $request->print(' Error: '.$!.''); - return 0; - } - return 1; + my ($request, $user, $newdirectory) = @_; + + unless(mkdir($newdirectory, 02770)) { + $request->print(''.&mt('Error').': '.$!.''); + return 0; + } + unless(chmod(02770, ($newdirectory))) { + $request->print(''.&mt('Error').': '.$!.''); + return 0; + } + return 1; +} + +sub decompress2 { + my ($r, $user, $dir, $file) = @_; + &Apache::lonnet::appenv({'cgi.file' => $file}); + &Apache::lonnet::appenv({'cgi.dir' => $dir}); + my $result=&Apache::lonnet::ssi_body('/cgi-bin/decompress.pl'); + $r->print($result); + &Apache::lonnet::delenv('cgi.file'); + &Apache::lonnet::delenv('cgi.dir'); + return 1; } =pod @@ -902,7 +1320,7 @@ sub NewDir2 { is performed and the result is shown. The strategy is to break out the processing into specific action processors - named action2 where action is the requested action and the 2 denotes + named action2 where action is the requested action and the 2 denotes phase 2 processing. Parameters: @@ -926,179 +1344,287 @@ Parameters: sub phasetwo { my ($r,$fn,$uname,$udom)=@_; - + &Debug($r, "loncfile - Entering phase 2 for $fn"); - - # Break down the file into it's component pieces. - - $fn=~/(.*)\/([^\/]+)\.(\w+)$/; - my $dir=$1; # Directory path - my $main=$2; # Filename. - my $suffix=$3; # Extension. - - my $dest; # On success this is where we'll go. - - &Debug($r, - "loncfile::phase2 dir = $dir main = $main suffix = $suffix"); - &Debug($r, - " newfilename = ".$ENV{'form.newfilename'}); + + # Break down the file into its component pieces. + + my $dir; # Directory path + my $main; # Filename. + my $suffix; # Extension. + if ($fn=~m:(.*)/([^/]+):) { + $dir=$1; # Directory path + $main=$2; # Filename. + } + if($main=~m:\.(\w+)$:){ # Fixes problems with filenames with no extensions + $suffix=$1; #This is the actually filename extension if it exists + $main=~s/\.\w+$//; #strip the extension + } + my $dest; # + my $dest_dir; # On success this is where we'll go. + my $disp_newname; # + my $dest_newname; # + &Debug($r,"loncfile::phase2 dir = $dir main = $main suffix = $suffix"); + &Debug($r," newfilename = ".$env{'form.newfilename'}); my $conspace=$fn; - - &Debug($r, - "loncfile::phase2 Full construction space name: $conspace"); - - &Debug($r, - "loncfie::phase2 action is $ENV{'form.action'}"); - + + &Debug($r,"loncfile::phase2 Full construction space name: $conspace"); + + &Debug($r,"loncfie::phase2 action is $env{'form.action'}"); + # Select the appropriate processing sub. - - if ($ENV{'form.action'} eq 'rename') { # Rename. - if($ENV{'form.newfilename'}) { - if(!&Rename2($r, $uname, $dir, $fn, $ENV{'form.newfilename'})) { + if ($env{'form.action'} eq 'decompress') { + $main .= '.'.$suffix; + if(!&decompress2($r, $uname, $dir, $main)) { + return ; + } + $dest = $dir."/."; + } elsif ($env{'form.action'} eq 'rename' || + $env{'form.action'} eq 'move') { + if($env{'form.newfilename'}) { + if (!defined($dir)) { + $fn=~m:^(.*)/:; + $dir=$1; + } + if(!&Rename2($r, $uname, $dir, $fn, $env{'form.newfilename'})) { return; } - # Prepend the directory to the new name to form the basis of the - # url of the new resource. - # - $dest = $dir."/".$ENV{'form.newfilename'}; + $dest = $dir."/"; + $dest_newname = $env{'form.newfilename'}; + $env{'form.newfilename'} =~ /.+(\/.+$)/; + $disp_newname = $1; + $disp_newname =~ s/\///; } - } elsif ($ENV{'form.action'} eq 'delete') { - if(!&Delete2($r, $uname, $ENV{'form.newfilename'})) { + } elsif ($env{'form.action'} eq 'delete') { + if(!&Delete2($r, $uname, $env{'form.newfilename'})) { return ; } # Once a resource is deleted, we just list the directory that # previously held it. # - $dest = $dir."/"; # Parent dir. - } elsif ($ENV{'form.action'} eq 'copy') { - if($ENV{'form.newfilename'}) { - if(!&Copy2($r, $uname, $dir, $fn, $ENV{'form.newfilename'})) { - return - } - $dest = $ENV{'form.newfilename'}; - - } else { - $r->print('

No New filename specified'); + $dest = $dir."/."; # Parent dir. + } elsif ($env{'form.action'} eq 'copy') { + if($env{'form.newfilename'}) { + if(!&Copy2($r, $uname, $dir, $fn, $env{'form.newfilename'})) { + return ; + } + $dest = $env{'form.newfilename'}; + } else { + $r->print('

'.&mt('No New filename specified').'

'); return; } - } elsif ($ENV{'form.action'} eq 'newdir') { - # - # Since the newfilename form field is construction space - # relative, ew need to prepend the current path; now in $fn. - # - my $newdir= $fn.$ENV{'form.newfilename'}; + } elsif ($env{'form.action'} eq 'newdir') { + my $newdir= $env{'form.newfilename'}; if(!&NewDir2($r, $uname, $newdir)) { return; } - $dest = $newdir."/" + $dest = $newdir."/"; + } + if ( ($env{'form.action'} eq 'newdir') && ($env{'form.phase'} eq 'two') && ( ($env{'form.callingmode'} eq 'testbank') || ($env{'form.callingmode'} eq 'imsimport') ) ) { + $r->print( + '

' + .&Apache::lonhtmlcommon::confirm_success(&mt('Done')) + .'
'.&mt('Continue').'' + .'

' + ); + } else { + if ($env{'form.action'} eq 'rename') { + $r->print( + '

'.&Apache::lonhtmlcommon::confirm_success(&mt('Done')).'

' + .&Apache::lonhtmlcommon::actionbox( + [''.&mt('Return to Directory').'', + ''.$disp_newname.''])); + } else { + $r->print(&done($dest)); + } } - # - # Substitute for priv for the first home in $dir to get our - # construction space path. - # - &Debug($r, "Final url is: $dest"); - $dest =~ s/\/home\//\/priv\//; - $dest =~ s/\/public_html//; - &Debug($r, "Final url after rewrite: $dest"); - - $r->print('

Done

'); } sub handler { - $r=shift; + $r=shift; + + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['decompress','action','filename','newfilename','mode']); + &Debug($r, "loncfile.pm - handler entered"); + &Debug($r, " filename: ".$env{'form.filename'}); + &Debug($r, " newfilename: ".$env{'form.newfilename'}); +# +# Determine the root filename +# This could come in as "filename", which actually is a URL, or +# as "qualifiedfilename", which is indeed a real filename in filesystem +# + my $fn; - &Debug($r, "loncfile.pm - handler entered"); - &Debug($r, " filename: ".$ENV{'form.filename'}); - &Debug($r, " newfilename: ".$ENV{'form.newfilename'}); - - my $fn; - - if ($ENV{'form.filename'}) { - $fn=$ENV{'form.filename'}; - &Debug($r, "loncfile::handler - raw url: $fn"); -# $fn=~s/^http\:\/\/[^\/]+\/\~(\w+)/\/home\/$1\/public_html/; -# $fn=~s/^http\:\/\/[^\/]+//; - $fn=URLToPath($fn); - &Debug($r, "loncfile::handler - doctored url: $fn"); - - } else { - &Debug($r, "loncfile::handler - no form.filename"); - $r->log_reason($ENV{'user.name'}.' at '.$ENV{'user.domain'}. - ' unspecified filename for cfile', $r->filename); - return HTTP_NOT_FOUND; - } - - unless ($fn) { - &Debug($r, "loncfile::handler - doctored url is empty"); - $r->log_reason($ENV{'user.name'}.' at '.$ENV{'user.domain'}. - ' trying to cfile non-existing file', $r->filename); - return HTTP_NOT_FOUND; - } + if ($env{'form.filename'}) { + &Debug($r, "test: $env{'form.filename'}"); + $fn=&unescape($env{'form.filename'}); + $fn=&URLToPath($fn); + } elsif($ENV{'QUERY_STRING'} && $env{'form.phase'} ne 'two') { + #Just hijack the script only the first time around to inject the + #correct information for further processing + $fn=&unescape($env{'form.decompress'}); + $fn=&URLToPath($fn); + $env{'form.action'}="decompress"; + } elsif ($env{'form.qualifiedfilename'}) { + $fn=$env{'form.qualifiedfilename'}; + } else { + &Debug($r, "loncfile::handler - no form.filename"); + $r->log_reason($env{'user.name'}.' at '.$env{'user.domain'}. + ' unspecified filename for cfile', $r->filename); + return HTTP_NOT_FOUND; + } + + unless ($fn) { + &Debug($r, "loncfile::handler - doctored url is empty"); + $r->log_reason($env{'user.name'}.' at '.$env{'user.domain'}. + ' trying to cfile non-existing file', $r->filename); + return HTTP_NOT_FOUND; + } # ----------------------------------------------------------- Start page output - my $uname; - my $udom; - ($uname,$udom)= - &Apache::loncacc::constructaccess($fn,$r->dir_config('lonDefDomain')); - &Debug($r, - "loncfile::handler constructaccess uname = $uname domain = $udom"); - unless (($uname) && ($udom)) { - $r->log_reason($uname.' at '.$udom. - ' trying to manipulate file '.$ENV{'form.filename'}. - ' ('.$fn.') - not authorized', - $r->filename); - return HTTP_NOT_ACCEPTABLE; - } - - $fn=~s/\/\~(\w+)//; - &Debug($r, "loncfile::handler ~ removed filename: $fn"); - - $r->content_type('text/html'); - $r->send_http_header; - - $r->print('LON-CAPA Construction Space'); - - $r->print( - ''); - - - $r->print('

Construction Space '.$fn.'

'); - - if (($uname ne $ENV{'user.name'}) || ($udom ne $ENV{'user.domain'})) { - $r->print('

Co-Author: '.$uname.' at '.$udom. - '

'); - } - - - &Debug($r, "loncfile::handler Form action is $ENV{'form.action'} "); - if ($ENV{'form.action'} eq 'delete') { - - $r->print('

Delete

'); - } elsif ($ENV{'form.action'} eq 'rename') { - $r->print('

Rename

'); - } elsif ($ENV{'form.action'} eq 'newdir') { - $r->print('

New Directory

'); - } elsif ($ENV{'form.action'} eq 'copy') { - $r->print('

Copy

'); - } else { - $r->print('

Unknown Action'); - return OK; - } - if ($ENV{'form.phase'} eq 'two') { - &Debug($r, "loncfile::handler entering phase2"); - &phasetwo($r,$fn,$uname,$udom); - } else { - &Debug($r, "loncfile::handler entering phase1"); - &phaseone($r,$fn,$uname,$udom); - } + my ($uname,$udom) = &Apache::lonnet::constructaccess($fn); + &Debug($r, + "loncfile::handler constructaccess uname = $uname domain = $udom"); + if (($uname eq '') || ($udom eq '')) { + $r->log_reason($uname.' at '.$udom. + ' trying to manipulate file '.$env{'form.filename'}. + ' ('.$fn.') - not authorized', + $r->filename); + return HTTP_NOT_ACCEPTABLE; + } + + + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + + my (%loaditem,$js); + + if ( ($env{'form.action'} eq 'newdir') && ($env{'form.phase'} eq 'two') && ( ($env{'form.callingmode'} eq 'testbank') || ($env{'form.callingmode'} eq 'imsimport') ) ) { + my $newdirname = $env{'form.newfilename'}; + $js = qq| + +|; + $loaditem{'onload'} = "writeDone()"; + } + + my $londocroot = $r->dir_config('lonDocRoot'); + my $trailfile = $fn; + $trailfile =~ s{^/(priv/)}{$londocroot/$1}; + + # Breadcrumbs + my $crsauthor; + my $text = 'Authoring Space'; + my $title = 'Authoring Space File Operation', + my $href = &Apache::loncommon::authorspace(&url($fn)); + if ($env{'request.course.id'}) { + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + if ($href eq "/priv/$cdom/$cnum/") { + $text = 'Course Authoring Space'; + $title = 'Course Authoring Space File Operation', + $crsauthor = 1; + } + } + &Apache::lonhtmlcommon::clear_breadcrumbs(); + &Apache::lonhtmlcommon::add_breadcrumb({ + 'text' => $text, + 'href' => $href, + }); + &Apache::lonhtmlcommon::add_breadcrumb({ + 'text' => 'File Operation', + 'title' => $title, + 'href' => '', + }); + + $r->print(&Apache::loncommon::start_page($title, + $js, + {'add_entries' => \%loaditem,}) + .&Apache::lonhtmlcommon::breadcrumbs() + .&Apache::loncommon::head_subbox( + &Apache::loncommon::CSTR_pageheader($trailfile)) + ); + + $r->print('

'.&mt('Location').': '.&display($fn).'

'); + + if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) { + unless ($crsauthor) { + $r->print('

' + .&mt('Co-Author [_1]',$uname.':'.$udom) + .'

' + ); + } + } + + + &Debug($r, "loncfile::handler Form action is $env{'form.action'} "); + my %action = &Apache::lonlocal::texthash( + 'delete' => 'Delete', + 'rename' => 'Rename', + 'move' => 'Move', + 'newdir' => 'New Directory', + 'decompress' => 'Decompress', + 'copy' => 'Copy', + 'newfile' => 'New Resource', + 'newhtmlfile' => 'New Resource', + 'newproblemfile' => 'New Resource', + 'newpagefile' => 'New Resource', + 'newsequencefile' => 'New Resource', + 'newrightsfile' => 'New Resource', + 'newstyfile' => 'New Resource', + 'newtaskfile' => 'New Resource', + 'newlibraryfile' => 'New Resource', + 'Select Action' => 'New Resource', + ); + if ($action{$env{'form.action'}}) { + if ($crsauthor) { + my @disallowed = qw(page sequence rights library); + my $newtype; + if ($env{'form.action'} =~ /^new(\w+)file$/) { + $newtype = $1; + } elsif ($env{'form.action'} eq 'newfile') { + ($newtype) = ($env{'form.newfilename'} =~ m{\.([^/.]+)$}); + $newtype = lc($newtype); + } + if (($newtype ne '') && + (grep(/^\Q$newtype\E$/,@disallowed))) { + $r->print('

' + .&mt('Creation of a new file of type: [_1] is not permitted in Course Authoring Space',$newtype) + .'

' + .&Apache::loncommon::end_page() + ); + return OK; + } + } + $r->print('

'.$action{$env{'form.action'}}.'

'); + } else { + $r->print('

' + .&mt('Unknown Action: [_1]',$env{'form.action'}) + .'

' + .&Apache::loncommon::end_page() + ); + return OK; + } + + if ($env{'form.phase'} eq 'two') { + &Debug($r, "loncfile::handler entering phase2"); + &phasetwo($r,$fn,$uname,$udom); + } else { + &Debug($r, "loncfile::handler entering phase1"); + &phaseone($r,$fn,$uname,$udom); + } - $r->print(''); - return OK; + $r->print(&Apache::loncommon::end_page()); + return OK; } 1;