"Fossies" - the Fresh Open Source Software archive

Member "SiteMgrYAP/cgi-bin/smgryap.cgi" of archive SiteMgrYAP-0.2.0.tar.gz:


#!/usr/bin/perl

# SiteMgr -- A web site file manager
#            Copyright 1996-7 Sanford Morton. See
#                 http://www.halcyon.com/sanford/cgi/copying.html
#            for copying permissions. See
#                 http://www.halcyon.com/sanford/cgi/sitemgr/
#            for instructions and discussion.

# SiteMgr 0.1.2
#           Copyright 1998-2000 Jose Manuel Macias. macias@cica.es
#
#            Some patches to original version, including:
#                - password and user address authentication
#                - support for multiple users/directories
#

use CGI;
use File::Copy;
use strict;

no strict 'vars';

require "/home/httpd/secure/sitemgr.conf"; 

my ($q, $script_url, $top_dir, $top_fs_dir, $target_item, $user, $crpass, $current_dir, $target_dir, $prev_fs_dir, $target_fs_dir, $errMsg );

#, $DocumentRoot, $SiteMgrURL, $AuthSiteMgrURL, $UploadURL, $HostName); 


# use cgidebug;

$q = new CGI;

### INITIALIZATION --
### Find out who and where we are.
### We won't browse or write above the top directory.
#++ We use $top_dir=UserDir (from auth. script) and
#++        $top_fs_dir=DocumentRoot + UserDir

$script_url = $ENV{'SCRIPT_NAME'};

$top_dir = $q->param('top_dir') if( $q->param('top_dir') );      # from authsmgr.cgi

$top_fs_dir = $DocumentRoot . $top_dir if( $q->param('top_dir') );

$user =  $q->param('user') if $q->param('user');
$crpass =  $q->param('crpass') if $q->param('crpass');

# some servers do not report this

$ENV{'SCRIPT_FILENAME'} = $0 unless $ENV{'SCRIPT_FILENAME'};

### set initial defaults
#++ added default for $target_fs_dir

$target_dir =  $top_dir;
$target_fs_dir = $top_fs_dir;
$errMsg = '';

### Many form requests will supply a current directory and target
### item, both full paths.

$target_item = $q->param('item') if $q->param('item');
$current_dir = $q->param('dir') if $q->param('dir');

my $operation = "";
$operation = $q->param('operation') if ($q->param('operation'));

### SOME SECURITY.
### If the referring url is not this script, then we refuse to
### process requests; display the default top level page instead.
#++ Referring url can be auth. script too
#++ I included inside this 'if' the directory index request.


