--- loncom/publisher/loncfile.pm 2003/12/29 19:01:27 1.49 +++ loncom/publisher/loncfile.pm 2024/09/03 11:07:47 1.129.2.2 @@ -9,7 +9,7 @@ # and displays a page showing the results of the action. # # -# $Id: loncfile.pm,v 1.49 2003/12/29 19:01:27 www Exp $ +# $Id: loncfile.pm,v 1.129.2.2 2024/09/03 11:07:47 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -37,16 +37,16 @@ =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 + 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 @@ -68,11 +68,11 @@ 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::lonhtmlcommon; use Apache::lonlocal; +use LONCAPA qw(:DEFAULT :match); my $DEBUG=0; my $r; # Needs to be global for some stuff RF. @@ -88,31 +88,36 @@ my $r; # Needs to be global for some Parameters: =over 4 - + =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 true. - - if ($DEBUG) { - $r->log_reason($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").''
+ .''
+ .'
'.&mt('Warning: target file exists, and has been published!').'
'; - } elsif ( -e $construct) { - $result.=''.&mt('Warning: target file exists!').'
'; - } - return $result; + my ($user, $domain, $construct, $creating) = @_; + $creating ||= 'file'; + + 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.').'
'); + + } + + 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'; + 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. @@ -259,38 +346,79 @@ 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.= - ''.&mt('Warning: change of MIME type!').'
'; + ''.&mt('Warning: change of MIME type!').'>
'; } return $result; } sub cleanDest { - my ($request,$dest)=@_; + my ($dest,$subdir,$fn,$uname,$udom)=@_; #remove bad characters - if ($dest=~/[\#\?&]/) { - $request->print("".&mt('Invalid characters in requested name have been removed.')."
"); - $dest=~s/[\#\?&]//g; + 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.','','')
+ .'
' + .&mt('Invalid characters in requested name have been removed.') + .'
'; + } + return ($dest,$error,$warnings); } sub relativeDest { - my ($fn,$newfilename,$uname)=@_; + my ($fn,$newfilename,$uname,$udom)=@_; + my $error = ''; if ($newfilename=~/^\//) { # absolute, simply add path - $newfilename='/home/'.$uname.'/public_html/'; + my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; + $newfilename="$londocroot/res/$udom/$uname/"; } else { my $dir=$fn; - $dir=~s/\/[^\/]+$//; + $dir=~s{/[^/]+$}{}; $newfilename=$dir.'/'.$newfilename; } - $newfilename=~s://+:/:g; # remove duplicate / - while ($newfilename=~m:/\.\./:) { - $newfilename=~ s:/[^/]+/\.\./:/:g; #remove dir/.. + $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; + return ($newfilename,$error); } =pod @@ -312,10 +440,10 @@ Parameters: =cut sub CloseForm1 { - my ($request, $fn) = @_; - $request->print(''); - $request->print(''); + my ($request, $fn) = @_; + $request->print(''); + $request->print(' '); } @@ -335,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. @@ -344,21 +472,21 @@ Parameters: =cut sub CloseForm2 { - my ($request, $user, $fn) = @_; - $request->print(''.
+ &mt('Cannot change MIME type of a directory.').
+ ''.
+ '
'.&mt('Cancel').'
'.&mt('Rename').' '.&display($fn).
- '
to '.&display($newfilename).'?
'
+ .&mt('Cannot rename or move non-obsolete published file.')
+ .'
'
+ .''.&mt('Cancel').'
' + .&mt($action.' [_1] to [_2]?', + &display($fn), + &display($newfilename)) + .'
' + ); &CloseForm1($request, $fn); } else { - $request->print(''.&mt('No new filename specified.').'
'); + $request->print(''.&mt('No new filename specified.').'
'); return; } } else { - $request->print(''.&mt('No such file').': '.&display($fn).'
'); + $request->print('' + .&mt('No such file: [_1]', + &display($fn)) + .'
' + ); return; } - + } + =pod =item Delete1 @@ -440,7 +601,7 @@ 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. @@ -454,16 +615,46 @@ Parameters: =cut sub Delete1 { - my ($request, $user, $domain, $fn) = @_; + my ($request, $user, $domain, $fn) = @_; - if( -e $fn) { - $request->print(''); - $request->print(''.&mt('Delete').' '.&display($fn).'?
'); - &CloseForm1($request, $fn); - } else { - $request->print(''.&mt('No such file').': '.&display($fn).'
'); - } + 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('Cannot delete non-obsolete published file.')
+ .'
'
+ .''.&mt('Cancel').'
' + .&mt('Delete [_1]?', + &display($fn)) + .'
' + ); + &CloseForm1($request, $fn); + } else { + $request->print('' + .&mt('No such file: [_1]', + &display($fn)) + .'
' + ); + } } =pod @@ -478,7 +669,7 @@ 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. @@ -504,32 +695,52 @@ sub Copy1 { 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 $return=&exists($user, $domain, $newfilename); + my ($type,$return)=&exists($user, $domain, $newfilename); $request->print($return); - if ($return =~/^Error:/) { - $request->print(''.&mt('Copy').' '.&display($fn).'
to '.
- &display($newfilename).'?
' + .&mt('Copy [_1] to [_2]?', + &display($fn), + &display($newfilename)) + .'
' + ); &CloseForm1($request, $fn); } else { - $request->print(''.&mt('No such file').': '.&display($fn).'
'); + $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. @@ -547,7 +758,7 @@ Parameters: =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 @@ -565,36 +776,266 @@ causes the newdir operation to transitio =cut -sub NewDir1 -{ - my ($request, $username, $domain, $fn, $newfilename) = @_; - - my $result=&exists($username,$domain,$newfilename); - if ($result) { - $request->print(''.$result.''); - } else { - $request->print(''.&mt('Make new directory').' '. - &display($newfilename).'?
'); - &CloseForm1($request, $fn); - } +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').' '.&display($fn).'?
'); + 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').': '.&display($fn).'
'); - } + } else { + $request->print('' + .&mt('No such file: [_1]', + &display($fn)) + .'
' + ); + } +} + +sub Archive1 { + my ($request,$fn) = @_; + my @posstypes = qw(problem library sty sequence page task rights meta xml html xhtml htm xhtm css js tex txt gif jpg jpeg png svg other); + my (%location_of,%defaults); + my ($compstyle,$canarchive,$cancompress,$numformat,$numcompress,$defext) = + &archive_tools(\%location_of,\%defaults); + if (!$canarchive) { + $request->print(''. + &mt('This LON-CAPA instance does not seem to have either tar or zip installed.').'
'."\n". + ''. + &mt('At least one of the two is needed in order to be able to create an archive file for: [_1].', + &display($fn))."\n". + ''); + } elsif (-e $fn) { + $request->print(''."\n". + &Apache::lonhtmlcommon::start_pick_box(). + &Apache::lonhtmlcommon::row_title(&mt('Directory')). + &display($fn). + &Apache::lonhtmlcommon::row_closure(). + &Apache::lonhtmlcommon::row_title(&mt('Options'). + &Apache::loncommon::help_open_topic('Archiving_Directory_Options')). + ''. + ''. + ''."\n". + ''."\n". + ''."\n". + &Apache::lonhtmlcommon::row_closure(1). + &Apache::lonhtmlcommon::end_pick_box().'' + .&mt('No such directory: [_1]', + &display($fn)) + .'
' + ); + } + return; +} + +sub archive_tools { + my ($location_of,$defaults) = @_; + my ($compstyle,$canarchive,$cancompress,$numformat,$numcompress,$defext); + ($numformat,$numcompress) = (0,0); + if ((ref($location_of) eq 'HASH') && (ref($defaults) eq 'HASH')) { + foreach my $program ('tar','gzip','bzip2','xz','zip') { + foreach my $dir ('/bin/','/usr/bin/','/usr/local/bin/','/sbin/', + '/usr/sbin/') { + if (-x $dir.$program) { + $location_of->{$program} = $dir.$program; + last; + } + } + } + foreach my $format ('tar','zip') { + if (exists($location_of->{$format})) { + unless ($canarchive) { + $defext = $format; + $defaults->{$format} = ' checked="checked"'; + if ($format eq 'tar') { + $compstyle = 'block'; + } else { + $compstyle = 'none'; + } + } + $canarchive = 1; + $numformat ++; + } + } + foreach my $compress ('gzip','bzip2','xz') { + if (exists($location_of->{$compress})) { + $numcompress ++; + unless ($cancompress) { + if ($defext eq 'tar') { + if ($compress eq 'gzip') { + $defext .= '.gz'; + } elsif ($compress eq 'bzip2') { + $defext .= '.bz2'; + } else { + $defext .= ".$compress"; + } + } + $defaults->{$compress} = ' checked="checked"'; + $cancompress = 1; + } + } + } + } + if (wantarray) { + return ($compstyle,$canarchive,$cancompress,$numformat,$numcompress,$defext); + } else { + return $defext; + } } + +sub archive_in_progress { + my ($earlyout,$idnum); + if ($env{'cgi.author.archive'} =~ /^(\d+)_\d+_\d+$/) { + my $timestamp = $1; + $idnum = $env{'cgi.author.archive'}; + if (exists($env{'cgi.'.$idnum.'.archive'})) { + my $hashref = &Apache::lonnet::thaw_unescape($env{'cgi.'.$idnum.'.archive'}); + my $lonprtdir = $Apache::lonnet::perlvar{'lonPrtDir'}; + if (-e $lonprtdir.'/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$idnum.'.txt') { + $earlyout = $timestamp; + } elsif (ref($hashref) eq 'HASH') { + my $suffix = $hashref->{'extension'}; + if (-e $lonprtdir.'/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$idnum.$suffix) { + $earlyout = $timestamp; + } + } + unless ($earlyout) { + &Apache::lonnet::delenv('cgi.'.$idnum.'.archive'); + &Apache::lonnet::delenv('cgi.author.archive'); + } + } else { + &Apache::lonnet::delenv('cgi.author.archive'); + } + } + return ($earlyout,$idnum); +} + +sub cancel_archive_form { + my ($r,$title,$fname,$earlyout,$idnum) = @_; + $r->print(''.&mt('Make new file').' '.&display($newfilename).'?
'); + my ($type, $result)=&exists($user,$domain,$newfilename); + if ($type eq 'error') { + $request->print($warnings.$result); $request->print(''); - $request->print(''); - $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).
+ '
'. + '
'. + ''); + } 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('No new filename specified.').'
'); - } - } + 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(''.&mt('Return to Directory'). + '
'); + return; + } + $r->print('' + ); + } + } 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 'archive') { + if (($uname eq $env{'user.name'}) && ($udom eq $env{'user.domain'})) { + &Archive1($r,$fn); + } else { + $r->print('' + .&mt('Archiving of Authoring Spaces is only permitted by Author') + .'
' + ); + } + } 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 @@ -770,62 +1310,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) { - - 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').": ".&display($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. @@ -851,43 +1397,41 @@ Returns: =cut sub Delete2 { - my ($request, $user, $filename) = @_; - if(opendir DIR, $filename) { - my @files=readdir(DIR); - shift @files; shift @files; # takes off . and .. - if(@files) { - $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; - } + 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; + } } - return 1; + } else { + if(-e $filename) { + unless(unlink($filename)) { + $request->print(''.&mt('Error').': '.$!.''); + return 0; + } + } else { + $request->print(''.&mt('No such file').'
'); + return 0; + } + } + return 1; } =pod =item Copy2($request, $username, $dir, $oldfile, $newfile) - Performs phase 2 of a copy. The file is copied and the status + Performs phase 2 of a copy. The file is copied and the status of that copy is reported back to the user. =over 4 @@ -907,7 +1451,7 @@ sub Delete2 { =back -Returns 0 failure, and 0 successs. +Returns 0 failure, and 1 successs. =cut @@ -915,22 +1459,32 @@ sub Copy2 { my ($request, $username, $dir, $oldfile, $newfile) = @_; &Debug($request ,"Will try to copy $oldfile to $newfile"); if(-e $oldfile) { + if ($oldfile eq $newfile) { + $request->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(' '.&mt('copy 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 { - unless (chmod(0660, $newfile)) { - $request->print(' '.&mt('chmod error').': '.$!.''); - return 0; - } return 1; } } else { - $request->print(''.&mt('No such file').'
'); + $request->print(''.&mt('No such file').'
'); return 0; } return 1; } + =pod =item NewDir2($request, $user, $newdirectory) @@ -954,31 +1508,116 @@ Returns 0 - failure 1 - success. =cut sub NewDir2 { - 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; + 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; + 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; } + +sub Archive2 { + my ($r,$uname,$udom,$fn,$identifier) = @_; + my %options = ( + dir => $fn, + uname => $uname, + udom => $udom, + ); + if ($env{'form.adload'}) { + $options{'adload'} = 1; + if ($env{'form.archivefname'} ne '') { + $env{'form.archivefname'} =~ s{\.+}{.}g; + $options{'fname'} = $env{'form.archivefname'}; + } + if ($env{'form.archiveext'} ne '') { + $options{'extension'} = $env{'form.archiveext'}; + } + } + my @filetypes = qw(problem library sty sequence page task rights meta xml html xhtml htm xhtm css js tex txt gif jpg jpeg png svg other); + my (@include,%oktypes); + map { $oktypes{$_} = 1; } @filetypes; + my @posstypes = &Apache::loncommon::get_env_multiple('form.filetype'); + foreach my $type (@posstypes) { + if ($oktypes{$type}) { + push(@include,$type); + } + } + if (scalar(@include) == scalar(@filetypes)) { + $options{'types'} = 'all'; + } else { + $options{'types'} = join(',',@include); + } + if (exists($env{'form.recurse'})) { + $options{'recurse'} = 1; + } + if (exists($env{'form.encrypt'})) { + if ($env{'form.enckey'} ne '') { + $options{'encrypt'} = $env{'form.enckey'}; + } + } + $options{'format'} = 'tar'; + $options{'compress'} = 'gzip'; + if ((exists($env{'form.format'})) && $env{'form.format'} =~ /^zip$/i) { + $options{'format'} = 'zip'; + delete($options{'compress'}); + } elsif ((exists($env{'form.compress'})) && ($env{'form.compress'} =~ /^(xz|bzip2)$/i)) { + $options{'compress'} = lc($env{'form.compress'}); + } + my $key = 'cgi.'.$identifier.'.archive'; + my $storestring = &Apache::lonnet::freeze_escape(\%options); + &Apache::lonnet::appenv({$key => $storestring, + 'cgi.author.archive' => $identifier}); + return 1; +} + +sub Archive3 { + my ($hashref) = @_; + if (ref($hashref) eq 'HASH') { + if (($hashref->{'uname'} eq $env{'user.name'}) && + ($hashref->{'udom'} eq $env{'user.domain'}) && + ($env{'environment.canarchive'}) && + ($env{'form.delarchive'})) { + my $filesdest = $Apache::lonnet::perlvar{'lonPrtDir'}.'/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$env{'form.delarchive'}; + if (-e $filesdest) { + my $size = (stat($filesdest))[7]; + if (unlink($filesdest)) { + my ($identifier,$suffix) = split(/\./,$env{'form.delarchive'},2); + if (($identifier) && (exists($env{'cgi.'.$identifier.'.archive'}))) { + my $delres = &Apache::lonnet::delenv('cgi.'.$identifier.'.archive'); + if (($delres eq 'ok') && + (exists($env{'cgi.author.archive'})) && + ($env{'cgi.author.archive'} eq $identifier)) { + &Apache::lonnet::authorarchivelog($hashref,$size,$filesdest,'delete'); + &Apache::lonnet::delenv('cgi.author.archive'); + } + } + return 1; + } + } + } + } + return 0; +} + =pod -=item phasetwo($r, $fn, $uname, $udom) +=item phasetwo($r, $fn, $uname, $udom,$identifier) Controls the phase 2 processing of file management requests for construction space. In phase one, the user @@ -986,7 +1625,7 @@ sub decompress2 { 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: @@ -1009,202 +1648,497 @@ Parameters: =cut sub phasetwo { - my ($r,$fn,$uname,$udom)=@_; - + my ($r,$fn,$uname,$udom,$identifier)=@_; + &Debug($r, "loncfile - Entering phase 2 for $fn"); - - # Break down the file into it's component pieces. - + + # 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 - $main=$`; #This is what is before the match (.) so it's just the main filename, yea it's nasty - $suffix=$1; #This is the actually filename extension if it exists - } - 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'}); + } + 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 'decompress') { - $main .= '.'; - $main .= $suffix; - if(!&decompress2($r, $uname, $dir, $main)) { - return ; - } - $dest = $dir."/."; - - - } elsif ($ENV{'form.action'} eq 'rename') { # Rename. - if($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 'archive') { + if (($env{'environment.archive'}) && + ($env{'user.name'} eq $uname) && + ($env{'user.domain'} eq $udom)) { + &Archive2($r,$uname,$udom,$fn,$identifier); + } else { + $r->print(&mt('You do not have permission to export to an archive file in this Authoring Space')); + } + return; + } 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'})) { + if(!&Rename2($r, $uname, $dir, $fn, $env{'form.newfilename'})) { return; } - $dest = &url($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'})) { + } 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').'
'); + } + $dest = $env{'form.newfilename'}; + } else { + $r->print(''.&mt('No New filename specified').'
'); return; } - } elsif ($ENV{'form.action'} eq 'newdir') { - my $newdir= $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').''
+ .'
'.&Apache::lonhtmlcommon::confirm_success(&mt('Done')).'
' + .&Apache::lonhtmlcommon::actionbox( + [''.&mt('Return to Directory').'', + ''.$disp_newname.''])); + } else { + $r->print(&done($dest)); + } } - $r->print(''.&mt('Unknown Action').' '.$ENV{'form.action'}.'