X-Git-Url: https://git.p6c8.net/devedit.git/blobdiff_plain/3e6b9e338fe5ea06b487202fe54217f2082cd13d..ea86dd1c2b813a085290e0e24040122c2487182b:/modules/Command.pm?ds=inline diff --git a/modules/Command.pm b/modules/Command.pm index 1a39d67..84a0378 100644 --- a/modules/Command.pm +++ b/modules/Command.pm @@ -6,41 +6,74 @@ package Command; # Execute Dev-Editor's commands # # Author: Patrick Canterino -# Last modified: 09-22-2003 +# Last modified: 2004-11-24 # use strict; -use vars qw(@EXPORT - $script); - -use CGI qw(header - redirect); +use vars qw(@EXPORT); use File::Access; use File::Copy; +use File::Path; -use HTML::Entities; -use Output; use POSIX qw(strftime); use Tool; -$script = $ENV{'SCRIPT_NAME'}; +use CGI qw(header); +use HTML::Entities; +use Output; +use Template; + +my $script = $ENV{'SCRIPT_NAME'}; +my $users = eval("getpwuid(0)") && eval("getgrgid(0)"); + +my %dispatch = ('show' => \&exec_show, + 'beginedit' => \&exec_beginedit, + 'canceledit' => \&exec_canceledit, + 'endedit' => \&exec_endedit, + 'mkdir' => \&exec_mkdir, + 'mkfile' => \&exec_mkfile, + 'upload' => \&exec_upload, + 'copy' => \&exec_copy, + 'rename' => \&exec_rename, + 'remove' => \&exec_remove, + 'chprop' => \&exec_chprop, + 'unlock' => \&exec_unlock, + 'about' => \&exec_about + ); ### Export ### use base qw(Exporter); -@EXPORT = qw(exec_show - exec_beginedit - exec_endedit - exec_mkfile - exec_mkdir - exec_workwithfile - exec_copy - exec_rename - exec_remove - exec_unlock); +@EXPORT = qw(exec_command); + +# exec_command() +# +# Execute the specified command +# +# Params: 1. Command to execute +# 2. Reference to user input hash +# 3. Reference to config hash +# +# Return: Output of the command (Scalar Reference) + +sub exec_command($$$) +{ + my ($command,$data,$config) = @_; + + foreach(keys(%dispatch)) + { + if(lc($_) eq lc($command)) + { + my $output = &{$dispatch{$_}}($data,$config); + return $output; + } + } + + return error($config->{'errors'}->{'cmd_unknown'},'/',{COMMAND => $command}); +} # exec_show() # @@ -51,135 +84,162 @@ use base qw(Exporter); # # Return: Output of the command (Scalar Reference) -sub exec_show($$$) +sub exec_show($$) { my ($data,$config) = @_; my $physical = $data->{'physical'}; my $virtual = $data->{'virtual'}; - my $output; + my $upper_path = upper_path($virtual); + my $uselist = $data->{'uselist'}; + + my $tpl = new Template; if(-d $physical) { # Create directory listing + return error($config->{'errors'}->{'no_dir_access'},$upper_path) unless(-r $physical && -x $physical); + my $direntries = dir_read($physical); - return error("Reading of directory $virtual failed") unless($direntries); + return error($config->{'dir_read_fail'},$upper_path,{DIR => $virtual}) unless($direntries); my $files = $direntries->{'files'}; my $dirs = $direntries->{'dirs'}; - $output .= htmlhead("Directory listing of $virtual"); - $output .= equal_url($config->{'httproot'},$virtual); - $output .= "
\n\n
\n";
+  my $dirlist = "";
 
   # Create the link to the upper directory
   # (only if we are not in the root directory)
 
   unless($virtual eq "/")
   {
-   my $upper = $physical."/..";
-   my @stat  = stat($upper);
+   my @stat  = stat($physical."/..");
 
-   $output .= "  [SUBDIR]  ";
-   $output .= strftime("%d.%m.%Y %H:%M",localtime($stat[9]));
-   $output .= " " x 10;
-   $output .= "../\n";
-  }
+   my $udtpl = new Template;
+   $udtpl->read_file($config->{'templates'}->{'dirlist_up'});
 