if( $ENV{'HTTP_REFERER'} eq ""){          # HTTP_REFERER missing
  
  $errMsg = "<dt><h2><font color=#FF0000>Serious error:</font></h2>
  <dd>SiteMgr will not accept queries from forms differents than 
  the autentication form. You must use it for loging into the system.";
  &print_web_page ($user,$crpass,$DocumentRoot ,$script_url, $prev_fs_dir, $top_fs_dir, $target_fs_dir, $errMsg,$operation);
  exit;
  }else{                                    # HTTP_REFERER ok, but we need check if it is a valid one ...
  
  if( $operation eq "NO_OP" ){                  # No operation but a directory listing ...
    
# here we look for a valid HTTP_REFERER
    
    if ( ($ENV{'HTTP_REFERER'} ne $SiteMgrURL) && ($ENV{'HTTP_REFERER'} ne $AuthSiteMgrURL) && ($ENV{'HTTP_REFERER'} ne $UploadURL)){
      $errMsg = "<dt><h2><font color=#FF0000>Serious error:</font></h2>
      <dd>SiteMgr will not accept requests from forms different 
      from itself or the authentication form.
      You must use this page or the authentication form for accesing 
      your account.";
    }
    
#	if no change made ...
    
    $target_fs_dir = $DocumentRoot . $current_dir if( $current_dir );
    
# if subdir button pressed
    
    $target_dir .= "/" . $q->param('subdir') if($q->param('subdir'));
    $target_fs_dir .= "/" . $q->param('subdir') if $q->param('subdir');
    
# if 'previous dir' button dir pressed
    
    $target_fs_dir = $q->param('parent_dir') if $q->param('prevdir');
    
# previous dir values
    
    $prev_fs_dir = $top_fs_dir;
    $prev_fs_dir = $target_fs_dir if $q->param('subdir');
    
    &print_web_page ($user,$crpass,$DocumentRoot ,$script_url, $prev_fs_dir, $top_fs_dir, $target_fs_dir, $errMsg,$operation);
    exit;
    }else{                                   # An operation and after, directory listing ...
    for ($q->param('operation')) {
      
###
###  Edit request:
###
      /^EDIT$/ and do {
        
# Normally, &print_edit_page will exit the script, but
# not if error messages are returned.
        
#	$target_fs_dir = $DocumentRoot . $current_dir if( $current_dir );
        
        unless ($errMsg = &validate_item ($DocumentRoot, $top_fs_dir, $target_item)) {
          $errMsg = &print_edit_page ($user,$crpass,$DocumentRoot,$current_dir,$target_item);
        }
        last;
      };
      
      
###
### Save an edited file:
### generated from the edit page,
      /^Save changes$/ and do {
        
        unless ($errMsg = &validate_item ($DocumentRoot, $top_fs_dir, $target_item)) {
          $errMsg = &save_changes ($q->param('text'), $DocumentRoot , $target_item );
        }
        
# set target dir from url
        
        ($target_dir = $target_item) =~ s#/[^/]+$##;
#$target_dir =  $current_dir if( $current_dir );
        
        last;
      };
      
###
### Preview an edited file
### generated from the edit page
      /^Preview changes$/ and do {
        
# Normally this will exit, unless there is an error message
        $errMsg = &preview_changes ($q->param('text'), $DocumentRoot , $target_item );
        last;
      };
      
      
###
### Delete a file or directory
###
      /^DELETE$/ and do {
        
        unless ($errMsg = &validate_item ($DocumentRoot, $top_fs_dir, $target_item)) {
          $errMsg = &delete_item (  $DocumentRoot, $target_item);
        }
        last;
      };
      
      
###
### Copy
###
      /^COPY$/ and do {
        
# validate the old and new names;
# the first error, if any, should short circuit
        $errMsg = &validate_new_url($top_fs_dir,  $DocumentRoot . $q->param('newName'))
        or $errMsg = &validate_item( $DocumentRoot, $top_fs_dir, $target_item)
        or $errMsg = &move_or_copy ( $DocumentRoot, $target_item, $q->param('newName'), "cp");
        
        last;
      };
      
###
### Move
###
      /^MOVE$/ and do {
        
# validate the old and new names;
# the first error, if any, should short circuit
        $errMsg = &validate_new_url($top_fs_dir, $DocumentRoot . $q->param('newName'))
        or $errMsg = &validate_item($DocumentRoot, $top_fs_dir, $target_item)
        or $errMsg = &move_or_copy ( $DocumentRoot , $target_item, $q->param('newName'), "mv");
        last;
      };
      
      
###
### Create a new file in the current directory
###
      
      /^CREATE$/ and do {
        
        $errMsg = &validate_new_url($top_fs_dir, $DocumentRoot . $q->param('newName'))
        or $errMsg = &create_file_or_dir('file', $DocumentRoot , $q->param('newName'))
        or $errMsg = &print_edit_page ($user,$crpass,$DocumentRoot,$target_fs_dir,$q->param('newName'));
        last;
      };
      
      
###
### Create a new directory
###
      
      /^MKDIR$/ and do {
        
        $errMsg = &validate_new_url($top_fs_dir, $DocumentRoot . $q->param('newName'))
        or $errMsg = &create_file_or_dir('dir', $DocumentRoot , $q->param('newName'));
        last;
      };
      
      
      
###
### Upload a file
###
#++ TODO: multiple upload
      
      /^Upload file$/ and do {
        
        my $upload_dir = $top_dir;
        $upload_dir = $current_dir if $current_dir;
        
        my ($remoteUploadName) = $q->param('remoteUploadName');
        my ($newUploadName) =  $q->param('newUploadName');
        
        unless ($remoteUploadName and $newUploadName) {
          $errMsg = "<dt><font color=#FF0000><h2>Previous action failed:</h2></font><dd>You must select a file for uploading <i>and</i> give a new name for the file uploaded.";
          last;
        }

        unless ($errMsg = &validate_new_url($top_fs_dir, $DocumentRoot . "$newUploadName")) {
          
          my ($tmpFileName) = $q->tmpFileName($remoteUploadName);
          $errMsg = &upload_file($DocumentRoot,$newUploadName, $tmpFileName);
        }
        last;
      };
      
    }            ### end of switch on 'operation'
    
###
### All that's left is to print the web page
###
### Target directory has been initialized to top directory.
### Set it to current dir if it exists and validate it.
    
    $target_fs_dir = $DocumentRoot . $current_dir if( $current_dir );
    $prev_fs_dir = $top_fs_dir;
    
    
    if ($current_dir) {
      $target_fs_dir = $DocumentRoot . $current_dir if( $current_dir );
      $prev_fs_dir = $target_fs_dir;
    }
    
    &print_web_page ( $user,$crpass, $DocumentRoot ,$script_url, $prev_fs_dir, $top_fs_dir, $target_fs_dir, $errMsg,$operation);
    
    
  };  ### end else
  
} ### end if



###
### PROCESS REQUESTS
#
#++ Directory index requests are processed above, here we process
#++ file operations ...


###
### Process requests for file operations.
### This is a switch statement over the 'operation' form tag
###


###############################################

###
### End main body of script
###
### Subroutines follow:

################################################

sub translate_url2fs {
# Translates a url path (without the http://domain.name part)
# to a file system path
# If a scalar (a single url) ) is the only argument, then a scalar
# is returned. If a list of urls are submitted, then a list is returned.
# If error, this subroutine (actually &get_prefix) returns a web page and dies.
  
  my @urls = @_;
  my @fs;
  
# get fs and url path prefixes
# error checking inside &get_prefix
  
  my ($fs_prefix, $url_prefix) = &get_prefix;
  
  foreach (@urls) {
    print "modificando: $_\n\n";
    s/$url_prefix// if $url_prefix;        # $url_prefix may be empty
    $_ = $fs_prefix . $_;
#if prefix exists ...
    push @fs, $_;
    print "modificada: $_\n\n";
  }
  
  return $fs[0] if @fs ==1;
  return @fs;
  
}

