File:  [LON-CAPA] / loncom / publisher / loncfile.pm
Revision 1.62: download - view: text, annotated - select for diffs
Tue Aug 24 21:21:41 2004 UTC (19 years, 7 months ago) by albertel
Branches: MAIN
CVS tags: version_1_2_X, version_1_2_1, version_1_2_0, HEAD
- move didn't actually work. Sigh (BUG#3368)

# The LearningOnline Network with CAPA
# Handler to rename files, etc, in construction space
#
#  This file responds to the various buttons and events
#  in the top frame of the construction space directory.
#  Each event is processed in two phases.  The first phase
#  presents a page that describes the proposed action to the user
#  and requests confirmation.  The second phase commits the action
#  and displays a page showing the results of the action.
#
#
# $Id: loncfile.pm,v 1.62 2004/08/24 21:21:41 albertel Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
=pod

=head1 NAME

Apache::loncfile - Construction space file management.

=head1 SYNOPSIS
 
 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 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
an "appropriate" directory listing in general.

    This is part of the LearningOnline Network with CAPA project
described at http://www.lon-capa.org.

=head2 Subroutines

=cut

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;

my $DEBUG=0;
my $r;				# Needs to be global for some stuff RF.

=pod

=item Debug($request, $message)

  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 setting the module global DEBUG variable to nonzero (TRUE).

 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);
    }
}

=pod

=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.
 Parameters:

=over 4

=item  Url    - string [in] The url to convert.
  
=back
  
 Returns:

=over 4

=item  The corresponding file system path. 

=back

Global References

=over 4

=item  $r      - Request object [in] Referenced in the &Debug calls.

=back

=cut

sub URLToPath {
    my $Url = shift;
    &Debug($r, "UrlToPath got: $Url");
    $Url=~ s/\/+/\//g;
    $Url=~ s/^http\:\/\/[^\/]+//;
    $Url=~ s/^\///;
    $Url=~ s/(\~|priv\/)(\w+)\//\/home\/$2\/public_html\//;
    &Debug($r, "Returning $Url \n");
    return $Url;
}

sub url {
    my $fn=shift;
    $fn=~s/^\/home\/(\w+)\/public\_html/\/priv\/$1/;
    $fn=&HTML::Entities::encode($fn,'<>"&');
    return $fn;
}

sub display {
    my $fn=shift;
    $fn=~s-^/home/(\w+)/public_html-/priv/$1-;
    return '<tt>'.$fn.'</tt>';
}


# 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 $published=$construct;
    $published=~
	s/^\/home\/$user\/public\_html\//\/home\/httpd\/html\/res\/$domain\/$user\//;
    if (-e $published) {
	if (&Apache::lonnet::metadata($published,'obsolete')) {
	    return 1;
	}
	return 0;
    } else {
	return 1;
    }
}



=pod

=item exists($user, $domain, $file)

   Determine if a resource file name 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  $domain - string [in] - Name of the domain in which the resource
                          might have been published.

=item  $file   - string [in] - Name of the file.

=back

Returns:

=over 4

=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, $construct) = @_;
    my $published=$construct;
    $published=~
	s/^\/home\/$user\/public\_html\//\/home\/httpd\/html\/res\/$domain\/$user\//;
    my $result='';    
    if ( -d $construct ) {
	return &mt('Error: destination for operation is an existing directory.');
    }
    if ( -e $published) {
	$result.='<p><font color="red">'.&mt('Warning: target file exists, and has been published!').'</font></p>';
    } elsif ( -e $construct) {
	$result.='<p><font color="red">'.&mt('Warning: target file exists!').'</font></p>';
    }
    return $result;
}

=pod

=item checksuffix($old, $new)
        
  Determine if a resource filename suffix (the stuff after the .) would change
as a result of this operation.

 Parameters:

=over 4

=item  $old   = string [in]  Previous filename.

=item  $new   = string [in]  Resultant filename.

=back

 Returns:

=over 4

=item    Empty string if everything worked.