-  # Get the longest file/directory name
+   $udtpl->fillin("UPPER_DIR",encode_entities($upper_path));
+   $udtpl->fillin("DATE",encode_entities(strftime($config->{'timeformat'},localtime($stat[9]))));
 
-  my $max_name_len = 0;
-
-  foreach(@$dirs,@$files)
-  {
-   my $length    = length($_);
-   $max_name_len = $length if($length > $max_name_len);
+   $dirlist .= $udtpl->get_template;
   }
 
   # Directories
 
   foreach my $dir(@$dirs)
   {
-   my @stat = stat($physical."/".$dir);
+   my $phys_path = $physical."/".$dir;
+   my $virt_path = encode_entities($virtual.$dir."/");
+
+   my @stat      = stat($phys_path);
+
+   my $dtpl = new Template;
+   $dtpl->read_file($config->{'templates'}->{'dirlist_dir'});
 
-   $output .= "  ";
-   $output .= "[SUBDIR]  ";
-   $output .= strftime("%d.%m.%Y %H:%M",localtime($stat[9]));
-   $output .= " " x 10;
-   $output .= "".encode_entities($dir)."/\n";
+   $dtpl->fillin("DIR",$virt_path);
+   $dtpl->fillin("DIR_NAME",$dir);
+   $dtpl->fillin("DATE",encode_entities(strftime($config->{'timeformat'},localtime($stat[9]))));
+   $dtpl->fillin("URL",equal_url($config->{'httproot'},$virt_path));
+
+   $dtpl->parse_if_block("readable",-r $phys_path && -x $phys_path);
+   $dtpl->parse_if_block("users",$users && -o $phys_path);
+
+   $dirlist .= $dtpl->get_template;
   }
 
   # Files
 
   foreach my $file(@$files)
   {
-   my @stat      = stat($physical."/".$file);
-   my $virt_path = $virtual.$file;
-   my $in_use    = $data->{'uselist'}->in_use($virtual.$file);
-
-   $output .= " " x (10 - length($stat[7]));
-   $output .= $stat[7];
-   $output .= "  ";
-   $output .= strftime("%d.%m.%Y %H:%M",localtime($stat[9]));
-   $output .= ($in_use) ? " (IN USE) " : " " x 10;
-   $output .= encode_entities($file);
-   $output .= " " x ($max_name_len - length($file))."\t  (";
-   $output .= "View | ";
-
-   $output .= ($in_use)
-              ? 'Edit'
-              : "Edit";
-
-   $output .= " | Do other stuff)\n";
+   my $phys_path = $physical."/".$file;
+   my $virt_path = encode_entities($virtual.$file);
+
+   my @stat      = stat($phys_path);
+   my $in_use    = $uselist->in_use($virtual.$file);
+
+   my $ftpl = new Template;
+   $ftpl->read_file($config->{'templates'}->{'dirlist_file'});
+
+   $ftpl->fillin("FILE",$virt_path);
+   $ftpl->fillin("FILE_NAME",$file);
+   $ftpl->fillin("SIZE",$stat[7]);
+   $ftpl->fillin("DATE",encode_entities(strftime($config->{'timeformat'},localtime($stat[9]))));
+   $ftpl->fillin("URL",equal_url($config->{'httproot'},$virt_path));
+
+   $ftpl->parse_if_block("not_readable",not -r $phys_path);
+   $ftpl->parse_if_block("binary",-B $phys_path);
+   $ftpl->parse_if_block("readonly",not -w $phys_path);
+
+   $ftpl->parse_if_block("viewable",-r $phys_path && -T $phys_path && not ($config->{'max_file_size'} && $stat[7] > $config->{'max_file_size'}));
+
+   $ftpl->parse_if_block("editable",-r $phys_path && -w $phys_path && -T $phys_path && not ($config->{'max_file_size'} && $stat[7] > $config->{'max_file_size'}) && not $in_use);
+
+   $ftpl->parse_if_block("in_use",$in_use);
+   $ftpl->parse_if_block("unused",not $in_use);
+
+   $ftpl->parse_if_block("too_large",$config->{'max_file_size'} && $stat[7] > $config->{'max_file_size'});
+
+   $ftpl->parse_if_block("users",$users && -o $phys_path);
+
+   $dirlist .= $ftpl->get_template;
   }
 