sub get_prefix {
# returns ($fs_prefix, $url_prefix)
# the differences between a url path and a fs path
# return web page and die on failure
  
  my ($url_path,$fs_path) = ($ENV{'SCRIPT_NAME'}, $ENV{'SCRIPT_FILENAME'});
  my ($fs_prefix) = '';
  
# try to match one inside the other, if so remove it !!!
  while (! ($url_path =~ s/$fs_path$//) ) {
    
# chop off first directory from front of fs path and save it,
    unless ( $fs_path =~ s/(^\/[^\/]+)// ) {
# if we have run out of path, return web page and die
      print "Content-type: text/html\n\n
      <h1>Internal error: prefix not found.</h1>
      There is an error (prefixes to a path).
      No change was made for this page. Please, report this error and
      the following information to the webmaster. Thanks.
      <ul><li>fs_prefix: $fs_prefix<li>\$1: $1<li>url_path: $url_path
      <li>SCRIPT_NAME: $ENV{'SCRIPT_NAME'}
      <li>SCRIPT_FILENAME: $ENV{'SCRIPT_FILENAME'}</ul>Environment variables:<ul>";
      foreach (keys %ENV) {
        print "<li>$_: $ENV{$_}\n";
      }
      print "</ul>";
      exit;
    }
    
    $fs_prefix .= $1;
  }
  
# url path is now a prefix
  return ($fs_prefix, $url_path);
}

#################################################
sub validate_new_url {
# performs various checks on a new file or directory name
# we don't check for previous existence of new name,
# to allow mv or copy to overwrite
# supplied as part of an action
# returns error message if not ok
# new_url must be a full url path
  
  my ($top_url_dir, $new_url) = @_;

  my $absolute_top_url_dir = $top_url_dir . "\/";
  
# check that a new name is supplied
  unless ($new_url) {
    return "<dt><font color=#FF0000><h2>Previous action failed:</h2></font>\n<dd>name for file or directory not given.";
  }
  
# sanitize the name to prevent shell escapes
  if ($new_url =~ /[^\w-~\/\.]/) {
    return "<dt><font color=#FF0000><h2>Previous action failed:</h2></font>\n<dd>The path and valid names can be\n letters, numbers and the following characters:\n  _ - ~ / \. and without blank spaces.\n Please, supply a new name.";
  }
  
# check that new path is within web site
  unless ($new_url =~ /^$absolute_top_url_dir/) {
    return "<dt><font color=#FF0000><h2>Previous action failed:</h2></font><dd>Given path to file is not permitted for you. Please, supply a new name.";
  }
  
# disallow double-dots (/../) in path
  if ($new_url =~ m@/\.\./@) {
    return "<dt><font color=#FF0000><h2>Previous action failed:</h2></font> <dd>Path must not contain two  dots (..) for referring to a directory above. Please, supply a path with correct names.";
  }
  
  
# all ok, return empty error message
  return '';
}

###################################################

sub validate_item {
# perform various checks on an item selected from the directory index
# returns error message if not ok
  
  my ($doc_root, $top_url_dir, $url_item) = @_;  # top first in case url_item is empty
  
# translate to file system paths
  
  my $fs_item = $doc_root . $url_item;
  my $top_fs_dir = $top_url_dir;
  my $absolute_top_fs_dir = $top_url_dir ; 
  
# check that a $url_item has been selected
  unless ($url_item) {
    return "<dt><font color=#FF0000><h2>Previous action failed:</h2></font><dd>You must select a file or directory from the list.";
  }
  
# Check that the item is within the web site.
# This shouldn't happen unless someone is pointing their own form here
# which also shouldn't happen -- but just to be safe...
  unless ($fs_item =~ /^$absolute_top_fs_dir/) {
    return "<dt><font color=#FF0000><h2>Previous action failed:</h2></font><dd>Selected item from directory, $url_item, is not valid.";
  }
  
# disallow double-dots (/../) in path
  if ($url_item =~ m@/\.\./@) {
    return "<dt><font color=#FF0000><h2>Previous action failed:</h2></font> <dd>Path must not contain two  dots (..) for referring to a directory above. Please, supply a path with correct names.";
  }
  
# check for existence and read/write permissions
  return"<dt><font color=#FF0000><h2>Previous action failed:</h2></font> <dd>Selected item from directory, $url_item, doesn't exist."  unless -e $fs_item;
  
  return"<dt><font color=#FF0000><h2>Previous action failed:</h2></font> <dd>Selected item from directory, $url_item, can't be read by <i>SiteMgr</i>." unless -r $fs_item;
  
  return"<dt><font color=#FF0000><h2>Previous action failed:</h2></font> <dd>Selected item from directory, $url_item, doesn't have write permissions for <i>SiteMgr</i>." unless -w $fs_item;
  
# If we get here, all is ok, so return an empty error message.
  return '';
}


#####################################################

sub create_file_or_dir {
# create a new empty file
# returns error message on error, null string if ok
# $type is 'file' or 'dir'
# $url os full url path
  
  my ($type, $doc_root, $url) = @_;
  
# translate to file system paths
  my $fs_item= $doc_root . $url;
  
# check for existence
  if (-e $fs_item) {
    return "<dt><font color=#FF0000><h2>Previous action failed:</h2></font> <dd>A file or directory with supplied name, $url, already exists.";
  }
  
# create the file or dir
  if ($type eq 'file') {
    unless (open(WR, ">$fs_item")) {
      return "<dt><font color=#FF0000><h2>Previous action failed:</h2></font> <dd> Unable to create the file: $url. Reason: $!";
    }
    print WR '';
    close WR;
    chmod 0644, "$fs_item";
    } elsif ($type eq 'dir') {
    unless ( mkdir $fs_item, 0755 ) {
      return "<dt><font color=#FF0000><h2>Previous action failed:</h2></font> <dd>Unable to create the directory: $url. Reason: $!";
    }
    } else {
    return "<dt><font color=#FF0000><h2>Previous action failed:</h2></font> <dd>Internal error: unknown file type.";
  }
  
  return "<dt><font color=#0000FF><h2>Previous action: directory created</h2></font> <dd>Directory <code>$url</code> was successfully created."
  if $type eq 'dir';
  return '';
}

###############################################

sub move_or_copy {
# mv or cp old_item to new_item; both are url paths.
# You could enhance and simplify by simply calling Unix 'mv' or 'cp'
# but with significant security risk. At least verify item types first.
  
  my ($doc_root, $old_url_item, $new_url_item, $op) = @_;
  my ($oped) = $op eq "mv" ? "moved" : "copied";
  
# translate to file system paths
  my ($old_fs_item, $new_fs_item) = ($doc_root . $old_url_item, $doc_root . $new_url_item);
  
# if old item is a file
  if (-f $old_fs_item) {
    
    copy ($old_fs_item, $new_fs_item) or
    return "<dt><h2>Previous action failed: file not $oped</h2> <dd>The file <code>$old_url_item</code> was not $oped to <code>$new_url_item</code>. Reason: $!.";
    chmod 0644, "$new_fs_item";
    if ($op eq "mv") {
      unlink $old_fs_item unless $old_fs_item eq $new_fs_item;
    }
    return "<dt><font color=#0000FF><h2>Previous action: file $oped</h2></font> <dd>The file <code>$old_url_item</code> was successfully $oped to  <code>$new_url_item</code>.";
  }
  
# if old item is a directory
  elsif (-d $old_fs_item) {
    
# read files in directory
    opendir DIR, $old_fs_item or
    return "<dt><h2>Previous action failed: directory not $oped</h2> <dd>Directory <code>$old_url_item</code> could not be read by SiteMgr. Reason: $!.";
#-- no hidden files, nor the current and parent directory
    my @files = grep !/^\./, readdir DIR;
#my @files = readdir DIR;                hay que descartar sólo . y .. (no .filename)
    closedir DIR;
    
    mkdir $new_fs_item, 0755 or
    return "<dt><h2>Previous action failed: directory not $oped</h2> <dd>Directory <code>$new_url_item</code> could not be created. Reason: $!.";
    
# loop over files in the directory
    my ($errlist) = '';
    
    foreach (@files) {
      
      if (-f "$old_fs_item/$_") { # a regular file
        if (copy ("$old_fs_item/$_", "$new_fs_item/$_")) {
          chmod (0644, "$new_fs_item/$_")
          } else {
          $errlist .= "<LI><CODE>$old_url_item/$_</CODE> -- $!\n";
        }
        
        if ($op eq "mv") {
          unlink "$old_fs_item/$_" unless "$old_fs_item/$_" eq "$new_fs_item/$_";
        }
        
        } elsif (-d "$old_fs_item/$_") { # a subdirectory
        $errlist .= "<LI><CODE>$old_url_item/$_</CODE> -- Unable to copy or move recursively subdirectories.\n";
        
        } elsif (-l "$old_fs_item/$_") { # a symlink
        $errlist .= "<LI><CODE>$old_url_item/$_</CODE> -- Unable to copy or move simbolic links.\n";
        
        } else { # unknown type
        $errlist .= "<LI><CODE>$old_url_item/$_</CODE> -- Imposible copiar o mover tipos de fichero desconocidos\n";
      }
    }
    
    if ($errlist) {     # collect list of file errors, if any
      $errlist = "Though, some of the files could not be $oped successfully: <UL>\n$errlist </UL>\nPerhaps, some of them can be $oped individually.";
      $errlist .= "                  This files and the old directory could not be deleted."
      if $op eq 'mv';
      } elsif ($op eq 'mv') { # if no file errors, rmdir if 'mv'
      rmdir $old_fs_item or
      $errlist = "SiteMgr could not delete the old directory <code>$old_url_item</code>, though files into it could be moved. Reason: $!";
    }
    return "<dt><h2>Previous action: directory $oped</h2> <dd>Directory <code>$old_url_item</code> was $oped to <code>$new_url_item</code>. $errlist";
  }
  
# do not copy symlinks
  elsif (-l $old_fs_item) {
    return "<dt><h2>Previous action failed: file not $oped</h2> <dd>File <code>$old_url_item</code> is a simbolic link. SiteMgr dosn't work with simbolic links by security reasons.";
  }
  
# unknown type
  else {
    return "<dt><h2>Previous action failed: item not $oped</h2> <dd>Item <code>$old_url_item ($old_fs_item)</code> is not a regular file or directory. SiteMgr doesn't work with unknown file types by security reasons.";
  }
}

#########################################################

sub delete_item {
# delete a file or directory
  my ($DocumentRoot ,$url_item) = @_;
  
# translate to file system paths
  my  $fs_item = $DocumentRoot . $url_item;
  
# now delete the item
  if (-d $fs_item) {
    if (rmdir $fs_item) {
      return "<dt><font color=#0000FF><h2>Previous action: Directory deleted</h2></font><dd>Directory <code>$url_item</code> was successfully deleted.";
      } else {
      return "<dt><h2>Previous action failed:</h2> <dd>Directory <code>$url_item</code> was not deleted. Reason: $!";
    }
    } else {
    if (unlink $fs_item) {
      return "<dt><font color=#0000FF><h2>Previous action: File deleted</h2></font> <dd>File <code>$url_item</code> was successfully deleted.";
      } else {
      return "<dt><h2>Previous action failed:</h2><dd>File <code>$url_item</code > was not deleted. Reason: $!";
    }
  }
}




###############################################################

sub upload_file {
# copies temp file (a fs path) to new url
# CGI.pm expects to delete the temp file
  my ($doc_root, $new_url_item, $tmpName) = @_;
  my (@stat);
  
# translate to file system paths
  
  my  $new_fs_item = $doc_root . $new_url_item;
  
#  my $new_fs_item = &translate_url2fs($new_url_item);
  
  
  
##### This section is used only in the demo version. #####
##### Comment it out to remove upload size limitations. #####
# filesize is $stat[7];
#++ No limitations for uploading ... uncoment this section and change to the desired limit.
#++
#++  unless ( @stat = stat($tmpName) ) {
#++    return "<dt><h2>Previous action failed:</h2>
#++            <dd>Internal error: when trying to find $tmpName.\n\n";
#++  }
#++  if ($stat[7] > 1000) {
#++    return "<dt><h2>Previous action failed:</h2>
#++            <dd>The file you requested to upload is too large. In this demo
#++            uploaded files must be smaller than 1 kb (1,000 bytes).\n\n";
#++  }
##### End of file size limitation section #####
  
# from File::Copy
  unless (copy ($tmpName, $new_fs_item)) {
    return "<dt><font color=#0000FF><h2>Previous action failed: file not uploaded</h2></font> <dd>Internal error: failed when copying temporal file. Reason: $!."
  }
  
  if (-d $new_fs_item) {
    chmod 0755, "$new_fs_item";
    } else {
    chmod 0644, "$new_fs_item";
  }
  
  return "<dt><font color=#0000FF><h2>Previous action: file uploaded</h2></font> <dd>The file was successfully uploaded as <code>$new_url_item</code>."
}




###########################################################

sub preview_changes {
  
### Write a temporary file containing $text in the same directory as the
### $file and then redirect the browser to it. In this way,
### relative images and links will work in the preview. They wouldn't if
### we simply wrote back the html to the browser, since it would be
### relative to the script's directory. We'll fork a process to sleep and
### then delete the temporary file in a few seconds.
  
  my ($text,$DocumentRoot,$url) = @_;
  
# make CR/LF substitutions in the text
  $text =~ s/\r\n/\n/g;
  $text =~ s/\r/\n/g;
  
# translate to file system paths
#my $fs_file = &translate_url2fs($url);
  
  my $fs_file = $DocumentRoot . $url;    #dummy asignation 'cause we don't use translate_url2fs
  
  $fs_file =~ s/[^\w-~\/\.\,]//g;    # sanitize the file name for shell escapes
  
# create names and url for temporary files in the same directory
# include process id in the name for uniqueness
  unless ( $url =~ s/\.html?$/$$.tmp\.html/i
    and $fs_file =~ s/\.html?$/$$.tmp\.html/i ) {
    print "Content-type: text/html\n\nSorry, only the files ended with .htm or .html can be previewed. Other files must be saved before previewed with your browser.";
    exit;
  }
  
# make the temporary file hidden
  if ($url =~ /[^\/]*$/ and $fs_file =~ /[^\/]*$/) {
    $url =~ s|([^/]*)$|\.$1|;
    $fs_file =~ s|([^/]*)$|\.$1|;
  }
  
# write the temporary file
  unless ( open (WR, ">$fs_file") ) {
    print "Content-type: text/html\n\nFailed when opening temporal file.";
    exit;
  }
  print WR $text;
  close WR;
  chmod 0644, "$fs_file";
  
# redirect the browser
  $| = 1;  # flush buffer so we don't wait.
  print "Location: http://$ENV{'SERVER_NAME'}/$url\n\n";
  
# open a process to delete it; since we do not close
# the process, it will live beyond the cgi script
  open (PROC, "| sleep 2; rm -f $fs_file");
  exit;
}



###################################################

sub save_changes {
# overwrite file at $url with $text
  my ($text, $DocumentRoot ,$url) = @_;
  
# translate to file system paths
#my $fs_file = &translate_url2fs($url);
  my $fs_file = $DocumentRoot . $url;
  
# make CR/LF substitutions--we assume it's a text file
  $text =~ s/\r\n/\n/g;
  $text =~ s/\r/\n/g;
  
  unless ( open(WR, ">$fs_file") ) {
    return "<dt><h2>Previous action failed</h2> <dd>Unable to write $url. Reason: $!";
  }
  print WR "$text";
  close WR;
  chmod 0644, "$fs_file";
  
  return "<dt><font color=#0000FF><h2>Previous action: file edited</h2></font> <dd>The file <a href=\\\"http:\/\/$ENV{SERVER_NAME}/$url\\\" target=_blank>$url</a> was successfully edited.";
}



#####################################################

sub print_edit_page {
  my ($user,$crpass,$DocumentRoot,$cur_url_dir,$url_filename) = @_;
  my ($text);
  
  
# translate to file system paths
  my $fs_filename = $DocumentRoot . $url_filename;
  
  ($cur_url_dir = $url_filename) =~ s#/[^/]+$##;
  
# we have already validated target, but we still need
# to check if it's a directory
  if (-d "$fs_filename") {
    return "<dt><h2>Previous action failed</h2> <dd>$url_filename is a directory. Please, select a file to edit.";
  }
  
# read in the target file
  unless (open (RD, "$fs_filename")) {
    return "<dt><h2>Previous action failed</h2> <dd>Unable to read the file $url_filename. Reason: $!";
  }
#    $text = join '', <RD>;
  
#		while(<RD>){
#			$_ =~ s/\n/ /g;
#			$_ =~ s/\"/\\\"/g;
#			chop $_;
#  		$text .= "\"" . $_ . "\\n\"" . "+";
#	  };
  
#		chop $text;  # the latest '\n'
  
#   close RD;

 
  print <<"HERE";
Content-type: text/html\n\n 
<html>

  <head>
  <script language="JavaScript">
  
  EditFile=open("","DisplayWindow","location=no,status=no,menubar=no,directories=no");
  EditFile.document.open();
  EditFile.document.write("<html>\\n<head>\\n<title>SiteMgr Editor</title>\\n");
  EditFile.document.write("</head>\\n<body bgcolor='#ffffff' link='#004400' vlink='#006600'>\\n");
    
    EditFile.document.write("<form name=editform method=post action='$script_url' target=FileListing>\\n");
    
    EditFile.document.write("<input type=hidden name=user value='$user'>\\n");
    EditFile.document.write("<input type=hidden name=crpass value='$crpass'>\\n");
    EditFile.document.write("<input type=hidden name=item value='$url_filename'>\\n");
    EditFile.document.write("<input type=hidden name=top_dir value='$top_dir'>\\n");
    EditFile.document.write("<input type=hidden name=dir value='$cur_url_dir'>\\n");
    EditFile.document.write("<input type=hidden name=operation value='Save changes'>\\n");
    
    
    EditFile.document.write("<h2>Editing the file: $url_filename</h2>\\n");
    EditFile.document.write("<table bgcolor='#FFFFFF' align=center width='90%'>\\n");
    EditFile.document.write("<tr align=center><td>\\n");
    EditFile.document.write("<textarea cols=60 rows=20 name=text>\\n");

HERE
      
      while(<RD>){
        $_ =~ s/\n/ /g;
        $_ =~ s/\r/ /g;
        $_ =~ s/\f/ /g;
        $_ =~ s/\t/ /g;
        $_ =~ s/\"/\\\"/g;
        if( $_ =~ s/^<\/script>// ){
          print "EditFile.document.writeln(\"<\/scr\")";
          print "EditFile.document.writeln(\"ipt>\\n\")";
          }else{
          print "EditFile.document.writeln(\"$_\");";
        }
      };
      
      close RD;
      
      print <<"HERE";
      
      EditFile.document.write("</textarea><P>\\n");
      EditFile.document.write("</td></tr>\\n");
      EditFile.document.write("</table>\\n");
      EditFile.document.write("<table bgcolor='#FFFFFF' width='100%'>\\n");
        EditFile.document.write("<tr align=center valign=center><td>\\n");
        
        EditFile.document.write("<a href=\\\"javascript:EditFile.document.editform.submit();\\\" target=FileListing \\n");
        EditFile.document.write("  onMouseOver=\\\"SaveFile.src='\/smgryap\/icons\/save-p.gif';\\\" \\n");
        EditFile.document.write("  onMouseOut=\\\"SaveFile.src='\/smgryap\/icons\/save.gif';\\\"><img name=SaveFile \\n");
        EditFile.document.write("  src=\\\"\/smgryap\/icons\/save.gif\\\" width=54 heigth=54 alt=\\\"Save edited file\\\" border=0><\/a> \\n");
        
        EditFile.document.write("<a href=\\\"javascript:window.close(self);\\\" \\n");
        EditFile.document.write("  onMouseOver=\\\"CloseEditor.src='\/smgryap\/icons\/closeeditor-p.gif';\\\" \\n");
        EditFile.document.write("  onMouseOut=\\\"CloseEditor.src='\/smgryap\/icons\/closeeditor.gif';\\\"><img name=CloseEditor \\n");
        EditFile.document.write("  src=\\\"\/smgryap\/icons\/closeeditor.gif\\\" width=54 heigth=54 alt=\\\"Close the editor\\\" border=0><\/a> \\n");
        
        
        EditFile.document.write("<\/td><\/tr>\\n");
        EditFile.document.write("<\/table>\\n");
        EditFile.document.write("<\/font>\\n");
        EditFile.document.write("<\/form>\\n<\/body>\\n<\/html>");
        
        EditFile.document.close();
        
        <\/script>
        <\/head>
        <\/html>
        
        
HERE
        return "<dt><font color=#0000FF><h2>Current action:<\/h2><\/font> <dd>Editing the file $url_filename. ";
        
        exit;
      }
      
      
      
#############################################################
      
      sub print_web_page {
        my ($user,$crpass,$DocumentRoot, $script_url, $prev_url_dir, $top_url_dir, $target_url_dir, $error_message,$operation) = @_;
        
        my $cur_url_dir = &get_sufix($target_url_dir,$DocumentRoot);
        
        if( $operation !~ /CREATE/ ){
          if( $operation !~ /EDIT/ ){
            print "Content-type: text/html\n\n";
          }
        }

###
### print page header
###
        if( $error_message =~ /failed/ && $operation !~ /MKDIR/ && $operation !~ /COPY/ && $operation !~ /MOVE/ && $operation !~ /Upload/ ){
          print "Content-type: text/html\n\n"; 
        }

        print <<"HERE";
<html>
<head>
<script language="JavaScript">
HERE
        ;
        
###
### print error message, if any
###
        
        if($error_message){
          print "parent.MsgWindow.document.open();\n";
          print "parent.MsgWindow.document.write(\"<html><body bgcolor=#FFFFFF>\");\n";
            print "parent.MsgWindow.document.write(\"$error_message\");\n";
            print "parent.MsgWindow.document.write(\"</body></html>\");\n";
            print "parent.MsgWindow.document.close();\n";
          }
          
          print <<"HERE";
          /*
          global variables for file or directory item selected
        and for the action selected (except upload))
        */
        var indexItemSelected = "";
        var actionSelected = "";
        
        /*
        onClick handler for radio buttons, recommeded for buggy NS 2.0
        item = url path to file or directory
        */
        function selectIndexItem(item) {
          
          this.document.mainform.selecteditem.value = item;
          indexItemSelected = item;
        }
        
        /*
        END OF JAVASCRIPT
        */
        
        </script>
        
        </head>
        <body bgcolor="#ddeedd" link="004400" vlink="006600">
        
        <blockquote>
        <dl>
        <form method=post action="$script_url" name="mainform">
        <input type=hidden name=selecteditem value="">
        <input type=hidden name=dir value="$cur_url_dir">
        <input type=hidden name=user value="$user">
        <input type=hidden name=crpass value="$crpass">
        
HERE
        ;                      ###### end of page header
        
###
### print directory index
###
        
# these local variables are used only in directory index
        my ($parent_url_dir, $target_fs_dir, $parent_fs_dir, $filename, $parent_fs_dir,
        @stat, $mtime, $size, $img, $comment, $fs_prefix, $url_prefix);
        
# Is important to check that it is not a serious error; a hacker could be behind this errors ...
        
        if( $error_message !~ /Fallo grave/ ) {
          
          print <<"HERE";
          
          <dt>\n<H2>Current directory file listing: $cur_url_dir/</H2>
          <hr>
          <dd>\n\n<table>
          
          <tr align=center>
          <td><b>Selection</b></td>
          <td></td>
          <td><b>Name</b></td>
          <td><b>Size</b></td>
          <td><b>Created</b></td>
          <td align=left><b>Type</b></td>
          </tr>
          
HERE
;
          
          
### if target dir is strictly below top
          
          if ( $target_url_dir =~ /^$top_url_dir.+/ ) {
            
            ($parent_url_dir = $target_url_dir) =~ s/\/[\w-\.~]+$//;
            ($parent_fs_dir = $target_dir) =~ s/\/[\w-\.~]+$//;
            
            print <<"HERE";
            
            <tr><td colspan=6>
            <input type=hidden name=parent_dir value="$parent_url_dir">
            <input type=submit name=prevdir value="up one directory"></td>
HERE
            ;
          }
# translate to file system paths
          
          $target_fs_dir = $target_url_dir;
          
### cycle through the files in the directory
          unless ( opendir DIR, $target_fs_dir ) {
            print "</table><dt><h2>Internal error:</h2>
            <dd>Please, send this text to the webmaster for seeing whats happening. 'opendir' failed: <ul>
	    <li>DocumentRoot: $DocumentRoot...
	    <li>HostName: $HostName...
	    <li>AuthSiteMgrURL: $AuthSiteMgrURL...
            <li>script_url: $script_url...
            <li>top_url_dir: $top_url_dir...
	    <li>top_fs_dir: $top_fs_dir...
            <li>parent_url_dir: $parent_url_dir
            <li>target_url_dir: $target_url_dir...
            <li>target_fs_dir: $target_fs_dir
            <li>error_message: $error_message...
            </ul>Environment variables: <ul>";
            foreach (keys %ENV) {
              print "<li>$_: $ENV{$_}\n";
            }
            print "</ul></dl></blockquote></body></html>";
            exit;
          }

          my @all_files_and_directories = readdir DIR;
 
          my @all_directories;
          my @all_files;
 
          for $filename (@all_files_and_directories) {
            @stat = stat $target_fs_dir.'/'.$filename;
 
            if (-d _) {
              unshift @all_directories , $filename;
            } else {
              unshift @all_files , $filename;
            }
          }
 
# All directories and files are sorted
 
         my @all_directories_sorted = sort @all_directories;
         my @all_files_sorted = sort @all_files;
 
# Directories will appear first
 
         my @all_sorted_directories_first ;
 
         push @all_sorted_directories_first , @all_directories_sorted;
         push @all_sorted_directories_first , @all_files_sorted;
 
# Let's print out all the directory listing
 
         for $filename (@all_sorted_directories_first) {
            
            next if $filename eq ".";  # skip hidden files
            next if $filename eq "..";
            
            @stat = stat $target_fs_dir.'/'.$filename;
            $mtime = localtime($stat[9]);
            $mtime =~ s/^... //;
            $mtime =~ s/:\d\d\s+\d\d\d\d//;
            $size = $stat[7];
            
            if (-d _) {                         # a directory
              
              print <<"HERE";
              <tr><td align=center>
              <input type=radio name=item value=\"$cur_url_dir/$filename\"
              onClick=selectIndexItem(\"$cur_url_dir/$filename\")> </td>
              <td> <IMG ALIGN=absbottom BORDER=0 SRC=\"\/smgryap\/icons\/folder.gif\"> </td>
              <td> <input type=submit name=subdir value="$filename"><br> </td>
              <td align=right>$size bytes</td>
              <td>$mtime </td>
              <td>Directory</td></tr>\n
HERE
              ;
              next;
            }
            
            if ($filename =~ /\.html?$/i) {     # .htm or .html file (not dir)
              $img = "\/smgryap\/icons\/html.gif";
              $comment = "HTML file";
              } elsif ($filename =~  /\.gif/i or $filename =~ /\.jpg/i or $filename =~ /\.png/i) { # gif, jpg, or png
              $img = "\/smgryap\/icons\/image.gif";
              $comment = "Image";
	      } elsif ($filename =~  /\.mov/i or $filename =~ /\.avi/i or $filename =~ /\.mpg/i) { # video formats 
	      $img = "\/smgryap\/icons\/video.gif";
	      $comment = "Video"; 
              } elsif ($filename =~  /\.txt/i) { # .txt file
              $img = "\/smgryap\/icons\/text.gif";
              $comment = "Text file";
              } else {
              $img = "\/smgryap\/icons\/unknown.gif";
              $comment = "Unknown format";
            }
            
            print <<"HERE";
            <tr><td align=center>
            <input type=radio name=item value=\"$cur_url_dir/$filename\"
            onClick=selectIndexItem(\"$cur_url_dir/$filename\")> </td>
            <td> <IMG ALIGN=absbottom BORDER=0 SRC=\"$img\"></td>
            <td><a href=\"/$cur_url_dir/$filename\" target=_blank>$filename</a></td>
            <td align=right>$size bytes</td>
            <td>$mtime </td>
            <td>$comment </td></tr>\n
HERE
            ;
          }                           ### end of while
          closedir DIR;
          print "</table>\n";              #######  end of print directory index
          
###
### print_file_operations
###
          print <<"HERE";
          
          <input type=hidden name=newName value="$cur_url_dir/" size=50>
          <input type=hidden name=operation value="NO_OP">
          
          <input type=hidden name=top_dir value=$top_dir>
          
          </form>                               <!-- still in blockquote and dl -->
          
          <form method=post action="$script_url"
          name="uploadForm"
          onSubmit="return checkUploadForm()"
          enctype="multipart/form-data">
          
          <input type=hidden name=user value="$user">
          <input type=hidden name=crpass value="$crpass">
          <input type=hidden name=top_dir value="$top_dir">
          <input type=hidden name=dir value="$cur_url_dir">
          
          <input type=hidden name=remoteUploadName size=50>
          <input type=hidden name=newUploadName>
          <input type=hidden name=operation value="Upload file">
          </form>
          </blockquote>
          <hr>
HERE
          ;       ############## End of print directory index
          
        }           ############## End of 'Serious fail' exclusion
        
        print "\n<\/body>\n<\/html>";
        
      }           ############## End of sub print_web_page
      
      
##########################################################
#
# gets the sufix (right hand side) of a url giving the root
#
      
      sub get_sufix()
      {
        my ($complete_url,$doc_root) = @_;
        
        my $new_url = $complete_url;
        
        $new_url =~ s/$doc_root//;
        
        return $new_url;
      }