=item    String containing an error message if there was a problem.

=back

=cut

sub checksuffix {
    my ($old,$new) = @_;
    my $result;
    my $oldsuffix;
    my $newsuffix;
    if ($new=~m:(.*/*)([^/]+)\.(\w+)$:) { $newsuffix=$3; }
    if ($old=~m:(.*)/+([^/]+)\.(\w+)$:) { $oldsuffix=$3; }
    if ($oldsuffix ne $newsuffix) {
	$result.=
            '<p><font color="red">'.&mt('Warning: change of MIME type!').'</font></p>';
    }
    return $result;
}

sub cleanDest {
    my ($request,$dest,$subdir)=@_;
    #remove bad characters
    my $foundbad=0;
    if ($subdir && $dest =~/\./) {
	$foundbad=1;
	$dest=~s/\.//g;
    }
    if  ($dest=~/[\#\?&%\"]/) {
	$foundbad=1;
	$dest=~s/[\#\?&%\"]//g;
    }
    if ($foundbad) {
	$request->print("<p><font color=\"red\">".&mt('Invalid characters in requested name have been removed.')."</font></p>");
    }
    return $dest;
}

sub relativeDest {
    my ($fn,$newfilename,$uname)=@_;
    if ($newfilename=~/^\//) {
# absolute, simply add path
	$newfilename='/home/'.$uname.'/public_html/';
    } else {
	my $dir=$fn;
	$dir=~s/\/[^\/]+$//;
	$newfilename=$dir.'/'.$newfilename;
    }
    $newfilename=~s://+:/:g; # remove duplicate /
    while ($newfilename=~m:/\.\./:) {
	$newfilename=~ s:/[^/]+/\.\./:/:g; #remove dir/..
    }
    return $newfilename;
}

=pod

=item CloseForm1($request, $user, $file)

   Close of a form on the successful completion of phase 1 processing

Parameters:

=over 4

=item  $request - Apache Request Object [in] - Apache server request object.

=item  $cancelurl - the url to go to on cancel.

=back

=cut

sub CloseForm1 {
    my ($request,  $fn) = @_;
    $request->print('<p><input type="submit" value="'.&mt('Continue').'" /></p></form>');
    $request->print('<form action="'.&url($fn).
		    '" method="POST"><p><input type="submit" value="'.&mt('Cancel').'" /></p></form>');
}


=pod

=item CloseForm2($request, $user, $directory)

   Successfully close off the phase 2 form.

Parameters:

=over 4

=item   $request    - Apache Request object [in] - The request that is being
                 executed.

=item   $user       - string [in] - Name of the user that is initiating the
                 request.

=item   $directory  - string [in] - Directory in which the operation is 
                 being done relative to the top level construction space
                 directory.

=back

=cut

sub CloseForm2 {
    my ($request, $user, $fn) = @_;
    $request->print('<h3><a href="'.&url($fn).'/">'.&mt('Done').'</a></h3>');
}

=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 
current request.

=item  $filename  - The filename relative to construction space.

=item  $user      - Name of the user making the request.

=item  $domain    - User login domain.

=item  $dir       - Directory specification of the path to the file.

=back

Side effects:

=over 4

=item A new form is displayed prompting for confirmation.  The newfilename
hidden field of this form is loaded with
new filename relative to the current directory ($dir).

=back

=cut  

sub Rename1 {
    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('<br /><font color="red">'.
				    &mt('Cannot change MIME type of a directory').
				    '</font>'.
				    '<br /><a href="'.&url($fn).'">'.&mt('Cancel').'</a>');
		    return;
		}
		$newfilename=~s/\/[^\/]+\/([^\/]+)$/\/$1/;
	    }
	    $newfilename=~s://+:/:g; # remove duplicate /
	    while ($newfilename=~m:/\.\./:) {
		$newfilename=~ s:/[^/]+/\.\./:/:g; #remove dir/..
	    }
	    my $return=&exists($user, $domain, $newfilename);
	    $request->print($return);
	    if ($return =~/^Error:/) {
		$request->print('<br /><a href="'.&url($fn).'">'.&mt('Cancel').'</a>');
		return;
	    }
	    unless (&obsolete_unpub($user,$domain,$fn)) {
		$request->print('<h3>'.&mt('Cannot rename or move non-obsolete published file').'</h3>'.
				'<br /><a href="'.&url($fn).'">'.&mt('Cancel').'</a>');
		return;
	    }
	    my $action;
	    if ($style eq 'rename') {
		$action=&mt('Rename');
	    } else {
		$action=&mt('Move');
	    }
	    $request->print('<input type="hidden" name="newfilename" value="'.
			    $newfilename.
			    '" /><p>'.$action.' '.&display($fn).
			    '</tt><br />to '.&display($newfilename).'?</p>');
	    &CloseForm1($request, $fn);
	} else {
	    $request->print('<p>'.&mt('No new filename specified.').'</p></form>');
	    return;
	}
    } else {
	$request->print('<p> '.&mt('No such file').': '.&display($fn).'</p></form>');
	return;
    }
    
}

=pod

=item Delete1

   Performs phase 1 processing of the delete operation.  In phase one
  we just check to be sure the file exists.

Parameters:

=over 4

=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   $filename  - string [in]  Source filename.

=back

=cut

sub Delete1 {
    my ($request, $user, $domain, $fn) = @_;

    if( -e $fn) {
	$request->print('<input type="hidden" name="newfilename" value="'.
			$fn.'"/>');
	unless (&obsolete_unpub($user,$domain,$fn)) {
	    $request->print('<h3>'.&mt('Cannot delete non-obsolete published file').'</h3>'.
			    '<br /><a href="'.&url($fn).'">'.&mt('Cancel').'</a>');
	    return;
	}
	$request->print('<p>'.&mt('Delete').' '.&display($fn).'?</p>');
	&CloseForm1($request, $fn);
    } else {
	$request->print('<p>'.&mt('No such file').': '.&display($fn).'</p></form>');
    }
}

=pod

=item Copy1($request, $user, $domain, $filename, $newfilename)

   Performs phase 1 processing of the construction space copy command.
   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 
                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   $fn  - string [in]  Source filename.

=item   $newfilename-string [in]  Destination filename.

=back

=cut

sub Copy1 {
    my ($request, $user, $domain, $fn, $newfilename) = @_;

    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 $return=&exists($user, $domain, $newfilename);
	$request->print($return);
	if ($return =~/^Error:/) {
	    $request->print('<br /><a href="'.&url($fn).'">'.&mt('Cancel').'</a>');
	    return;
	}
	$request->print('<input type="hidden" name="newfilename" value="'.
			$newfilename.
			'" /><p>'.&mt('Copy').' '.&display($fn).'<br />to '.
			&display($newfilename).'?</p>');
	&CloseForm1($request, $fn);
    } else {
	$request->print('<p>'.&mt('No such file').': '.&display($fn).'</p></form>');
    }
}

=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.

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 - Domain user is in

=item   $fn     - source file.

=item   $newdir   - Name of the directory to be created; path relative to the 
               top level of construction space.
=back

Side Effects:

=over 4

=item A new form is displayed.  Clicking on the confirmation button
causes the newdir operation to transition into phase 2.  The hidden field
"newfilename" is set with the construction space path to the new directory.


=back

=cut


sub NewDir1 {
    my ($request, $username, $domain, $fn, $newfilename, $mode) = @_;

    my $result=&exists($username,$domain,$newfilename);
    if ($result) {
	$request->print('<font color="red">'.$result.'</font></form>');
    } else {
	if ($mode eq 'testbank') {
	    $request->print('<input type="hidden" name="callingmode" value="testbank">');
	} elsif ($mode eq 'imsimport') {
	    $request->print('<input type="hidden" name="callingmode" value="imsimport">');
	}
	$request->print('<input type="hidden" name="newfilename" value="'.
			$newfilename.'" /><p>'.&mt('Make new directory').' '.
			&display($newfilename).'?</p>');
	&CloseForm1($request, $fn);
    }
}


sub Decompress1 {
    my ($request, $user, $domain, $fn) = @_;
    if( -e $fn) {
   	$request->print('<input type="hidden" name="newfilename" value="'.$fn.'"/>');
   	$request->print('<p>'.&mt('Decompress').' '.&display($fn).'?</p>');
   	&CloseForm1($request, $fn);
    } else {
	$request->print('<p>'.&mt('No such file').': '.&display($fn).'</p></form>');
    }
}

=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 file name

=item   $newfilename
                  - Name of the file to be created; no path information
=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 driectory listing you came from

=back

=cut

sub NewFile1 {
    my ($request, $user, $domain, $fn, $newfilename) = @_;

    if ($ENV{'form.action'} =~ /new(.+)file/) {
	my $extension=$1;

        ##Informs User (name).(number).(extension) not allowed 
	if($newfilename =~ /\.(\d+)\.(\w+)$/){
	    $r->print('<font color="red">'.$newfilename.
		      ' - '.&mt('Bad Filename').'<br />('.&mt('name').').('.&mt('number').').('.&mt('extension').')'.
		      ' '.&mt('Not Allowed').'</font>');
	    return;
	}
	if ($newfilename !~ /\Q.$extension\E$/) {
	    if ($newfilename =~ m|^[^\.]*\.([^\.]+)$|) {
		#already has an extension strip it and add in expected one
		$newfilename =~ s|.([^\.]+)$||;
	    }
	    $newfilename.=".$extension";
	}
    }
    my $result=&exists($user,$domain,$newfilename);
    if($result) {
	$request->print('<font color="red">'.$result.'</font></form>');
    } else {
	$request->print('<p>'.&mt('Make new file').' '.&display($newfilename).'?</p>');
	$request->print('</form>');
	$request->print('<form action="'.&url($newfilename).
			'" method="POST"><p><input type="submit" value="'.&mt('Continue').'" /></p></form>');
	$request->print('<form action="'.&url($fn).
			'" method="POST"><p><input type="submit" value="'.&mt('Cancel').'" /></p></form>');
    }
}

=pod

=item phaseone($r, $fn, $uname, $udom)

  Peforms phase one processing of the request.  In phase one, error messages
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 
performed and reported to the user.

 Parameters:

=over 4

=item $r  - request object [in] - The Apache request being executed.

=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 name under which the user logged in. 

=back

=cut

sub phaseone {
    my ($r,$fn,$uname,$udom)=@_;
  
    my $doingdir=0;
    if ($ENV{'form.action'} eq 'newdir') { $doingdir=1; }
    my $newfilename=&cleanDest($r,$ENV{'form.newfilename'},$doingdir);
    $newfilename=&relativeDest($fn,$newfilename,$uname);
    $r->print('<form action="/adm/cfile" method="post">'.
	      '<input type="hidden" name="qualifiedfilename" value="'.$fn.'" />'.
	      '<input type="hidden" name="phase" value="two" />'.
	      '<input type="hidden" name="action" value="'.$ENV{'form.action'}.'" />');
  
    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('<p>'.&mt('No new filename specified.').'</p></form>');
	}
    } elsif ($ENV{'form.action'} eq 'newdir') {
	my $mode = '';
	if (exists($ENV{'form.callingmode'}) ) {
	    $mode = $ENV{'form.callingmode'};
	}   
	&NewDir1($r, $uname, $udom, $fn, $newfilename, $mode);
    }  elsif ($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 'Select Action') {
	if ($newfilename) {
	    &NewFile1($r, $uname, $udom, $fn, $newfilename);
	} else {
	    $r->print('<p>'.&mt('No new filename specified.').'</p></form>');
	}
    }
}

=pod

=item Rename2($request, $user, $directory, $oldfile, $newfile)

Performs phase 2 processing of a rename reequest.   This is where the
actual rename is performed.

Parameters

=over 4

=item $request - Apache request object [in] The request being processed.

=item $user  - string [in] The name of the user initiating the request.

=item $directory - string [in] The name of the directory relative to the
                 construction space top level of the renamed file.

=item $oldfile - Name of the file.

=item $newfile - Name of the new file.

=back

Returns:

=over 4

=item 1 Success.

=item 0 Failure.

=cut

sub Rename2 {

    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('<font color="red">'.&mt('Error').': '.$!.'</font>');
	    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("<p> ".&mt('No such file').": ".&display($oldfile).'</p></form>');
	return 0;
    }
    return 1;
}

=pod

=item Delete2($request, $user, $filename)

  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.

Parameters:

=over 4

=item $request - Apache Request object [in] the request object for the current
                 delete operation.

=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.

=back

Returns:
  1 - success.
  0 - Failure.

=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('<font color="red"> '.&mt('Error: Directory Non Empty').'</font>'); 
	    return 0;
	} else {   
	    if(-e $filename) {
		unless(rmdir($filename)) {
		    $request->print('<font color="red">'.&mt('Error').': '.$!.'</font>');
		    return 0;
		}
	    } else {
		$request->print('<p> '.&mt('No such file').'. </p></form>');
		return 0;
	    }
	}
    } else {
	if(-e $filename) {
	    unless(unlink($filename)) {
		$request->print('<font color="red">'.&mt('Error').': '.$!.'</font>');
		return 0;
	    }
	} else {
	    $request->print('<p> '.&mt('No such file').'. </p></form>');
	    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 
   of that copy is reported back to the user.

=over 4

=item $request - Apache request object [in]; the apache request currently
                 being executed.

=item $username - string [in] Name of the user who is requesting the copy.

=item $dir - string [in] Directory path relative to the construction space
             of the destination file.

=item $oldfile - string [in] Name of the source file.

=item $newfile - string [in] Name of the destination file.


=back

Returns 0 failure, and 0 successs.

=cut

sub Copy2 {
    my ($request, $username, $dir, $oldfile, $newfile) = @_;
    &Debug($request ,"Will try to copy $oldfile to $newfile");
    if(-e $oldfile) {
	unless (copy($oldfile, $newfile)) {
	    $request->print('<font color="red"> '.&mt('copy Error').': '.$!.'</font>');
	    return 0;
	} elsif (!chmod(0660, $newfile)) {
	    $request->print('<font color="red"> '.&mt('chmod error').': '.$!.'</font>');
	    return 0;
	} elsif (-e $oldfile.'.meta' && 
		 !copy($oldfile.'.meta', $newfile.'.meta') &&
		 !chmod(0660, $newfile.'.meta')) {
	    $request->print('<font color="red"> '.&mt('copy metadata error').
			    ': '.$!.'</font>');
	    return 0;
	} else {
	    return 1;
	}
    } else {
	$request->print('<p> '.&mt('No such file').' </p>');
	return 0;
    }
    return 1;
}

=pod

=item NewDir2($request, $user, $newdirectory)

	Performs phase 2 processing of directory creation.  This involves creating the directory and
	reporting the results of that creation to the user.
	
Parameters:
=over 4

=item $request  - Apache request object [in].  Object representing the current HTTP request.

=item $user - string [in] The name of the user that is initiating the request.

=item $newdirectory - string [in] The full path of the directory being created.

=back

Returns 0 - failure 1 - success.

=cut

sub NewDir2 {
    my ($request, $user, $newdirectory) = @_;
  
    unless(mkdir($newdirectory, 02770)) {
	$request->print('<font color="red">'.&mt('Error').': '.$!.'</font>');
	return 0;
    }
    unless(chmod(02770, ($newdirectory))) {
	$request->print('<font color="red"> '.&mt('Error').': '.$!.'</font>');
	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

=item phasetwo($r, $fn, $uname, $udom)

   Controls the phase 2 processing of file management
   requests for construction space.  In phase one, the user
   was asked to confirm the operation.  In phase 2, the operation
   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 
  phase 2 processing.

Parameters:

=over 4

=item  $r     - Apache Request object [in] The request object for this httpd
           transaction.

=item  $fn    - string [in]  A filename indicating the object that is being
           manipulated.

=item  $uname - string [in] The name of the user initiating the file management
           request.

=item  $udom  - string  [in] The login domain of the user initiating the
           file management request.
=back

=cut

sub phasetwo {
    my ($r,$fn,$uname,$udom)=@_;
    
    &Debug($r, "loncfile - Entering phase 2 for $fn");
    
    # Break down the file into it's 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'});

    my $conspace=$fn;
    
    &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' ||
	     $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;
	    }
	    $dest = $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('<p>'.&mt('No New filename specified').'</p></form>');
	    return;
	}
	
    } elsif ($ENV{'form.action'} eq 'newdir') {
        my $newdir= $ENV{'form.newfilename'};
	if(!&NewDir2($r, $uname, $newdir)) {
	    return;
	}
	$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('<h3><a href="javascript:self.close()">'.&mt('Done').'</a></h3>');
    } else {
	$r->print('<h3><a href="'.&url($dest).'">'.&mt('Done').'</a></h3>');
    }
}

sub handler {

    $r=shift;

    &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['decompress','action','filename','newfilename']);

    &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;

    if ($ENV{'form.filename'}) {
	&Debug($r, "test: $ENV{'form.filename'}");
	$fn=&Apache::lonnet::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=&Apache::lonnet::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;
    }


    &Apache::loncommon::content_type($r,'text/html');
    $r->send_http_header;

    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'};
	$r->print('<html><head><title>LON-CAPA Construction Space</title><script language="Javascript">');
	$r->print(qq|
function writeDone() {
    var winName = window.opener
    window.focus();
    winName.document.dataForm.newdir.value = "$newdirname"
    setTimeout("self.close()",10000)
}
  </script>
  </head>|);
	my $loaditem = 'onLoad="writeDone()"';
	$r->print(&Apache::loncommon::bodytag('Construction Space File Operation','',$loaditem));
    } else {
	$r->print('<html><head><title>LON-CAPA Construction Space</title></head>');
	$r->print(&Apache::loncommon::bodytag('Construction Space File Operation'));
    }

  
    $r->print('<h3>'.&mt('Location').': '.&display($fn).'</h3>');
  
    if (($uname ne $ENV{'user.name'}) || ($udom ne $ENV{'user.domain'})) {
	$r->print('<h3><font color="red">'.&mt('Co-Author').': '.$uname.' at '.$udom.
		  '</font></h3>');
    }


    &Debug($r, "loncfile::handler Form action is $ENV{'form.action'} ");
    if ($ENV{'form.action'} eq 'delete') {
      	$r->print('<h3>'.&mt('Delete').'</h3>');
    } elsif ($ENV{'form.action'} eq 'rename') {
	$r->print('<h3>'.&mt('Rename').'</h3>');
    } elsif ($ENV{'form.action'} eq 'move') {
	$r->print('<h3>'.&mt('Move').'</h3>');
    } elsif ($ENV{'form.action'} eq 'newdir') {
	$r->print('<h3>'.&mt('New Directory').'</h3>');
    } elsif ($ENV{'form.action'} eq 'decompress') {
	$r->print('<h3>'.&mt('Decompress').'</h3>');
    } elsif ($ENV{'form.action'} eq 'copy') {
	$r->print('<h3>'.&mt('Copy').'</h3>');
    } elsif ($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 'Select Action' ) {
	$r->print('<h3>'.&mt('New Resource').'</h3>');
    } else {
	$r->print('<p>'.&mt('Unknown Action').' '.$ENV{'form.action'}.' </p></body></html>');
	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('</body></html>');
    return OK;  
}

1;
__END__


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>