-  $output .= "
\n\n
\n\n"; - $output .= < - -Create new directory: -$virtual - - -Create new file: -$virtual - - - -
-END - $output .= htmlfoot; + $tpl->read_file($config->{'templates'}->{'dirlist'}); + + $tpl->fillin("DIRLIST",$dirlist); + $tpl->fillin("DIR",$virtual); + $tpl->fillin("SCRIPT",$script); + $tpl->fillin("URL",equal_url($config->{'httproot'},$virtual)); } else { # View a file + return error($config->{'errors'}->{'noview'},$upper_path) unless(-r $physical); + # Check on binary files + # We have to do it in this way, or empty files + # will be recognized as binary files - if(-B $physical) + unless(-T $physical) { # Binary file - return error("This editor is not able to view/edit binary files."); + return error($config->{'errors'}->{'binary'},$upper_path); } else { # Text file - $output = htmlhead("Contents of file $virtual"); - $output .= equal_url($config->{'httproot'},$virtual); - $output .= dir_link($virtual); + my $size = -s $physical; + + if($config->{'max_file_size'} && $size > $config->{'max_file_size'}) + { + return error($config->{'errors'}->{'file_too_large'},$upper_path,{SIZE => $config->{'max_file_size'}}) + } + else + { + my $content = file_read($physical); + $$content =~ s/\015\012|\012|\015/\n/g; + + $tpl->read_file($config->{'templates'}->{'viewfile'}); + + $tpl->fillin("FILE",$virtual); + $tpl->fillin("DIR",$upper_path); + $tpl->fillin("URL",equal_url($config->{'httproot'},$virtual)); + $tpl->fillin("SCRIPT",$script); - $output .= '
'."\n"; - $output .= '
'."\n";
-   $output .= encode_entities(${file_read($physical)});
-   $output .= "\n
\n
"; + $tpl->parse_if_block("editable",-r $physical && -w $physical && -T $physical && not ($config->{'max_file_size'} && $size > $config->{'max_file_size'}) && $uselist->unused($virtual)); - $output .= htmlfoot; + $tpl->fillin("CONTENT",encode_entities($$content)); + } } } - return \$output + my $output = header(-type => "text/html"); + $output .= $tpl->get_template; + + return \$output; } # exec_beginedit @@ -196,65 +256,72 @@ sub exec_beginedit($$) my ($data,$config) = @_; my $physical = $data->{'physical'}; my $virtual = $data->{'virtual'}; + my $dir = upper_path($virtual); my $uselist = $data->{'uselist'}; - return error("You cannot edit directories.") if(-d $physical); - return error_in_use($virtual) if($uselist->in_use($virtual)); + return error($config->{'errors'}->{'editdir'},$dir) if(-d $physical); + return error($config->{'errors'}->{'in_use'}, $dir,{FILE => $virtual}) if($uselist->in_use($virtual)); + return error($config->{'errors'}->{'noedit'}, $dir) unless(-r $physical && -w $physical); # Check on binary files - if(-B $physical) + unless(-T $physical) { # Binary file - return error("This editor is not able to view/edit binary files."); + return error($config->{'errors'}->{'binary'},$dir); } else { - # Text file - - $uselist->add_file($virtual); - $uselist->save; - - my $dir = upper_path($virtual); - my $content = encode_entities(${file_read($physical)}); - - my $output = htmlhead("Edit file $virtual"); - $output .= equal_url($config->{'httproot'},$virtual); - $output .= <Caution! This file is locked for other users while you are editing it. To unlock it, click Save and exit or Exit WITHOUT saving. Please don't click the Reload button in your browser! This will confuse the editor.

- -
- - -

-
- -
- - - - - - - - - - - - -
Save as new file: $dir Encode ISO-8859-1 special chars
- - -
-END - - $output .= htmlfoot; + if($config->{'max_file_size'} && (-s $physical) > $config->{'max_file_size'}) + { + return error($config->{'errors'}->{'file_too_large'},$dir,{SIZE => $config->{'max_file_size'}}) + } + else + { + # Text file - return \$output; + $uselist->add_file($virtual); + $uselist->save; + + my $content = file_read($physical); + $$content =~ s/\015\012|\012|\015/\n/g; + + my $tpl = new Template; + $tpl->read_file($config->{'templates'}->{'editfile'}); + + $tpl->fillin("FILE",$virtual); + $tpl->fillin("DIR",$dir); + $tpl->fillin("URL",equal_url($config->{'httproot'},$virtual)); + $tpl->fillin("SCRIPT",$script); + $tpl->fillin("CONTENT",encode_entities($$content)); + + my $output = header(-type => "text/html"); + $output .= $tpl->get_template; + + return \$output; + } } } +# exec_canceledit() +# +# Abort file editing +# +# Params: 1. Reference to user input hash +# 2. Reference to config hash +# +# Return: Output of the command (Scalar Reference) + +sub exec_canceledit($$) +{ + my ($data,$config) = @_; + my $virtual = $data->{'virtual'}; + + file_unlock($data->{'uselist'},$virtual); + return devedit_reload({command => 'show', file => upper_path($virtual)}); +} + # exec_endedit() # # Save a file, unlock it and return to directory view @@ -269,9 +336,21 @@ sub exec_endedit($$) my ($data,$config) = @_; my $physical = $data->{'physical'}; my $virtual = $data->{'virtual'}; + my $dir = upper_path($virtual); my $content = $data->{'cgi'}->param('filecontent'); + my $uselist = $data->{'uselist'}; + + # We already unlock the file at the beginning of the + # subroutine, because if we have to abort this routine, + # the file keeps locked. + # Nobody else will access the file during this routine + # because of the concept of File::UseList. + + file_unlock($uselist,$virtual); - return error("You cannot edit directories.") if(-d $physical); + # Normalize newlines + + $content =~ s/\015\012|\012|\015/\n/g; if($data->{'cgi'}->param('encode_iso')) { @@ -280,15 +359,31 @@ sub exec_endedit($$) $content = encode_entities($content,"\200-\377"); } + if($data->{'cgi'}->param('saveas') && $data->{'new_physical'} ne '' && $data->{'new_virtual'} ne '') + { + # Create the new filename + + $physical = $data->{'new_physical'}; + $virtual = $data->{'new_virtual'}; + + # Check if someone else is editing the new file + + return error($config->{'errors'}->{'in_use'},$dir,{FILE => $virtual}) if($uselist->in_use($virtual)); + } + + return error($config->{'errors'}->{'text_to_binary'},$dir) unless(-T $physical); + return error($config->{'errors'}->{'editdir'},$dir) if(-d $physical); + return error($config->{'errors'}->{'noedit'}, $dir) if(-e $physical && !(-r $physical && -w $physical)); + if(file_save($physical,\$content)) { - # Saving of the file was successfull - so unlock it! + # Saving of the file was successful - so unlock it! - return exec_unlock($data,$config); + return devedit_reload({command => 'show', file => $dir}); } else { - return error("Saving of file '$virtual' failed'"); + return error($config->{'errors'}->{'edit_failed'},$dir,{FILE => $virtual}); } } @@ -303,7 +398,32 @@ sub exec_endedit($$) sub exec_mkfile($$) { - 1; + my ($data,$config) = @_; + my $new_physical = $data->{'new_physical'}; + my $new_virtual = $data->{'new_virtual'}; + my $dir = upper_path($new_virtual); + $new_virtual = encode_entities($new_virtual); + + if($new_physical) + { + return error($config->{'errors'}->{'file_exists'},$dir,{FILE => $new_virtual}) if(-e $new_physical); + + file_create($new_physical) or return error($config->{'errors'}->{'mkfile_failed'},$dir,{FILE => $new_virtual}); + return devedit_reload({command => 'show', file => $dir}); + } + else + { + my $tpl = new Template; + $tpl->read_file($config->{'templates'}->{'mkfile'}); + + $tpl->fillin("DIR","/"); + $tpl->fillin("SCRIPT",$script); + + my $output = header(-type => "text/html"); + $output .= $tpl->get_template; + + return \$output; + } } # exec_mkdir() @@ -317,80 +437,94 @@ sub exec_mkfile($$) sub exec_mkdir($$) { - 1; + my ($data,$config) = @_; + my $new_physical = $data->{'new_physical'}; + my $new_virtual = $data->{'new_virtual'}; + my $dir = upper_path($new_virtual); + $new_virtual = encode_entities($new_virtual); + + return error($config->{'errors'}->{'file_exists'},$dir,{FILE => $new_virtual}) if(-e $new_physical); + + if($new_physical) + { + mkdir($new_physical,0777) or return error($config->{'errors'}->{'mkdir_failed'},$dir,{DIR => $new_virtual}); + return devedit_reload({command => 'show', file => $dir}); + } + else + { + my $tpl = new Template; + $tpl->read_file($config->{'templates'}->{'mkdir'}); + + $tpl->fillin("DIR","/"); + $tpl->fillin("SCRIPT",$script); + + my $output = header(-type => "text/html"); + $output .= $tpl->get_template; + + return \$output; + } } -# exec_workwithfile() +# exec_upload() # -# Display a form for renaming/copying/deleting/unlocking a file +# Upload a file # # Params: 1. Reference to user input hash # 2. Reference to config hash # # Return: Output of the command (Scalar Reference) -sub exec_workwithfile($$) +sub exec_upload($$) { my ($data,$config) = @_; my $physical = $data->{'physical'}; my $virtual = $data->{'virtual'}; - my $unused = $data->{'uselist'}->unused($virtual); + my $cgi = $data->{'cgi'}; - my $output = htmlhead("Work with file $virtual"); - $output .= equal_url($config->{'httproot'},$virtual); - $output .= dir_link($virtual); - $output .= "

Note: On UNIX systems, filenames are case-sensitive!

\n\n"; + return error($config->{'errors'}->{'no_directory'},upper_path($virtual),{FILE => $virtual}) unless(-d $physical); - $output .= "

Someone else is currently editing this file. So not all features are available.

\n\n" unless($unused); + if(my $uploaded_file = $cgi->param('uploaded_file')) + { + # Process file upload - $output .= < + my $filename = file_name($uploaded_file); + my $file_phys = $physical."/".$filename; + my $file_virt = $virtual."".$filename; -

Copy

+ return error($config->{'errors'}->{'file_exists'},$virtual,{FILE => $file_virt}) if(-e $file_phys && not $cgi->param('overwrite')); -

Copy file '$virtual' to:

+ my $ascii = $cgi->param('ascii'); + my $handle = $cgi->upload('uploaded_file'); -
+ local *FILE; -END + open(FILE,">$file_phys") or return error($config->{'errors'}->{'mkfile_failed'},$virtual,{FILE => $file_virt}); + binmode(FILE) unless($ascii); - if($unused) - { - $output .= <Move/rename + # Read transferred file and write it to disk -

Move/Rename file '$virtual' to:

+ read($handle, my $data, -s $handle); + $data =~ s/\015\012|\012|\015/\n/g if($ascii); # Replace line separators if transferring in ASCII mode + print FILE $data; -
+ close(FILE); -

Delete

- -
- - -

-
-END + return devedit_reload({command => "show", file => $virtual}); } else { - $output .= <Unlock file - -

Someone else is currently editing this file. At least, the file is marked so. Maybe, someone who was editing the file, has forgotten to unlock it. In this case (and only in this case) you can unlock the file using this button:

+ my $tpl = new Template; + $tpl->read_file($config->{'templates'}->{'upload'}); -
- - -

-
-END - } + $tpl->fillin("DIR",$virtual); + $tpl->fillin("URL",equal_url($config->{'httproot'},$virtual)); + $tpl->fillin("SCRIPT",$script); - $output .= "\n
"; - $output .= htmlfoot; + my $output = header(-type => "text/html"); + $output .= $tpl->get_template; - return \$output; + return \$output; + } } # exec_copy() @@ -404,7 +538,68 @@ END sub exec_copy($$) { - 1; + my ($data,$config) = @_; + my $physical = $data->{'physical'}; + my $virtual = encode_entities($data->{'virtual'}); + my $new_physical = $data->{'new_physical'}; + + return error($config->{'errors'}->{'dircopy'}) if(-d $physical); + return error($config->{'errors'}->{'nocopy'}) unless(-r $physical); + + if($new_physical) + { + my $new_virtual = $data->{'new_virtual'}; + my $dir = upper_path($new_virtual); + $new_virtual = encode_entities($new_virtual); + + if(-e $new_physical) + { + return error($config->{'errors'}->{'exist_edited'},$dir,{FILE => $new_virtual}) if($data->{'uselist'}->in_use($data->{'new_virtual'})); + + if(-d $new_physical) + { + return error($config->{'errors'}->{'dir_replace'},$dir); + } + elsif(not $data->{'cgi'}->param('confirmed')) + { + my $tpl = new Template; + $tpl->read_file($config->{'templates'}->{'confirm_replace'}); + + $tpl->fillin("FILE",$virtual); + $tpl->fillin("NEW_FILE",$new_virtual); + $tpl->fillin("NEW_FILENAME",file_name($new_virtual)); + $tpl->fillin("NEW_DIR",$dir); + $tpl->fillin("DIR",upper_path($virtual)); + + $tpl->fillin("COMMAND","copy"); + $tpl->fillin("URL",equal_url($config->{'httproot'},$virtual)); + $tpl->fillin("SCRIPT",$script); + + my $output = header(-type => "text/html"); + $output .= $tpl->get_template; + + return \$output; + } + } + + copy($physical,$new_physical) or return error($config->{'errors'}->{'copy_failed'},upper_path($virtual),{FILE => $virtual, NEW_FILE => $new_virtual}); + return devedit_reload({command => 'show', file => $dir}); + } + else + { + my $tpl = new Template; + $tpl->read_file($config->{'templates'}->{'copyfile'}); + + $tpl->fillin("FILE",$virtual); + $tpl->fillin("DIR",upper_path($virtual)); + $tpl->fillin("URL",equal_url($config->{'httproot'},$virtual)); + $tpl->fillin("SCRIPT",$script); + + my $output = header(-type => "text/html"); + $output .= $tpl->get_template; + + return \$output; + } } # exec_rename() @@ -418,12 +613,73 @@ sub exec_copy($$) sub exec_rename($$) { - 1; + my ($data,$config) = @_; + my $physical = $data->{'physical'}; + my $virtual = $data->{'virtual'}; + my $new_physical = $data->{'new_physical'}; + + return error($config->{'errors'}->{'rename_root'},"/") if($virtual eq "/"); + return error($config->{'errors'}->{'in_use'},upper_path($virtual),{FILE => $virtual}) if($data->{'uselist'}->in_use($virtual)); + + if($new_physical) + { + my $new_virtual = $data->{'new_virtual'}; + my $dir = upper_path($new_virtual); + $new_virtual = encode_entities($new_virtual); + + if(-e $new_physical) + { + return error($config->{'errors'}->{'exist_edited'},$dir,{FILE => $new_virtual}) if($data->{'uselist'}->in_use($data->{'new_virtual'})); + + if(-d $new_physical) + { + return error($config->{'errors'}->{'dir_replace'},$dir); + } + elsif(not $data->{'cgi'}->param('confirmed')) + { + my $tpl = new Template; + $tpl->read_file($config->{'templates'}->{'confirm_replace'}); + + $tpl->fillin("FILE",$virtual); + $tpl->fillin("NEW_FILE",$new_virtual); + $tpl->fillin("NEW_FILENAME",file_name($new_virtual)); + $tpl->fillin("NEW_DIR",$dir); + $tpl->fillin("DIR",upper_path($virtual)); + + $tpl->fillin("COMMAND","rename"); + $tpl->fillin("URL",equal_url($config->{'httproot'},$virtual)); + $tpl->fillin("SCRIPT",$script); + + my $output = header(-type => "text/html"); + $output .= $tpl->get_template; + + return \$output; + } + } + + rename($physical,$new_physical) or return error($config->{'errors'}->{'rename_failed'},upper_path($virtual),{FILE => $virtual, NEW_FILE => $new_virtual}); + return devedit_reload({command => 'show', file => $dir}); + } + else + { + my $tpl = new Template; + $tpl->read_file($config->{'templates'}->{'renamefile'}); + + $tpl->fillin("FILE",$virtual); + $tpl->fillin("DIR",upper_path($virtual)); + $tpl->fillin("URL",equal_url($config->{'httproot'},$virtual)); + $tpl->fillin("SCRIPT",$script); + + my $output = header(-type => "text/html"); + $output .= $tpl->get_template; + + return \$output; + } } # exec_remove() # -# Remove a file and return to directory view +# Remove a file or a directory and return to directory view # # Params: 1. Reference to user input hash # 2. Reference to config hash @@ -436,14 +692,163 @@ sub exec_remove($$) my $physical = $data->{'physical'}; my $virtual = $data->{'virtual'}; - return error_in_use($virtual) if($data->{'uselist'}->in_use($virtual)); + return error($config->{'errors'}->{'remove_root'},"/") if($virtual eq "/"); - my $dir = upper_path($virtual); + if(-d $physical) + { + # Remove a directory - unlink($physical); + if($data->{'cgi'}->param('confirmed')) + { + rmtree($physical); + return devedit_reload({command => 'show', file => upper_path($virtual)}); + } + else + { + my $tpl = new Template; + $tpl->read_file($config->{'templates'}->{'confirm_rmdir'}); - my $output = redirect("http://$ENV{'HTTP_HOST'}$script?command=show&file=$dir"); - return \$output; + $tpl->fillin("DIR",$virtual); + $tpl->fillin("UPPER_DIR",upper_path($virtual)); + $tpl->fillin("URL",equal_url($config->{'httproot'},$virtual)); + $tpl->fillin("SCRIPT",$script); + + my $output = header(-type => "text/html"); + $output .= $tpl->get_template; + + return \$output; + } + } + else + { + # Remove a file + + return error($config->{'errors'}->{'in_use'},upper_path($virtual),{FILE => $virtual}) if($data->{'uselist'}->in_use($virtual)); + + if($data->{'cgi'}->param('confirmed')) + { + unlink($physical) or return error($config->{'errors'}->{'delete_failed'},upper_path($virtual),{FILE => $virtual}); + return devedit_reload({command => 'show', file => upper_path($virtual)}); + } + else + { + my $tpl = new Template; + $tpl->read_file($config->{'templates'}->{'confirm_rmfile'}); + + $tpl->fillin("FILE",$virtual); + $tpl->fillin("DIR",upper_path($virtual)); + $tpl->fillin("URL",equal_url($config->{'httproot'},$virtual)); + $tpl->fillin("SCRIPT",$script); + + my $output = header(-type => "text/html"); + $output .= $tpl->get_template; + + return \$output; + } + } +} + +# exec_chprop() +# +# Change the mode and the group of a file or a directory +# +# Params: 1. Reference to user input hash +# 2. Reference to config hash +# +# Return: Output of the command (Scalar Reference) + +sub exec_chprop($$) +{ + my ($data,$config) = @_; + my $physical = $data->{'physical'}; + my $virtual = $data->{'virtual'}; + my $dir = upper_path($virtual); + my $cgi = $data->{'cgi'}; + my $mode = $cgi->param('mode'); + my $group = $cgi->param('group'); + + if($users) + { + # System supports user and groups + + if(-o $physical) + { + # We own this file + + if($mode || $group) + { + if($mode) + { + # Change the mode + + my $oct_mode = $mode; + $oct_mode = "0".$oct_mode if(length($oct_mode) == 3); + $oct_mode = oct($oct_mode); + + chmod($oct_mode,$physical); + } + + if($group) + { + # Change the group using the `chgrp` system command + + return error($config->{'errors'}->{'invalid_group'},$dir,{GROUP => encode_entities($group)}) unless($group =~ /^[a-z0-9_]+[a-z0-9_-]*$/i); + system("chgrp",$group,$physical); + } + + return devedit_reload({command => 'show', file => $dir}); + } + else + { + # Display the form + + my @stat = stat($physical); + + my $mode = $stat[2]; + my $mode_oct = substr(sprintf("%04o",$mode),-4); + my $gid = $stat[5]; + + my $tpl = new Template; + $tpl->read_file($config->{'templates'}->{'chprop'}); + + # Insert file properties into the template + + $tpl->fillin("MODE_OCTAL",$mode_oct); + $tpl->fillin("MODE_STRING",mode_string($mode)); + $tpl->fillin("GID",$gid); + + if(my $group = getgrgid($gid)) + { + $tpl->fillin("GROUP",encode_entities($group)); + $tpl->parse_if_block("group_detected",1); + } + else + { + $tpl->parse_if_block("group_detected",0); + } + + # Insert other information + + $tpl->fillin("FILE",$virtual); + $tpl->fillin("DIR",$dir); + $tpl->fillin("URL",equal_url($config->{'httproot'},$virtual)); + $tpl->fillin("SCRIPT",$script); + + my $output = header(-type => "text/html"); + $output .= $tpl->get_template; + + return \$output; + } + } + else + { + return error($config->{'errors'}->{'not_owner'},$dir,{FILE => $virtual}); + } + } + else + { + return error($config->{'errors'}->{'no_users'},$dir,{FILE => $virtual}); + } } # exec_unlock() @@ -459,16 +864,128 @@ sub exec_remove($$) sub exec_unlock($$) { my ($data,$config) = @_; - my $physical = $data->{'physical'}; my $virtual = $data->{'virtual'}; my $uselist = $data->{'uselist'}; - my $dir = upper_path($virtual); + return devedit_reload({command => 'show', file => upper_path($virtual)}) if($uselist->unused($virtual)); + + if($data->{'cgi'}->param('confirmed')) + { + file_unlock($uselist,$virtual); + return devedit_reload({command => 'show', file => upper_path($virtual)}); + } + else + { + my $tpl = new Template; + $tpl->read_file($config->{'templates'}->{'confirm_unlock'}); + + $tpl->fillin("FILE",$virtual); + $tpl->fillin("DIR",upper_path($virtual)); + $tpl->fillin("URL",equal_url($config->{'httproot'},$virtual)); + $tpl->fillin("SCRIPT",$script); + + my $output = header(-type => "text/html"); + $output .= $tpl->get_template; + + return \$output; + } +} + +# exec_about() +# +# Display some information about Dev-Editor +# +# Params: 1. Reference to user input hash +# 2. Reference to config hash +# +# Return: Output of the command (Scalar Reference) + +sub exec_about($$) +{ + my ($data,$config) = @_; + + my $tpl = new Template; + $tpl->read_file($config->{'templates'}->{'about'}); + + $tpl->fillin("SCRIPT",$script); + + # Dev-Editor's version number + + $tpl->fillin("VERSION",$data->{'version'}); + + # Some path information + + $tpl->fillin("SCRIPT_PHYS",encode_entities($ENV{'SCRIPT_FILENAME'})); + $tpl->fillin("CONFIG_PATH",encode_entities($data->{'configfile'})); + $tpl->fillin("FILE_ROOT", encode_entities($config->{'fileroot'})); + $tpl->fillin("HTTP_ROOT", encode_entities($config->{'httproot'})); + + # Perl + + $tpl->fillin("PERL_PROG",encode_entities($^X)); + $tpl->fillin("PERL_VER",sprintf("%vd",$^V)); + + # Information about the server + + $tpl->fillin("HTTPD",encode_entities($ENV{'SERVER_SOFTWARE'})); + $tpl->fillin("OS",$^O); + $tpl->fillin("TIME",encode_entities(strftime($config->{'timeformat'},localtime))); + + # Process information + + $tpl->fillin("PID",$$); + + # Check if the functions getpwuid() and getgrgid() are available + + if($users) + { + # Dev-Editor is running on a system which allows users and groups + # So we display the user and the group of our process + + my $uid = POSIX::getuid; + my $gid = POSIX::getgid; + + $tpl->parse_if_block("users",1); + + # ID's of user and group + + $tpl->fillin("UID",$uid); + $tpl->fillin("GID",$gid); + + # Names of user and group + + if(my $user = getpwuid($uid)) + { + $tpl->fillin("USER",encode_entities($user)); + $tpl->parse_if_block("user_detected",1); + } + else + { + $tpl->parse_if_block("user_detected",0); + } + + if(my $group = getgrgid($gid)) + { + $tpl->fillin("GROUP",encode_entities($group)); + $tpl->parse_if_block("group_detected",1); + } + else + { + $tpl->parse_if_block("group_detected",0); + } + + # Process umask + + $tpl->fillin("UMASK",sprintf("%04o",umask)); + } + else + { + $tpl->parse_if_block("users",0); + } - $uselist->remove_file($virtual); - $uselist->save; + my $output = header(-type => "text/html"); + $output .= $tpl->get_template; - my $output = redirect("http://$ENV{'HTTP_HOST'}$script?command=show&file=$dir"); return \$output; }