# Gossamer Threads Module Library - http://gossamer-threads.com/ # # GT::FileMan::Commands # CVS Info : # $Id: Commands.pm,v 1.267 2005/04/11 17:24:03 jagerman Exp $ # # Copyright (c) 2004 Gossamer Threads Inc. All Rights Reserved. # ==================================================================== # package GT::FileMan::Commands; # =============================================================== use strict; use GT::TempFile; use GT::Base qw/:persist/; use vars qw/$ICONS $READ_SIZE %LANGUAGE/; use GT::AutoLoader; use GT::File::Tools qw/:all/; # Our nasty language hash. %LANGUAGE = ( UPLOAD_MODE => "File %s was successfully uploaded in %s mode.", MSG_LOG_OFF => "Please enter username and password to login.", MSG_MULTI_UPLOAD => "%s files have been successfully uploaded.", MSG_CHMOD_CHANGED => "Permissions on %s file(s) have been updated successfully.", MSG_SEACH_FOUND => "Your search found %s results.", MSG_REPLA_FOUND => "Your search and replace updated %s files in %s", MSG_SEACH_NOTFOUND => "Your search did not produce any results.", MSG_FILE_EDITING => "%s %s file ...(size %s bytes)- Download", MSG_FILE_CREATED => "%s has been created.", MSG_FILE_EDITED => "Changes to %s have been saved.", MSG_DIR_CREATED => "%s directory has been created.", MSG_PREFERENCES => "Your options have been saved.", MSG_UNCOMPRESS => "%s file has been unarchived.", MSG_TAR_CANCEL => "Creation of tar file has been cancelled.", MSG_TAR_CREATED => "Tar file %s has been created.", MSG_COPIED => " %s selected file/directory(s) have been copied (%s can not be copied).", MSG_MOVED => " %s selected file/directory(s) have been moved (%s can not be moved).", MSG_DEL_SUCC => "%s files and %s directories have been removed.", MSG_DEL_CURR => "You've removed the directory: %s", MSG_DEL_ALL => "You've removed the directory, and all contents recursively.", MSG_DEL_SKIP => "You've skiped the directory :%s", MSG_DEL_CANC => "You've cancelled deleting the directory", MSG_DEL_ALL_SUCC => "All child dirs and files on the selected directorys has been removed. ", MSG_CONTINUE => " click here to continue.", MSG_PWD_CHANGED => "Your password was changed. ", MSG_DEMO => "Disabled in Demo.", MSG_USER_ADDED => "%s was added successfully.", MSG_USER_DELETED => "%s was deleted successfully.", MSG_USER_RMALL => "Users were deleted sucessfully.", ERR_DEL => "Can not remove file(s)", ERR_CHMOD => "Can not change mode ", ERR_FILE_OPEN => "Can not open file: %s", ERR_FILE_EMPTY => "File %s is empty.", ERR_FILE_EXISTS => "File %s exists.", ERR_FILE_NOT_EXISTS => "File %s does not exist.", ERR_FILE_PERM => " Sorry, but we don't have write access to the htaccess files: '%s' and '%s'", ERR_FILE_PEM => "The %s directory is not writeable.", ERR_NOT_TEXT_FILE => "File %s is not a text file.", ERR_DIR_NOT_EXISTS => "Directory %s does not exist.", ERR_DIR_PEM => "The %s is not writeable.", ERR_DIR_PERM => "Please check permission.", ERR_NOT_ISFILE => "%s is a directory.", ERR_TMP_FILE => "Can not open temp file.", ERR_FREE_SPC => "Upload: Not enough free space to upload that file.", ERR_RM_FILE => "Unable to remove file: %s. Reason: %s", ERR_UPLOAD => "Unable to upload file: %s. Reason: %s.", ERR_FILE_SAVE => "Cannot save file %s. Check permissions.", ERR_DIR_EXISTS => "Directory %s already exists.", ERR_NAME => "Illegal Characters in Directory. Please use letters, numbers, - and _ only.", ERR_FILE_NAME1 => "No double .. allowed in file names.", ERR_FILE_NAME2 => "No leading . in file names.", ERR_READ_DIR => "Can not open dir: %s. Reason: %s", ERR_DIR_DEEP => "Directory level too deep.", ERR_DISK_SPACE => "Not enough space to save it (free space is %s kb)", ERR_UNCOMPRESS => "Select files or directories before to uncompress.", ERR_TAR => "Error: %s.", ERR_TAR_NOT_EXISTS => "Can not create a tar file: %s", ERR_TAR_PEM => "Can not create a tar file %s. Check permission.", ERR_DOWNLOAD => "You selected a directory !", ERR_LOGIN => "Invalid Username and Password.", ERR_INVALID => "Input value has invalid characters : %s ", ERR_NOT_FILE => "The %s is not a file", ERR_OLD_PASSWORD => "Invalid Old password", ERR_NEW_PASSWORD => "New password must be more than 3 character", ERR_OPEN_FILE => "Can not open %s file, reason: %s", ERR_WRITEABLE => "Can not save %s file, reason: %s", ERR_NO_AZIP => "Please install the Archive::Zip library which is required.", ERR_NO_GZIP => "Please install the Compress::Zlib library which is required.", COBALT_NOREMOTE => "FileMan is not currently running under server authentication!", ERR_VERSION => "This action does not support for your current version!", ERR_PRINT => "Please select the files which are required text or image files", PRINT_NEXT => "Print Next", COBALT_NOUSER => "Unable to lookup user '%s'", COBALT_BADUID => "Invalid user '%s' (%s)", COBALT_CANTSU => "Can't switch to user '%s' (%s,%s). Reason: '%s'", COBALT_BADDIR => "Invalid home directory '%s'. It does not look like a standard Raq director.", COBALT_BADGROUP => "This program is restricted to site administrators only. You must be in the site administer group in order to use this." ); # Mapping of image name to icon files. $ICONS = { 'gif jpg jpeg bmp' => ['image2.gif' => 'Image File'], 'txt' => ['text.gif' => 'Text File'], 'cgi pl pm' => ['text.gif' => 'Script File'], 'zip gz tar' => ['compressed.gif' => 'Compressed File'], 'htm html shtm shtml' => ['ie.gif' => 'Html File'], 'wav au mid mod mp3' => ['sound.gif' => 'Sound File'], 'exe' => ['binary.gif' => 'Binary File'], 'doc' => ['doc.gif' => 'MS Word'], 'xls' => ['xls.gif' => 'MS Excel'], 'pdf' => ['pdf.gif' => 'Adobe Acrobat'], 'unknown' => ['unknown.gif' => ''], }; # How large a chunk should we read into memory at once. $READ_SIZE = 500000; sub DESTROY {} $COMPILE{cmd_main_display} = __LINE__ . <<'END_OF_SUB'; sub cmd_main_display { # ------------------------------------------------------------------ # Display main page # my ($self, $args, $type) = @_; # Load user list from .htpassword if it exists if ($args->{show_passwd} or $self->{cgi}->{show_passwd}) { $self->{url_opts} .= ';show_passwd=1' if ($self->{url_opts} !~ /show_passwd/); my $htpasswd = $self->load_htpasswd(); foreach (keys %$htpasswd) { $args->{$_} ||= $htpasswd->{$_}; } } $self->list_files(); $self->{cgi}->{cmd_do} = 'cmd_command' if ($type); $self->page('main.html', $args); } END_OF_SUB $COMPILE{load_htpasswd} = __LINE__ . <<'END_OF_SUB'; sub load_htpasswd { my $self = shift; my $pass_path = $self->{in}->cookie('def_passwd_dir'); my ($htpasswd, $exist, $delete_list); if (!$self->{cfg}->{passwd_dir_level} and !$pass_path =~ /^$self->{cfg}->{root_dir}/) { print $self->{in}->header (-cookie => [ $self->{in}->cookie ( -name => 'def_passwd_dir', -value => '0', -expires => '+5y')]); $pass_path = ''; } if ($pass_path) { # create .htaccess and .htpasswd in Password directory my $file_name = $self->_safe_dir(); $file_name =~ s/[\/ \:]/\_/g; $htpasswd = "$pass_path/.htpass$file_name"; $exist = 1 if (-e $htpasswd); } else { my $fpasswd = $self->_safe_file(".htpasswd", {fullfile => 1, exist => 1}); $htpasswd = $fpasswd->{file}; $exist = 1 if ($fpasswd->{exist}); } my $faccess = $self->_safe_file(".htaccess", {fullfile => 1, exist => 1}); my $htaccess = $faccess->{file}; if ($exist and $faccess->{exist}) { open (HTPAS, "< $htpasswd") or die "Unable to open: $htpasswd ($!)"; my @users = ; close HTPAS; $delete_list = "" if (@users); } return { delete_list => $delete_list, pass_path => $pass_path }; } END_OF_SUB $COMPILE{list_files} = __LINE__ . <<'END_OF_SUB'; sub list_files { # ------------------------------------------------------------------ # Displays a list of files for a given work_path. # my $self = shift; my $do = shift || 'cmd_main_display'; my $only_dir = $self->{cfg}->{only_dir}; #only display directory listings my $work_path = $self->{work_path}; my $real_work_path = $self->_safe_dir(); my $html_url = $self->{cfg}->{html_root_url} || ''; my $url_opts = $self->{url_opts} || ''; my $url = "$self->{http_ref}?fdo=$do;$url_opts"; my $list; # Check if we have data already to list if (ref $self->{results} eq 'ARRAY') { $list = $self->{results}; } else { # Else get the list of files using readdir. opendir (DIR, $real_work_path) or die sprintf ($LANGUAGE{ERR_READ_DIR}, $real_work_path, "$!"); @$list = readdir(DIR); closedir (DIR); } # Create path string my ($string, $spath, $parent, $path) = ('', '', '', []); $path = [split /\//, $self->{work_path}] if ($self->{work_path}); $string = 'root: ' ; for my $ii (0.. $#$path) { next if (@$path[$ii] eq ''); $spath .= (($spath) ? '/' : '').@$path[$ii]; $parent .= (($parent) ? '/' : '').@$path[$ii] if ($ii < $#$path); $string .= "/".$path->[$ii].""; } # Create data array to sort my ($list_dir, $list_file, $readme, $num_objects, $total_space); foreach my $file (@$list) { next if ($file eq '.'); next if ($file eq '..'); next if (!$self->{in}->cookie('hidden_file') and $file =~ /^\./); #don't show hidden file my $fullfile = "$real_work_path/$file"; next if ($only_dir and (!-d $fullfile)); # next if not directory my @stat = stat($fullfile); my $hash; $readme = $file if (uc($file) eq 'README'); @$hash{'name', 'size', 'date', 'perm', 'nsize'} = ($file, $stat[7], $stat[9], $stat[2], $stat[7]); $hash->{user} = eval { getpwuid($stat[4]); } || ''; $num_objects++; if (-d $fullfile) { $hash->{disabled} = 1 if not -x _; $hash->{nsize} = 0; push @$list_dir, $hash; } else { $hash->{type} = _get_icon($file)->{type}; $hash->{disabled} = 1 if (!-r $fullfile); $total_space += $hash->{size}; push @$list_file,$hash; } } my $orderby = $self->{cgi}->{sb} || $self->{in}->cookie('def_sort') || 'name'; my $sortdown = !$self->{cgi}->{sd}; $list_file = $self->qsort($list_file,$orderby,$sortdown) if ($#$list_file > 0); $list_dir = $self->qsort($list_dir,$orderby,$sortdown) if ($#$list_dir > 0); # Get the full filename, file size, file modification date and file permissions. foreach (@$list_dir) { $_->{icon} = ""; $_->{isdir}= '1'; $_->{type} = 'File Folder'; $_->{size} = ''; $_->{date} = _get_date($_->{date}); $_->{perm} = _print_permissions($_->{perm}); } foreach (@$list_file) { my $spec = _get_icon($_->{name}); $_->{icon} = ""; $_->{isdir}= '0'; $_->{size} = _print_filesize($_->{size}); $_->{date} = _get_date($_->{date}); $_->{perm} = _print_permissions($_->{perm}); } my ($sorted, $speed_bar, $output); @$sorted = ($sortdown) ? (@$list_dir, @$list_file) : (@$list_file, @$list_dir); # Prepare output after sort # Skip pages my $pg = $self->{cgi}->{pg} || 1; #current page my $r_pg = $self->{in}->cookie('def_files_page') || 25; my $def_files = $self->{in}->cookie('def_files_page') || ''; my $count = 0; if ($def_files ne 'all' and $pg ne 'all'){ my $skip = 0; foreach (@$sorted) { $skip++; if (($#$sorted >= $r_pg) and ($pg > 0)) { my $r_start = ($pg == 1) ? 1 : (($pg - 1) * $r_pg + 1); next if ($skip < $r_start); $count++; last if ($count == $r_pg); } push @$output, $_; } $speed_bar = $self->speed_bar($#$sorted + 1) if ($#$sorted >= $r_pg); } # else all rows else { $speed_bar = $self->speed_bar($#$sorted + 1) if ($#$sorted >= $r_pg and $pg eq 'all'); $output = $sorted; } $self->{work_path} and unshift @$output, { 'icon' => "", 'name' => "Parent Directory", 'type' => '', 'size' => ' ', 'date' => ' ', 'perm' => '', 'user' => ' ' }; # Build columns title my $sort_title; my $cols; @$cols{'name', 'size', 'date', 'perm', 'user', 'type', 'view'} = ('Name', 'Size', 'Modified', 'Permissions', 'Owner', 'File Type', 'View'); foreach (keys %$cols) { my $temp = "{$_}.'' ; $temp .= (($_ eq $orderby) ? (($sortdown) ? " " : " ") : ''); $sort_title->{'s'.$_} = $temp; } my $msg_readme; if ($readme) { $msg_readme = "

Readme File:"; open (DATA, "<$real_work_path/$readme") or return $self->cmd_main_display({reload => 1, status => "$!"}); $count = 0; while () { chomp; next if ( $_ =~ /^\#/ or !$_); $msg_readme .= (($msg_readme)? "
":"").$_; $count++; last if ($count == 10); } close DATA; $msg_readme .= "

"; } # Return data $self->{data} = { pg => $pg, %$sort_title, string => $string, results => $output, speed_bar => $speed_bar, readme => $msg_readme, num_objects => $num_objects, total_space => $total_space, count => ($count) ? (($count > 10) ? $count - 1 : $count) : $#$output + 1, }; if ($self->{cfg}->{allowed_space}){ my $disk_space = $self->_checkspace(); foreach (keys %$disk_space) { $self->{data}->{$_} = $disk_space->{$_}; } $self->{data}->{allowed_space} = sprintf('%.1fMB', $self->{cfg}->{allowed_space} / (1024*1024)); # Format space limit } return 1; } END_OF_SUB $COMPILE{cmd_show} = __LINE__ . <<'END_OF_SUB'; sub cmd_show { # ------------------------------------------------------------------ # display with unusual template # my ($self, $args) = @_; $args ||= {}; my $template = $self->{cgi}->{page} || 'file_editor.html'; if ($template eq 'file_editor.html') { ($self->{cgi}->{content} =~ /\
{cgi}->{content} =~ s/{cgi}->{content} = $self->{in}->html_escape($self->{cgi}->{content}) if (!$args->{error} and $self->{cgi}->{content}); if (!defined $args->{use_html} and $self->get_browser(1) and !$self->{in}->cookie('editor_mode')) { $args->{use_html} = 1; } return $self->page($template, { editor_mode => (!$self->{in}->cookie('editor_mode')) ? 0 : 1, rows => $self->{in}->cookie('rows') || 20, cols => $self->{in}->cookie('cols') || 100, %$args }); } elsif ($template eq 'preferences.html') { my $def_passwd_dir = $self->{in}->cookie('def_passwd_dir') || $self->{cgi}->{def_passwd_dir}; $def_passwd_dir =~ s/$self->{cfg}->{root_dir}\/// if (!$self->{cfg}->{passwd_dir_level}); return $self->page($template, { def_sort => $self->{in}->cookie('def_sort') || $self->{cgi}->{def_sort} , def_working_dir => $self->{in}->cookie('def_working_dir') || $self->{cgi}->{def_working_dir}, def_files_page => $self->{in}->cookie('def_files_page') || 25, def_pages_screen => $self->{in}->cookie('def_pages_screen') || 20, readme_position => $self->{in}->cookie('readme_position') || 'Y', hidden_file => $self->{in}->cookie('hidden_file') || '0', editor_mode => $self->{in}->cookie('editor_mode') || '0', passwd_dir_level => $self->{cfg}->{passwd_dir_level}, def_passwd_dir => ($def_passwd_dir eq '0') ? '' : $def_passwd_dir, %$args }); } $self->page ($template,$args); } END_OF_SUB $COMPILE{cmd_cd} = __LINE__ . <<'END_OF_SUB'; sub cmd_cd { #------------------------------------------------------------------ # CD command # my $self = shift; my $result = $self->_cd_check(); return $self->cmd_main_display({ reload => 1, status => $result->{status} }, 1) if ($result->{status}); # not safe $self->{work_path} = $result->{work_path}; $self->{cgi}->{work_path} = $result->{work_path}; $self->cmd_main_display(); } sub _cd_check { #---------------------------------------------------------------- # check cd command # my $self = shift; my $input = $self->{cgi}->{txt_input}; my $root_path = $self->{cfg}->{root_dir}; my $fulldir = $self->_safe_dir($input,{ exist => 1, write => 1}); return {status => sprintf($LANGUAGE{ERR_INVALID}, $input), work_path => ''} if ($fulldir == -1); # not safe return {status => sprintf($LANGUAGE{ERR_DIR_NOT_EXISTS}, $input), work_path => ''} if (ref $fulldir eq 'HASH' and !$fulldir->{exist}); # not exist (my $dir = $fulldir->{fulldir}) =~ s,$root_path/,,; return { status => '', work_path => $dir}; } END_OF_SUB $COMPILE{cmd_search} = __LINE__ . <<'END_OF_SUB'; sub cmd_search { #---------------------------------------------------------------- # Search command # my ($self, $repl) = @_; my ($results, $string, $spath); my $sortdown = !$self->{cgi}->{sd}; my $work_path = $self->{work_path} || ''; my $orderby = $self->{cgi}->{sb} || $self->{in}->cookie('def_sort') || 'name'; my $pg = $self->{cgi}->{pg} || '1'; #current page my $r_pg = $self->{in}->cookie('def_files_page') || '25'; my $search = $self->{cgi}->{txt_input}; my $url_opts = $self->{url_opts} || ''; $pg = 'all' if ($r_pg eq 'all'); my ($r_start, $files); $search =~ s/[\/\\]//g; $search =~ s,\*,.*?,g; $search =~ s,\?,.?,g; # Initial value for url my $scope = $self->{cgi}->{scope}; my $src_opts= "scope=$scope&c_case=$self->{cgi}->{c_case}&c_content=$self->{cgi}->{c_content}"; my $url = "$self->{http_ref}?fdo=cmd_main_display&$url_opts"; my $url_pg = "$self->{http_ref}?cmd_do=cmd_search&cmd=search&txt_input=".(($repl) ? $self->{cgi}->{txt_with} : $search)."&work_path=$work_path&$url_opts"; my $path = [split /\//, $work_path]; if (! $scope) { # All of root my $fulldir = $self->_safe_dir(); find($fulldir, sub {push @$files, shift}); } else { # Selected files my $selected = [$self->{in}->param('c_edit')]; foreach (@$selected) { my $fulldir = $self->_safe_dir($_); next if ($fulldir == -1); find($fulldir->{fulldir}, sub {push @$files, shift}); $src_opts .= "&c_edit=$_"; } } $url_pg .= "&$src_opts"; # Search data if ($repl) { # replace $results = $self->_replace($files); } else { # search data if (!$self->{cgi}->{c_content}) { # file name foreach my $file (@$files) { my ($name) = $file =~ m,/([^/]+)$,; #just get only the file name next if ($name eq $self->{work_path}); # don't take the work_path if ($self->{cgi}->{c_case}) { # None Case Sensitive push @$results, $self->_file_info($file) if ($name =~ m,$search,); } else { push @$results, $self->_file_info($file) if ($name =~ m,$search,i); } } } else { # contents $results = $self->_search_content($files); } } #Push data of current page into an output array. my ($skip, $output, $total_space, $msg); if ($pg eq 'all') { $output = $results; } else { $r_start = ($pg == 1) ? 0 : (($pg - 1) * $r_pg ); for my $ii (0 .. $#$results) { $total_space += @$results[$ii]->{size}; if ($ii >= $r_start and $#$output < $r_pg - 1) { push @$output, @$results[$ii]; } } } $string = "root: "; for my $ii (0.. $#$path) { next if (@$path[$ii] eq ''); $spath .= (($spath) ? '/' : '') . @$path[$ii]; $string .= "/".@$path[$ii].""; } if ($#$results >= 0) { $msg = ($repl) ? sprintf ($LANGUAGE{MSG_REPLA_FOUND}, $#$results + 1, ($scope)? '' : 'in ' . (($work_path) ? '/' : 'Root').$work_path) : sprintf ($LANGUAGE{MSG_SEACH_FOUND}, $#$results + 1, ($scope)? '' : 'in ' . (($work_path) ? '/' : 'Root').$work_path); } else { $msg = $LANGUAGE{MSG_SEACH_NOTFOUND}; } # Sort data my ($cols, $sort_title, $speed_bar); @$cols{'name','size','date','perm','user','type','view'} = ('Name','Size','Modified','Permissions','Owner','File Type','View'); foreach (keys %$cols) { my $temp = "{$_}."" ; $temp .= ( ( $_ eq $orderby ) ? ( ($sortdown) ? "  ^" : "  v" ) : '' ); $sort_title->{'s'.$_} = $temp; } # Create speed bar $speed_bar = $self->speed_bar($#$results,"$url_pg&sb=$orderby") if (($#$results - 1) > $r_pg and $r_pg > 0); $output = $self->qsort($output,$orderby,$sortdown) if ($#$output > 1); foreach (@$output) { $total_space += $_->{size} if ($pg eq 'all'); $_->{size} = _print_filesize($_->{size}); $_->{perm} = _print_permissions($_->{perm}); $_->{date} = _get_date($_->{date}); } $self->{data} = { url => "$self->{http_ref}", results => $output,%$sort_title, string => $string, total_space=> $total_space, num_objects=> (($#$results >=0)? $#$results+1:0), status => "$msg", speed_bar => $speed_bar, search => 1, reload => 1 }; $self->page('main.html',{reload=>1}); } sub _search_content { #------------------------------------------------------------------- # search contents # my ($self, $files) = @_; my $results; my $search = $self->{cgi}->{txt_input}; $search = quotemeta($search) if ($self->{cgi}->{c_regex}); foreach my $file (@$files) { if (-T $file) { # Text file next if (!open(SOURCE, "< $file")); my $buffer; if (-s SOURCE < $READ_SIZE) { read (SOURCE, $buffer, -s SOURCE); if ($self->{cgi}->{c_case}) { # None Case Sensitive push @$results, $self->_file_info($file) if ($buffer =~ m,$search,); } else { push @$results, $self->_file_info($file) if ($buffer =~ m,$search,i); } } else { while (read SOURCE, $buffer, $READ_SIZE) { if ($self->{cgi}->{c_case}) { #None Case Sensitive if ($buffer =~ m,$search,) { push @$results, $self->_file_info($file); last; } } else { if ($buffer =~ m,$search,i) { push @$results, $self->_file_info($file); last; } } } } close SOURCE; } } return $results; } END_OF_SUB $COMPILE{cmd_replace} = __LINE__ . <<'END_OF_SUB'; sub cmd_replace { #----------------------------------------------------------------- # Search and replace # my $self = shift; $self->cmd_search(1); } sub _replace { #----------------------------------------------------------------- # Search and replace contents # my ($self, $files) = @_; my ($write, $results); my $search = $self->{cgi}->{txt_input}; my $with = $self->{cgi}->{txt_with}; if ($self->{cgi}->{c_word}) { $search = " $search "; $with = " $with "; } $search = quotemeta($search) if ($self->{cgi}->{c_regex}); foreach my $file(@$files) { if ((-T $file) and (-w $file)) { next if (!open(SOURCE, "<$file")); my ($buffer, $found, $tmp); while (read SOURCE, $buffer, $READ_SIZE) { if ($self->{cgi}->{c_case}) { #None Case Sensitive if ($buffer =~ m,$search,) { $found = 1; last; } } else { if ($buffer =~ m,$search,i) { $found = 1; last; } } } close SOURCE; if ($found) { my $tempfile = new GT::TempFile; if (!$self->{cfg}->{winnt}) { $file =~ m,^([\/\w.-]+)$,; $file = $1; #untainted } $tmp = _fcopy($file, "$$tempfile.tmp"); $tmp = _fcopy("$$tempfile.tmp", $file, $search, $with, $self->{cgi}->{c_case}); _fcopy("$$tempfile.tmp","$file.bak") if ($self->{cgi}->{c_bak}); # create a .bak file push @$results, $self->_file_info($file) if ($tmp); $self->history("cmd_replace|$file|$search with $with") if ( $self->{cfg}->{multi} ); #save log inf } } } return $results; } END_OF_SUB $COMPILE{cmd_command} = __LINE__ . <<'END_OF_SUB'; sub cmd_command { #---------------------------------------------------------------- # execute a command # my $self = shift; $ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin'; #for taint mode my $server_name = $ENV{'SERVER_NAME'}; my $html_url = $self->{cfg}->{html_root_url}; my $url_opts = $self->{url_opts} || ''; my $work_path = $self->{work_path} || ''; my $working_dir = $self->{cgi}->{working_dir} || $self->_safe_dir(); my $cmd = $self->{cgi}->{txt_input} || ''; my $css_file = $self->{in}->cookie('scheme') || 'fileman'; my $full_path = $self->{cfg}->{root_dir}.(($work_path)? "/$work_path" : ''); my ($prompt, $run_file); $self->history("cmd_command|$cmd") if ( $self->{cfg}->{multi} );#save log info if ($self->{cgi}->{c_edit}) { $run_file = $full_path.'/'.$self->{cgi}->{c_edit}; $cmd = $run_file.' '.$cmd; } print $self->{in}->header; chdir ($working_dir); # ping command my $font = $self->{in}->cookie('font'); if ($cmd =~ m,^\s*ping\s*, or $self->{cgi}->{long}) { $prompt = $self->{cfg}->{winnt} ? "$working_dir> " : "[". eval { getpwuid($<) } ."\@$server_name ".($working_dir || '/')."]"; my $command_time_out = $self->{cfg}->{command_time_out} || 60; my ($pid, $oldfh); if(!$self->{cfg}->{winnt}) { $SIG{ALRM} = sub { die "timeout"}; alarm($command_time_out); } print qq! {cfg}->{html_root_url}/$css_file.css>

$font $prompt $cmd

        !;
        eval {
                $pid   = open (TMP, "$cmd |");
                $oldfh = select(TMP); $| = 1; select($oldfh);
                while(){
                    s/(\n|\r\n)$//;
                    print GT::CGI->html_escape($_), "\n";
                }
                close (TMP) or die $@;
        };
        if ($@) {
            if ($@ =~ /timeout/) {
                my $ret = kill ('INT', $pid);
                $ret ? print "Command timed out." : print "Command timed out. Unable to kill: $!";
            }
            else {
                die $@;
            }
        }
        print "

"; } else { # Other command my ($output,$errors) = ('',''); if ($cmd or $self->{cgi}->{runfile}) { my $tmp_output = new GT::TempFile; # create a result file my $tmp_errors = new GT::TempFile; # create a error file if ($self->{cfg}->{winnt}) { #for WinNT system ("$cmd 1> $$tmp_output 2> $$tmp_errors"); } else { system ("$cmd 2> $$tmp_errors 1> $$tmp_output"); } open (TMP, "< $$tmp_output") or return $self->cmd_main_display({reload => 1, status => $!}); read (TMP, $output, -s TMP); close TMP; open (TMP, "< $$tmp_errors") or return $self->cmd_main_display({reload => 1, status => $!}); read (TMP, $errors, -s TMP); close TMP; if (($cmd =~ m/^\s*cd\s+(.+)/) and !$errors) { ($self->{cfg}->{winnt} and $working_dir !~ m,^/,) and $working_dir = '/'.$working_dir; $working_dir = _command_show($working_dir,$cmd) || {}; ($self->{cfg}->{winnt}) and $working_dir =~ s,/,,; } $output = $self->{in}->html_escape($output) if ($output); $errors ||= ''; } my $action = ($cmd)? '' : "onload='top.js_cmd_command(1)'"; $prompt = $self->{cfg}->{winnt} ? "$working_dir> " : "[". eval { getpwuid($<) } ."\@$server_name ".($working_dir || '/')."]"; print qq! $font

$prompt $cmd

$output
$errors
!; } } END_OF_SUB $COMPILE{cmd_upload} = __LINE__ . <<'END_OF_SUB'; sub cmd_upload { # ----------------------------------------------------- # upload a files # my ($self, $data) = @_; # $ENV{'PATH'} = ''; #for taint mode warning $data ||= $self->{in}->param('txt_input'); my $work_path = $self->{work_path}; my $path = $self->{cfg}->{root_dir}.(($work_path)? "/$work_path" : ''); if (!-w $path) { # Current directory does not writeable my $msg = sprintf($LANGUAGE{ERR_FILE_PEM},($work_path) ? $work_path : 'Root'); ($self->{in}->param('txt_input')) ? return $self->cmd_main_display({ reload => 1 , status => $msg }) : return (0, $msg); } my $free_space = 0; if ($self->{cfg}->{allowed_space} > 0) { my $disk_space = $self->_checkspace($self->{cfg}->{root_dir}); $free_space = $disk_space->{free_space}; } my $filename = $data; my $mode = $self->{cgi}->{type}; $filename =~ s/.*?([^\\\/:]+)$/$1/; $filename =~ s/[\[\]\s\$\#\%'"]/\_/g; # Change the name if needed if ($self->{cgi}->{name} eq 'uppercase') { $filename =~ s/(\w+)/\U$1/gi; } elsif ($self->{cgi}->{name} eq 'lowercase') { $filename =~ s/(\w+)/\L$1/gi; } # Get the full file name and save the file. my ($bytesread, $buffer, $fullfile, $file_size); my $file = $self->_safe_file ($filename, { fullfile => 1, exist => 1, write => 1}); return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_INVALID}, $filename)}) if ($file == -1); # not safe $fullfile = $file->{file}; if (!$self->{cfg}->{winnt}) { $fullfile =~ m,^([\/\w.-]+)$,; $fullfile = $1; #untainted } if (!$self->{in}->param('txt_input')) { #multi upload return (0, sprintf($LANGUAGE{ERR_FILE_EXISTS}, $filename)) if ($file->{exist} and !$self->{cgi}->{overwrite}); return (0, sprintf($LANGUAGE{ERR_FILE_PEM}, $filename)) if ($file->{exist} and !$file->{write} and $self->{cgi}->{overwrite}); } else { return $self->cmd_main_display({ reload => 1 , status =>sprintf($LANGUAGE{ERR_FILE_EXISTS}, $filename)}) if ($file->{exist} and !$self->{cgi}->{overwrite}); return $self->cmd_main_display({ reload => 1 , status =>sprintf($LANGUAGE{ERR_FILE_PEM}, $filename)}) if ($file->{exist} and !$file->{write} and $self->{cgi}->{overwrite}); } $file_size = 0; open (OUTFILE, ">$fullfile") ; binmode (OUTFILE); while ($bytesread=read($data,$buffer,1024)) { if ($mode eq 'ascii') { $buffer =~ s,\r\n,\n,g; } print OUTFILE $buffer; $file_size += 1024; if ($self->{cfg}->{allowed_space} > 0) { if (($file_size / 1024) > $free_space) { close OUTFILE; unlink ($fullfile); ($self->{in}->param('txt_input')) ? return $self->cmd_main_display({ reload => '1', status => $LANGUAGE{ERR_FREE_SPC}}) : return (0,$LANGUAGE{ERR_FREE_SPC}); } } } close OUTFILE; if ($mode eq 'auto') { if (-T $fullfile) { open (FILE, "< $fullfile") or die sprintf($LANGUAGE{ERR_FILE_OPEN}, $fullfile, "$!"); read (FILE, my $data, -s FILE); close FILE; $data =~ s,\r\n,\n,g; open (FILE, "> $fullfile") or die sprintf($LANGUAGE{ERR_FILE_OPEN}, $fullfile, "$!"); print FILE $data; close FILE; $mode = 'ascii/text'; } } # Change mode if ($self->{cfg}->{upload_chmod}) { my $octal_perm = oct($self->{cfg}->{upload_chmod}); # Permissions have to be in octal chmod($octal_perm, $fullfile) if $octal_perm; # 0 _probably_ means not octal, because 0 is an odd permission to use } my $status; if (-s $fullfile == 0) { unlink ($fullfile); $status = sprintf($LANGUAGE{ERR_UPLOAD}, $filename, "File is 0 bytes."); } else { $status = sprintf($LANGUAGE{UPLOAD_MODE},$filename,$mode); } $self->cmd_main_display({ reload=>1 , status => $status}) if ($self->{in}->param('txt_input')); if (-e $fullfile || -s $fullfile != 0) { if ( $self->{cfg}->{multi} ) { #save log info my $from = $fullfile; $from =~ s/$path\///; $self->history("cmd_upload|$from|$path"); } return (1, $status); } else { return (0, $status); } } END_OF_SUB $COMPILE{cmd_mul_upload} = __LINE__ . <<'END_OF_SUB'; sub cmd_mul_upload { # ----------------------------------------------------- # upload nulti files # my $self = shift; my $count = 0; my $msg = ''; for my $i(1..10) { my $data = $self->{in}->param('file'.$i); next if (!$data); my ($result, $status) = $self->cmd_upload ($data); $result ? $count++ : ($msg .= $status . '
'); } $self->{cgi}->{cmd_do} = 'cmd_upload'; $self->cmd_main_display ( { reload => 1 , status => $count ? sprintf($LANGUAGE{MSG_MULTI_UPLOAD},$count) : $msg } ); } END_OF_SUB $COMPILE{cmd_editor} = __LINE__ . <<'END_OF_SUB'; sub cmd_editor { #------------------------------------------------------------- # Editor a text file # my $self = shift; my $url_opts = $self->{url_opts} || ''; my $filename = $self->{cgi}->{filename} || ''; my $work_path= $self->{work_path} || ''; my $root_path= $self->{cfg}->{root_dir}; my $data = $self->{cgi}->{content} || ''; my $fullfile; # Store number of rows and cols for TEXTAREA object into cookie if ($self->{cgi}->{resize}) { my $rows = $self->{cgi}->{rows} || 20; my $cols = $self->{cgi}->{cols} || 100; $rows = 20 if ($rows > 50); $cols = 100 if ($cols > 200); print $self->{in}->header( -cookie => [ $self->{in}->cookie( -name => 'cols', -value => $cols), $self->{in}->cookie( -name => 'rows', -value => $rows) ] ); my $size = 0; if ($filename) { my $file = $self->_safe_file($filename,{ size => 1}); $size = $file->{size}; } my $status = sprintf($LANGUAGE{MSG_FILE_EDITING}, 'Editing ', $filename, $size, $filename); return $self->cmd_show({ content => $self->{in}->html_escape($data), rows => $rows, cols => $cols, status => $status, use_html => 0, old => ($self->{cgi}->{filename})? 1 : 0 }); } # Switch to HTML or TEXT layout elsif ($self->{cgi}->{switch_edit}) { my $switch = ($self->{cgi}->{use_html}) ? 0 : 1; my $filename = $self->{cgi}->{filename}; if ($filename) { my $file = $self->_safe_file($filename,{ write => 1, text => 1, fullfile => 1, size => 1, isfile => 1}); return $self->cmd_show({ msg => sprintf($LANGUAGE{ERR_INVALID}, $filename)}) if ($file == -1); # not safe return $self->cmd_show({ msg => sprintf($LANGUAGE{ERR_NOT_FILE}, $filename)}) if (!$file->{isfile}); # not a file my $status = sprintf($LANGUAGE{MSG_FILE_EDITING},'Editing ', $filename, $file->{size}, $filename); return $self->cmd_show({ use_html => $switch, filename => ($filename =~ m,^/,) ? '' : $filename, old => ($filename =~ m,^/,) ? 0 : 1, use_html => $switch, writeable=> $file->{write} }); } else { return $self->cmd_show({ use_html => $switch }); } } # Save the contents ($self->{cgi}->{save}) ? ($filename = $self->{cgi}->{filename}) : ($filename = $self->{cgi}->{filenew}); my $old = $self->{cgi}->{fileold}; my $msg = $self->_valid_name_check($filename); return $self->cmd_show({msg => $msg, old => $old, use_html => $self->{cgi}->{use_html}}) if ($msg); $self->{cgi}->{content} = $self->{in}->html_escape($data); my $file = $self->_safe_file($filename, { fullfile => 1, exist => 1}); return $self->cmd_show({msg => sprintf($LANGUAGE{ERR_INVALID}, $filename), old => $old}) if ($file == -1); # not safe $fullfile = $file->{file}; if (($file->{exist}) and (!$old or $filename eq $self->{cgi}->{filenew})) { #file already exists my $tempfile = new GT::TempFile; open (FILE, "> $$tempfile.tmp") or return $self->cmd_show({ msg => $LANGUAGE{ERR_TMP_FILE}, old => $old}); print FILE $data; close FILE; return $self->page('file_editor_confirm.html', { filename => $filename, tmp_file => "$$tempfile.tmp"}); } $self->editor_process($filename,$data); } END_OF_SUB $COMPILE{editor_process} = __LINE__ . <<'END_OF_SUB'; sub editor_process { #------------------------------------------------------- # Save the contents to a file # my ($self, $filename, $contents) = @_; if (!$filename) { $filename = $self->{cgi}->{filename}; my $tmp_file ||= $self->{cgi}->{tmp_file}; open (DATA,"<$tmp_file") or return $self->cmd_main_display({ reload => 1, status => $LANGUAGE{ERR_TMP_FILE}, error => 1 }); read (DATA, $contents, -s DATA); close DATA; } my $file = $self->_safe_file($filename,{ fullfile => 1}); my $old = $self->{cgi}->{fileold}; if ($file == -1) { $self->{cgi}->{content} = $self->{in}->html_escape($contents); return $self->cmd_show({msg => sprintf($LANGUAGE{ERR_INVALID}, $filename), old => $old, error => 1 }); # not safe } my $fullfile = $file->{file}; open(FILE,">$fullfile") or return $self->cmd_show({ msg => sprintf($LANGUAGE{ERR_FILE_OPEN}, $filename), old => $old, error => 1 }); # Strip windows linefeeds. $contents =~ s,\r\n,\n,g; print FILE $contents; close(FILE); if (-e $fullfile) { $self->history("cmd_edit|$fullfile") if ( $self->{cfg}->{multi} ); #save log info" $self->{cgi}->{cmd_do} = 'cmd_command'; my $status = (!$old) ? sprintf($LANGUAGE{MSG_FILE_CREATED}, $filename) : sprintf($LANGUAGE{MSG_FILE_EDITED}, $filename); return $self->cmd_main_display({ reload => '1', status => $status}); } return $self->cmd_show({ msg => sprintf($LANGUAGE{ERR_FILE_SAVE}, $filename)}); } END_OF_SUB $COMPILE{cmd_makedir} = __LINE__ . <<'END_OF_SUB'; sub cmd_makedir { #----------------------------------------------- # Make directory # my $self = shift; # Get the full path. my $new = $self->{cgi}->{txt_input}; my $msg = $self->_valid_name_check($new); return $self->cmd_main_display({ reload => '1', status => $msg}) if ($msg); my $work_path = $self->{work_path} || ''; my $fulldir = $self->_safe_dir($new, { exist => 1 } ); return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_INVALID}, $new)}) if $fulldir == -1; if ($fulldir->{exist}) { return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_DIR_EXISTS}, $new)}); } else { my ($name) = $fulldir->{fulldir} =~ /\/([^\/]+)$/; (my $path = $fulldir->{fulldir}) =~ s,/$name$,,; return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_DIR_NOT_EXISTS}, $self->{cgi}->{txt_input}) }) if (!-e $path); return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_DIR_PEM}, $self->{cgi}->{txt_input}) }) if (!-w $path); #permission } if (rmkdir ($fulldir->{fulldir}, 0755)) { $self->history("cmd_makedir|$fulldir->{fulldir}") if ( $self->{cfg}->{multi} ); #save log info return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{MSG_DIR_CREATED}, $new) }); } return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_DIR_PEM},($new =~ m,^/,) ? $new : ($work_path || 'Root'))}); } END_OF_SUB $COMPILE{cmd_preferences} = __LINE__ . <<'END_OF_SUB'; sub cmd_preferences { #--------------------------------------------------- # Save options of system # my $self = shift; ($self->{cgi}->{save}) or return $self->cmd_main_display(); my $def_sort = $self->{cgi}->{def_sort} || 'Name'; my $def_working_dir = $self->{cgi}->{def_working_dir} || '/'; my $def_passwd_dir = $self->{cgi}->{def_passwd_dir}; my $def_files_page = $self->{cgi}->{def_files_page} || (($self->{cgi}->{showall})? 'all': 25); my $def_pages_screen= $self->{cgi}->{def_pages_screen} || (($self->{cgi}->{showall})? 'all': 20); my $hidden_file = $self->{cgi}->{hidden_file} || '0'; my $editor_mode = $self->{cgi}->{editor_mode} || '0'; my $scheme = $self->{cgi}->{scheme} || 'fileman'; my $font = $self->{cgi}->{font} || ""; my $readme_position = $self->{cgi}->{readme_position}; ($font =~ /^$/) or $font = ""; $def_files_page = 25 if ($def_files_page > 100); $def_pages_screen = 20 if ($def_pages_screen > 50); $def_working_dir =~ s/$GT::FileMan::UNSAFE_PATH//g; $def_passwd_dir =~ s/$GT::FileMan::UNSAFE_PATH//g; $def_passwd_dir = "$self->{cfg}->{root_dir}/$def_passwd_dir" if ($def_passwd_dir and !$self->{cfg}->{passwd_dir_level}); $def_passwd_dir ||= '0'; if ($def_passwd_dir and (!-e $def_passwd_dir or !-w _)) { $self->{cgi}->{page} = 'preferences.html'; (-e _) or return $self->cmd_show( {msg => sprintf($LANGUAGE{ERR_DIR_NOT_EXISTS}, $def_passwd_dir)} ); (-w _) or return $self->cmd_show( {msg => sprintf($LANGUAGE{ERR_DIR_PEM}, $def_passwd_dir)} ); } print $self->{in}->header ( -cookie => [ $self->{in}->cookie ( -name => 'def_sort', -value => $def_sort, -expires => '+5y'), $self->{in}->cookie ( -name => 'def_passwd_dir', -value => $def_passwd_dir, -expires => '+5y'), $self->{in}->cookie ( -name => 'def_working_dir', -value => $def_working_dir, -expires => '+5y'), $self->{in}->cookie ( -name => 'def_files_page', -value => $def_files_page, -expires => '+5y'), $self->{in}->cookie ( -name => 'def_pages_screen',-value => $def_pages_screen, -expires => '+5y'), $self->{in}->cookie ( -name => 'readme_position', -value => $readme_position, -expires => '+5y'), $self->{in}->cookie ( -name => 'hidden_file' , -value => $hidden_file, -expires => '+5y'), $self->{in}->cookie ( -name => 'scheme' , -value => $scheme, -expires => '+5y'), $self->{in}->cookie ( -name => 'font' , -value => $font, -expires => '+5y'), $self->{in}->cookie ( -name => 'editor_mode' , -value => $editor_mode, -expires => '+5y'), ] ); $self->{cgi}->{cmd_do} = 'cmd_command'; return $self->cmd_main_display({ reload => 1, status => $LANGUAGE{MSG_PREFERENCES}, re_scheme => 1 }); } END_OF_SUB $COMPILE{user_form} = __LINE__ . <<'END_OF_SUB'; sub user_form { #--------------------------------------------------- # Save options of system # my ($self, $msg) = @_; ($self->{cfg}->{multi} or $self->{cfg}->{single}) or die $LANGUAGE{ERR_VERSION}; $self->page('user_form.html', { msg => $msg}); } END_OF_SUB $COMPILE{cmd_admin} = __LINE__ . <<'END_OF_SUB'; sub cmd_admin { #--------------------------------------------------- # Save user password # my $self = shift; ($self->{cfg}->{multi} or $self->{cfg}->{single}) or die $LANGUAGE{ERR_VERSION}; ($self->{cfg}->{single}) and return $self->pwd_single(); my $username = $self->{cgi}->{Username}; my $old_pass = $self->{cgi}->{Old_Password}; my $new_pass = $self->{cgi}->{New_Password}; my $db_name = $self->{cfg}->{db_name}; return $self->user_form($LANGUAGE{ERR_OLD_PASSWORD}) if (!$old_pass); return $self->user_form($LANGUAGE{ERR_NEW_PASSWORD}) if (!$new_pass or length($new_pass) < 3); open (DATA, "<$self->{cfg}->{priv_path}/$db_name") or return $self->cmd_main_display({reload => 1, status => sprintf($LANGUAGE{ERR_FILE_OPEN},$db_name, "$!")},1); flock(DATA, 1); my @lines = ; close DATA; my $found; # check username and password LINE: foreach (@lines) { if ($_ =~ /^$/) { next LINE; } if ($_ =~ /^#/) { next LINE; } chomp ($_); $_ =~ s/\r//g; # Remove Windows linefeed character. my @record = split (/\Q|\E/o, $_); if (($record[1] ne $username) or ($record[2] ne crypt($old_pass,$old_pass))) { next LINE;} $found = 1; last; } ($found) or return $self->user_form($LANGUAGE{ERR_OLD_PASSWORD}); # Save user information my $rows; LINE: foreach (@lines) { if ($_ =~ /^$/) { next LINE; } if ($_ =~ /^#/) { next LINE; } chomp ($_); $_ =~ s/\r//g; # Remove Windows linefeed character. my @record = split (/\Q|\E/o, $_); if ($username eq $record[1]) { # replace user information $record[2] = crypt($new_pass,$new_pass); $rows .= join("|",@record); } else { $rows .= $_; } $rows .= "\n"; } open (NEW, ">$self->{cfg}->{priv_path}/$db_name") or return $self->cmd_main_display({reload => 1, status => sprintf($LANGUAGE{ERR_FILE_OPEN},$db_name, "$!")}, 1); flock(NEW, 2); print NEW $rows; close NEW; return $self->cmd_main_display({reload => 1, status => $LANGUAGE{MSG_PWD_CHANGED}},1); } END_OF_SUB sub pwd_single () { #------------------------------------------------------ # Change password in single version # my $self = shift; ($self->{cfg}->{single}) or die $LANGUAGE{ERR_VERSION}; my $fn = "$self->{cfg}->{priv_path}/lib/ConfigData.pm"; (-e $fn) or return $self->user_form(sprintf($LANGUAGE{ERR_OPEN_FILE},'ConfigData.pm',$!)); (-w _) or return $self->user_form(sprintf($LANGUAGE{ERR_WRITEABLE},'ConfigData.pm',$!)); my $old = $self->{cgi}->{Old_Password}; my $new = $self->{cgi}->{New_Password}; return $self->user_form($LANGUAGE{ERR_OLD_PASSWORD}) if (!$old); return $self->user_form($LANGUAGE{ERR_NEW_PASSWORD}) if (!$new and length($new) < 3); return $self->user_form($LANGUAGE{ERR_OLD_PASSWORD}) if (crypt($old,$self->{cfg}->{password}) ne $self->{cfg}->{password}); # Encrypt password my @salt_chars = ('A' .. 'Z', 0 .. 9, 'a' .. 'z', '.', '/'); my $salt = join '', @salt_chars[rand 64, rand 64]; $self->{cfg}->{password} = crypt($new, $salt); my $time = localtime; open (FH, "> $fn") or return $self->user_form(sprintf($LANGUAGE{ERR_OPEN_FILE},'ConfigData.pm',$!)); print FH <dump ( var => '', data => $self->{cfg} ); close FH; print $self->{in}->header (-cookie => [ $self->{in}->cookie ( -name => 'password', -value => crypt($self->{cfg}->{password}, $self->{cfg}->{username}), -expires => '') ]); return $self->cmd_main_display({reload => 1, status => $LANGUAGE{MSG_PWD_CHANGED}},1); } $COMPILE{log_off} = __LINE__ . <<'END_OF_SUB'; sub log_off { #--------------------------------------------------- # Log off # my $self = shift; print $self->{in}->header( -cookie => [ $self->{in}->cookie( -name => 'username', -value => '', -expires => ''), $self->{in}->cookie( -name => 'password', -value => '', -expires => '') ]); return $self->page('login_form.html', { msg => $LANGUAGE{MSG_LOG_OFF} }); } END_OF_SUB $COMPILE{cmd_view} = __LINE__ . <<'END_OF_SUB'; sub cmd_view { #--------------------------------------------------- # View a file # my ($self,$filename) = @_; $filename ||= $self->{cgi}->{c_edit}; my $file = $self->_safe_file($filename, { write => 1, text => 1, fullfile => 1, size => 1}); return $self->cmd_main_display({reload => 1, status => sprintf($LANGUAGE{ERR_INVALID},$filename)}) if ($file == -1); # not safe my $url_opts = $self->{url_opts} || ''; my $work_path = $self->{work_path} || ''; my $fullfile = $file->{file}; my ($ext) = $fullfile =~ /\.([^.]+)$/; my $img_type = "bmp gif jpg jpeg tif tiff"; my $status = sprintf($LANGUAGE{MSG_FILE_EDITING}, 'View ', $filename, -s $fullfile, $filename); return $self->page('view_image.html', { filename => $filename, work_path=> $work_path, status => $status }) if (($img_type =~ m,$ext,i) and $ext); $self->_view_file($filename); } END_OF_SUB $COMPILE{cmd_edit} = __LINE__ . <<'END_OF_SUB'; sub cmd_edit { #------------------------------------------------------------- # Print the content of a file # my ($self, $filename, $use_html) = @_; $filename ||= $self->{cgi}->{c_edit}; my $file = $self->_safe_file($filename,{ write => 1, text => 1, fullfile => 1, size => 1, isfile => 1}); return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_INVALID}, $filename) }, 1) if ($file == -1); # not safe return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_NOT_FILE}, $filename) }, 1) if (!$file->{isfile}); # not a file my $url_opts = $self->{url_opts} || ''; my $work_path = $self->{work_path} || ''; my $fullfile = $file->{file}; my ($ext) = $fullfile =~ /\.([^.]+)$/; $use_html ||= ''; if ($file->{text} and $ext ne 'pdf') { # Text file open (DATA,"<$fullfile") or return $self->cmd_main_display({reload => 1, status => sprintf($LANGUAGE{ERR_FILE_OPEN},$filename, "$!")},1); read (DATA, my $content, -s DATA); close DATA; if ( $self->get_browser(1) and !$use_html and !$self->{in}->cookie('editor_mode') and ((lc($ext) eq 'html') or (lc($ext) eq 'htm')) ) { #should show HTML mode $use_html = 1; $content =~ s/
{in}->html_escape($content); my $status = sprintf($LANGUAGE{MSG_FILE_EDITING}, 'Editing ', $filename, $file->{size}, $filename); $self->cmd_show({ content => $content, filename => ($filename =~ m,^/,)? '' : $filename, status => $status, old => ($filename =~ m,^/,)? 0 : 1, use_html => $use_html, writeable=> $file->{write} }); return; } # Image file my $img_type = "bmp gif jpg jpeg tif tiff"; my $status = sprintf($LANGUAGE{MSG_FILE_EDITING}, 'View ', $filename, -s $fullfile, $filename); return $self->page('view_image.html', { filename => $filename, work_path => $work_path, status => $status }) if ($img_type =~ m,$ext,i); my $doc = "doc xls pdf DOC XLS PDF mp3 MP3 mpga MPGA mpg MPG"; return $self->_view_file($filename) if ($doc =~ m,$ext,i); # .doc, .xls, .pdf file return $self->cmd_tar($filename) if ($ext =~ /tar|gz|zip/i); return $self->_send_to_browser($fullfile); # Download if it is an unknow file } END_OF_SUB $COMPILE{cmd_print_img} = __LINE__ . <<'END_OF_SUB'; sub cmd_print_img { #---------------------------------------------------------------- # print image file # my $self = shift; my $filename = $self->{cgi}->{filename}; $self->_view_file($filename); } END_OF_SUB $COMPILE{cmd_download} = __LINE__ . <<'END_OF_SUB'; sub cmd_download { #---------------------------------------------------------------- # download a file # my $self = shift; my $files = [ $self->{in}->param('c_edit') ]; my $mode = $self->{cgi}->{chmode} || 'binary'; my $zip_type = $self->{cgi}->{opt_gz}; if ($#$files == 0) { my $file = $self->_safe_file($self->{in}->param('c_edit'), { fullfile => 1}); return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_INVALID}, $self->{in}->param('c_edit'))}) if ($file == -1); # not safe return $self->_send_to_browser($file->{file}, $mode) if (-f $file->{file} and !$zip_type); } $zip_type ||= 1; my $tempfile = new GT::TempFile; my $ext; if ($zip_type == 3 and $GT::FileMan::HAVE_AZIP) { my $error = $self->_zip_process("$$tempfile.zip", $files); return $self->cmd_main_display({ reload => 1, status => "$error" }) if ($error); $ext = 'zip'; } elsif ( $zip_type == 2 and $GT::FileMan::HAVE_GZIP ) { $self->_tar_process("$$tempfile.tar.gz", $files); $ext = 'tar.gz'; } else { $self->_tar_process("$$tempfile.tar", $files); $ext = 'tar'; } $self->_send_to_browser("$$tempfile.$ext", 'auto', "download.$ext"); } END_OF_SUB sub _send_to_browser { #---------------------------------------------------------------- # send the contents of a file to browser for downloading # my $self = shift; my $send_file = shift; my $mode = shift; my $name = shift; if ($mode eq 'auto') { (-T $send_file) and $mode = 'ascii'; } if(open(SENDFILE, $send_file)) { $self->history("cmd_download|$send_file") if ($self->{cfg}->{multi}); #save log file my $file_size = -s $send_file; if (! $name) { ($name) = $send_file =~ m,/([^/]+)$,; } print $self->{in}->header( '-type' => 'application/download', '-Content-Length' => $file_size, '-Content-Transfer-Encoding' => 'binary', '-Content-Disposition' => \"attachment; filename=\"$name\"" ); ($self->{cfg}->{winnt}) and binmode STDOUT; binmode SENDFILE; my $buffer; while (read(SENDFILE, $buffer, $READ_SIZE)){ if ($mode eq 'ascii') { $buffer =~ s,\r\n,\n,g; } print $buffer; } close SENDFILE; } else { # failed to open file $send_file =~ s,$self->{cfg}->{root_path},,; $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_FILE_OPEN}, $send_file, "$!") }); } } $COMPILE{cmd_copy} = __LINE__ . <<'END_OF_SUB'; sub cmd_copy { # -------------------------------------------------------- # Copy files or/and directories # my $self = shift; my $files; my ($count_copied, $not_copied, $history) = (0, 0, ''); # Prepare files and dirs need to copy @$files = $self->{in}->param('c_edit'); my $to_dir = $self->_safe_file($self->{cgi}->{txt_input},{ exist => 1, write => 1, fullfile => 1 }); return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_INVALID}, $self->{cgi}->{txt_input}) }) if ($to_dir == -1); # not safe if ($to_dir->{exist}) { return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_DIR_PEM}, $self->{cgi}->{txt_input}) }) if (!$to_dir->{write}); #permission } else { my ($file) = $to_dir->{file} =~ /\/([^\/]+)$/; (my $path = $to_dir->{file}) =~ s,/$file$,,g; return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_DIR_NOT_EXISTS}, $self->{cgi}->{txt_input}) }) if (!-e $path); return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_DIR_PEM}, $self->{cgi}->{txt_input}) }) if (!-w $path); #permission } foreach ( @$files ) { my $from = $self->_safe_file($_, { fullfile => 1, size => 1 }); return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_INVALID},$_) }) if ($from == -1); # not safe next if ($from->{file} eq $to_dir->{file}); # don't copy to itself or it will loop infinitely. # Check free space. if ($self->{cfg}->{allowed_space} > 0) { my $need_space; (-d $from->{file})? find($from->{file}, sub {$need_space += -s shift}) : ($need_space = -s $from->{file}); #current file/dir size my $disk_space = $self->_checkspace(); my $free_space = $disk_space->{free_space}; return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_DISK_SPACE}, $free_space) }) if ($free_space*1024 < $need_space); } if (copy($from->{file}, $to_dir->{file})) { $count_copied++; } else { $not_copied++; } } if ($history) { chop $history; $self->history("cmd_copy|$history") if ( $self->{cfg}->{multi} ); #save log info } $self->{cgi}->{cmd_do} = "cmd_copy"; return $self->cmd_main_display( { reload => 1, status => sprintf($LANGUAGE{MSG_COPIED}, $count_copied, $not_copied) }); } END_OF_SUB $COMPILE{cmd_move} = __LINE__ . <<'END_OF_SUB'; sub cmd_move { # -------------------------------------------------------- # Move files or/and directories # my $self = shift; my ($count_moved, $not_moved, $history) = (0, 0, ''); my $files; @$files = $self->{in}->param('c_edit'); # Prepare files and dirs need to move my $to_dir = $self->_safe_file($self->{cgi}->{txt_input}, { exist => 1, write => 1, fullfile => 1 }); return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_INVALID}, $self->{cgi}->{txt_input}) }) if ($to_dir == -1); # not safe if ($to_dir->{exist}) { return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_DIR_PEM}, $self->{cgi}->{txt_input}) }) if (!$to_dir->{write}); #permission } else { my ($file) = $to_dir->{file} =~ /\/([^\/]+)$/; (my $path = $to_dir->{file}) =~ s,/$file$,,g; return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_DIR_NOT_EXISTS}, $self->{cgi}->{txt_input}) }) if (!-e $path); return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_DIR_PEM}, $self->{cgi}->{txt_input}) }) if (!-w $path); #permission } foreach (@$files) { my $from = $self->_safe_file($_, { fullfile => 1 }); return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_INVALID},$_) }) if ($from == -1); # not safe next if ($from->{file} eq $to_dir->{file}); # don't copy to itself or it will loop infinitely. if (move($from->{file},$to_dir->{file})) { $count_moved++; } else { $not_moved++; } } if ($history) { chop $history; $self->history("cmd_move|$history") if ( $self->{cfg}->{multi} ); #save log info } $self->{cgi}->{cmd_do} = "cmd_move"; return $self->cmd_main_display( { reload => 1, status => sprintf($LANGUAGE{MSG_MOVED}, $count_moved, $not_moved) }); } END_OF_SUB $COMPILE{cmd_delete} = __LINE__ . <<'END_OF_SUB'; sub cmd_delete { # -------------------------------------------------------- # Delete files or directories # my $self = shift; my ($files, $notdeleted); my ($count_file, $count_dir, $history) = (0, 0, ''); #List files and dirs need to remove @$files = $self->{in}->param('c_edit'); foreach (@$files) { my $file = $self->_safe_file($_, { fullfile => 1 }); if ($file == -1) { $self->{cgi}->{cmd_do} = "cmd_command" ; return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_INVALID},$_) }); # not safe } my $full_name = $file->{file}; if ( -d $full_name and !-l $full_name ) { if ( rmdir($full_name) ) { $count_dir++; } else { push @$notdeleted,$_; } } else { if ( del($full_name) ) { $count_file++; $history .= "$full_name:"; } } } if ($history) { chop $history; $self->history("cmd_delete|$history") if ( $self->{cfg}->{multi} ); #save log info } $self->list_files(); my $status = ( $count_file > 0 or $count_dir > 0 ) ? sprintf($LANGUAGE{MSG_DEL_SUCC}, $count_file, $count_dir) : $LANGUAGE{ERR_DEL}; if ($notdeleted) { # Return list file for loop if recursive diectory my $list_files; foreach ( @$notdeleted ) { push @$list_files, { name => $_ }; } $self->{cgi}->{cmd_do} = "cmd_del_confirm"; return $self->page('confirm_delete.html', { reload => 1, list_files => $list_files, file_cur => @$files[0], status => $status }); } else { $self->{cgi}->{cmd_do} = "cmd_command"; $self->cmd_main_display({ reload => 1, status => $status }); } } END_OF_SUB $COMPILE{cmd_del_confirm} = __LINE__ . <<'END_OF_SUB'; sub cmd_del_confirm { # -------------------------------------------------------- # confirm before delete a directory have sub dir # my $self = shift; my $full_path = $self->_safe_dir(); my ($files, $history); if ( $self->{in}->param('c_edit') ) { @$files = $self->{in}->param('c_edit'); #Confirm remove all recursive directorys if ( $self->{cgi}->{all} ) { foreach ( @$files ) { my $file = $self->_safe_file($_,{fullfile => 1}); return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_INVALID},$_)}) if ($file == -1); # not safe my $full_name = $file->{file}; deldir($full_name); $history .= "$full_name:"; } if ($history and $self->{cfg}->{multi}) { chop $history; $self->history("cmd_delete|$history"); #save log info } $self->{cgi}->{cmd_do} = "cmd_command"; return $self->cmd_main_display({ reload => 1, status => $LANGUAGE{MSG_DEL_ALL}}); } #Remove current recursive directory elsif ($self->{cgi}->{over}) { my $file_cur = pop(@$files); my $file = $self->_safe_file($file_cur,{ fullfile => 1 }); return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_INVALID}, $file_cur) }) if ($file == -1); # not safe my $full_name = $file->{file}; deldir($full_name); $history .= "$full_name:"; my $list_files; foreach (@$files) { push @$list_files, { name => $_ }; } if ($#$files >= 0) { $self->{cgi}->{cmd_do} = "cmd_del_confirm"; my $status = sprintf($LANGUAGE{MSG_DEL_CURR}, $self->{cgi}->{file_cur}); return $self->page('confirm_delete.html',{ reload => 1, list_files => $list_files, file_cur => @$files[0] }, status => $status); } } #Skip remmoving current dir elsif ($self->{cgi}->{skip}) { pop(@$files); my $list_files; foreach (@$files) { push @$list_files, { name => $_ }; } if ($#$files >= 0) { $self->{cgi}->{cmd_do} = "cmd_del_confirm"; my $status = sprintf($LANGUAGE{MSG_DEL_SKIP}, $self->{cgi}->{file_cur}); return $self->page('confirm_delete.html',{ reload => 1, list_files => $list_files, file_cur => @$files[0]}, status => $status); } } #Cancel delete recursive elsif ($self->{cgi}->{cancel}) { $self->{cgi}->{cmd_do} = "cmd_command"; return $self->cmd_main_display({ reload => 1, status => $LANGUAGE{MSG_DEL_CANC} }); } } if ($history and $self->{cfg}->{multi}) { chop $history; $self->history("cmd_delete|$history"); #save log info } $self->{cgi}->{cmd_do} = "cmd_command"; return $self->cmd_main_display({ reload => 1, status => $LANGUAGE{MSG_DEL_ALL_SUCC} }); } END_OF_SUB $COMPILE{cmd_print} = __LINE__ . <<'END_OF_SUB'; sub cmd_print { # -------------------------------------------------------- # Print selected file(s) # my $self = shift; my @input = $self->{in}->param('c_edit'); my $all = $self->{cgi}->{print_all}; # Check the selected files my @files; foreach my $n ( @input ) { my $f = $self->_safe_file($n, { text => 1, fullfile => 1, size => 1, isfile => 1}); next if ( $f == -1 ); next if ( !$f->{isfile} ); my ($ext) = $n =~ /\.([^.]+)$/; my $img = ($ext =~ /^jpg|JPG|gif|GIF|bmp|BMP|mpga|MPGA/) ? 1 : 0; $all = 0 if ($img); if ($f->{text} or $img) { push @files, { name => $n, fullfile => $f->{file}, image => $img }; } } return $self->_js_alert($LANGUAGE{ERR_PRINT}) if ($#files < 0); my $output = qq!
!; if ($all) { # Print multiple files my $flag = ''; foreach my $f (@files) { open (FILE, "< $f->{fullfile}") or die sprintf($LANGUAGE{ERR_FILE_OPEN}, $f->{fullfile}, "$!"); read (FILE, my $data, -s FILE); close FILE; my $style; $flag and $style = "style='page-break-before: always;'"; $output .= qq|

$data

|; $flag++; } } else { # Print single file my $file = pop @files; my $next_url = ''; if ( $#files >= 0 ) { $next_url = $self->{in}->url (absolute => 1, query_string => 0)."?fdo=cmd_print&&work_path=$self->{work_path}&"; $next_url .= ";$self->{url_opts};" if ($self->{url_opts}); foreach ( @files ) { $next_url .= "c_edit=$_->{name}&"; } } if ($file->{image}) { $self->page('image_print.html', { filename => $file->{name}, work_path => $self->{work_path}, next_url => $next_url }); } else { open (FILE, "< $file->{fullfile}") or die sprintf($LANGUAGE{ERR_FILE_OPEN}, $file->{fullfile}, "$!"); read (FILE, my $data, -s FILE); close FILE; $output .= qq|
$data

|; $output = sprintf($LANGUAGE{PRINT_NEXT}, $next_url) .$output if ( $next_url ); } } $output .= qq!!; print $self->{in}->header; print $output; } END_OF_SUB sub _js_alert { #--------------------------------------------------------- # my ($self, $msg) = @_; print $self->{in}->header; print qq!
!; } $COMPILE{cmd_chmod} = __LINE__ . <<'END_OF_SUB'; sub cmd_chmod { # -------------------------------------------------------- # Changes the permission attributes of a file my $self = shift; my $newperm = $self->{cgi}->{txt_input}; my $count = 0; my $full_path = $self->_safe_dir(); my $files = $self->{cgi}->{c_edit}; my $history = "cmd_chmod|"; my $octal_perm= oct($newperm); #if only one file (ref $files eq 'ARRAY') or $files = [$files]; foreach (@$files) { my $from = $self->_safe_file($_, { fullfile => 1 }); next if ($from == -1); # not safe if ($self->{cgi}->{opt_gz} and -d $from->{file}) { find($from->{file}, sub { chmod($octal_perm, shift); }); $count++; } else { $history .= "$from->{file}:"; chmod($octal_perm, $from->{file}) and $count++; } } chop $history; $self->history($history) if ($self->{cfg}->{multi});#save log info my $status = ( $count ) ? sprintf($LANGUAGE{MSG_CHMOD_CHANGED}, $count) : $LANGUAGE{ERR_CHMOD}; $self->cmd_main_display({ reload => 1, status => $status }); } END_OF_SUB $COMPILE{cmd_tail} = __LINE__ . <<'END_OF_SUB'; sub cmd_tail { #----------------------------------------------------- # tail command # my $self = shift; my $filename = $self->{cgi}->{c_edit}; my $url_opts = $self->{url_opts} || ''; my $work_path = $self->{work_path} || ''; my $file = $self->_safe_file($filename,{fullfile => 1, exist => 1, isfile => 1, size => 1}); return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_INVALID},$filename)}) if ($file == -1); #not safe my $fullfile = $file->{file}; my $retime = $self->{cgi}->{retime}; my $contents = ''; my $lines = $self->{cgi}->{txt_input} || 10; return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_FILE_NOT_EXISTS}, $filename) }) if (!$file->{exist}); return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_NOT_ISFILE}, $filename) }) if (!$file->{isfile}); my $follow; @ARGV = grep { if ($_ eq "-f") { $follow++; 0 } else { 1 } } @ARGV; open FILE, "<$fullfile" or return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_FILE_OPEN},$filename)}); my $file_size = $file->{size}; return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_FILE_EMPTY}, $filename)}) unless $file_size; print $self->{in}->header; if ($retime) { print qq! !; } my $css_file = $self->{in}->cookie('scheme') || 'fileman'; print qq! {cfg}->{html_root_url}/$css_file.css>
!;
    my $read_size = 4096;
    my $to_read   = ($file_size > $read_size) ? $read_size : $file_size;
    my $buffer;
    seek FILE, -$to_read, 2;
    read FILE, $buffer, $to_read;
    my $read       = $to_read;
    my $need_lines = $lines - 1;
    while () {
        if ($buffer =~ /\n(.*(?:\n.*){$need_lines}\n?$)/) {
            print $self->{in}->html_escape($1);
            last;
        }
        $to_read = ($file_size - $read > $read_size) ? $read_size : $file_size - $read;
        unless ($to_read == 0) {
            print $self->{in}->html_escape($buffer);
            last;
        }
        seek FILE, -($to_read + $read), 2;
        $read += $to_read;
        my $new_buffer;
        my $bytes_read = read FILE, $new_buffer, $to_read;
        if ($bytes_read == 0) {
            print $self->{in}->html_escape($buffer);
            last;
        }
        $buffer = $new_buffer . $buffer;
    }

    my $cnt = 0;
    if ($follow) {
        seek FILE, 0, 2; # Seek to the end of the file
        while () {
            select undef, undef, undef, 1;
            seek FILE, 0, 1 or last; # Reset eof(FILE)
            print while ;
            seek FILE, 0, 2;
            last if ($cnt++ > 60); # Only run for one min max.
        }
    }
    print "
"; } END_OF_SUB $COMPILE{cmd_perl} = __LINE__ . <<'END_OF_SUB'; sub cmd_perl { #---------------------------------------------------------------- # check perl syntax # my $self = shift; $ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin'; #for taint mode my $url_opts = $self->{url_opts} || ''; my $work_path = $self->{work_path} || ''; print $self->{in}->header; my $css_file = $self->{in}->cookie('scheme') || 'fileman'; print qq! {cfg}->{html_root_url}/$css_file.css>
!; my $exts = 'cgi pl pm'; my $files ; @$files = $self->{in}->param('c_edit'); my $redirector = ($self->{cfg}->{winnt} ? " 2>&1 1>&2" : " 1>&1 2>&1"); foreach (@$files) { my $file = $self->_safe_file($_, { fullfile => 1, text => 1}); my $full_name = $file->{file}; next if (not $file->{text}); my ($ext) = $full_name =~ /\.([^.]+)$/; next if ($exts !~ /$ext/i); my $tmp = $full_name; $tmp =~ s,$self->{cfg}->{root_dir}/,,; print "

 $tmp "; my $check_now = $self->{cfg}->{path_to_perl} . ' -cw -I'.$self->{cfg}->{priv_path}.'/lib '.$full_name.' '.$redirector; print '

 ',`$check_now`,'
'; print ""; } print ''; } END_OF_SUB $COMPILE{cmd_diff} = __LINE__ . <<'END_OF_SUB'; sub cmd_diff { #---------------------------------------------------- # Show difference between two files # my $self = shift; my $filename1 = $self->{cgi}->{c_edit}; my $filename2 = $self->{cgi}->{txt_input}; my $file1 = $self->_safe_file($filename1, { fullfile => 1, text => 1, exist => 1 }); my $file2 = $self->_safe_file($filename2, { fullfile => 1, text => 1, exist => 1 }); ($file1 == -1) and return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_INVALID}, $filename1) }); ($file2 == -1) and return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_INVALID}, $filename2) }); my $work_path = $self->{work_path} || ''; my $fullfile1 = $file1->{file}; my $fullfile2 = $file2->{file}; return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_FILE_NOT_EXISTS}, $filename2) }) if (!$file2->{exist}); return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_NOT_TEXT_FILE} , $filename1) }) if (!$file1->{text}); return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_NOT_TEXT_FILE} , $filename2) }) if (!$file2->{text}); require GT::FileMan::Diff; my $diff = GT::FileMan::Diff::html_diff($fullfile1, $fullfile2, 3); if (!ref $diff) { $diff == 1 ? return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_FILE_OPEN}, $fullfile1, "$!") }) : return $self->cmd_main_display({ reload => '1', status => sprintf($LANGUAGE{ERR_FILE_OPEN}, $fullfile1, "$!") }); } my $back_btn = ($self->{cgi}->{hide_back_button}) ? '' : ""; print $self->{in}->header; my $css_file = $self->{in}->cookie('scheme') || 'fileman'; print qq! {cfg}->{html_root_url}/$css_file.css>
$back_btn $$diff
!; } END_OF_SUB $COMPILE{cmd_tar} = __LINE__ . <<'END_OF_SUB'; sub cmd_tar { #---------------------------------------------------- # Create tar file # my ($self, $fn, $error) = @_; if ($fn) { return $self->_zip_information($fn, $error) if ($fn =~ /.zip$/i and $GT::FileMan::HAVE_AZIP); return $self->_tar_information($fn, $error) if ($fn =~ /.gz$/i and $GT::FileMan::HAVE_GZIP); return $self->_tar_information($fn, $error) if ($fn =~ /.tar$/i); # .tar file } my $input = $self->{cgi}->{txt_input}; my $zip_type = $self->{cgi}->{opt_gz}; my $from_path = $self->_safe_dir(); my $fulldir = $self->_safe_dir($input); ($fulldir == -1) and return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_INVALID}, $input) }); # not safe my $fullfile = $fulldir->{fulldir}; my $path = [split /\//,$fullfile]; my $tar_file = @$path[$#$path]; my $to_path = $fullfile; $to_path =~ s/\/@$path[$#$path]//; #path to save tar file return $self->cmd_main_display({reload => 1, status => sprintf($LANGUAGE{ERR_TAR_NOT_EXISTS}, $input)}) if (!-e $to_path); # check exists the directory return $self->cmd_main_display({reload => 1, status => sprintf($LANGUAGE{ERR_TAR_PEM}, $input)}) if (!-w $to_path); # check permission on this directory if ($zip_type == 1) { # create a .tar.gz file $tar_file .= '.gz' if ($tar_file =~ m/.tar$/i); $tar_file .= '.tar.gz' if ($tar_file !~ m/.tar.gz$/i); } elsif ($zip_type == 2) { # create a .zip file $tar_file .= '.zip' if ($tar_file !~ /.zip$/i); } else { # create a .tar file $tar_file .= '.tar' if ($tar_file !~ /.tar$/i); } # Check required modules my $err_check = _tar_check($tar_file); return $self->cmd_main_display({ reload => 1, status => $LANGUAGE{ERR_NO_GZIP} }) if ($err_check); # check permission on this directory $fullfile = "$to_path/$tar_file"; if (!$self->{cgi}->{confirm}) { if (-e $fullfile) { my $results; my $files = [$self->{in}->param('c_edit')]; foreach my $file (@$files) { push @$results, { name => $file }; } return $self->page('tar_confirm.html', { results => $results, file => $tar_file }); } } if ( $zip_type == 2 ) { my $error = $self->_zip_process($fullfile, [$self->{in}->param('c_edit')]); return $self->cmd_main_display({ reload => 1, status => $error }) if ($error); } else { $self->_tar_process($fullfile); } $self->{cgi}->{cmd_do} = 'cmd_tar'; $self->history($fullfile) if ( $self->{cfg}->{multi} ); #save log info $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{MSG_TAR_CREATED}, $tar_file) }); } END_OF_SUB $COMPILE{cmd_uncompress} = __LINE__ . <<'END_OF_SUB'; sub cmd_uncompress { #-------------------------------------------------------- # Uncompress .tar or .gz file # my $self = shift; my $root_path = $self->{cfg}->{root_dir}; my $work_path = $self->{work_path}; my $input = $self->{cgi}->{txt_input}; my $fullfile = $self->_safe_file($self->{cgi}->{cmp_file}, {fullfile => 1, exist => 1}); my $selected = [$self->{in}->param('c_edit')]; my $untar_pg = $self->{cgi}->{uncomp_option}; return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_INVALID}, $self->{cgi}->{cmp_file}) }) if ($fullfile == -1); return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_FILE_NOT_EXISTS}, $self->{cgi}->{cmp_file}) }) unless ($fullfile->{exist}); # Check required modules my $error = _tar_check($fullfile->{file}); return $self->cmd_main_display({ reload => 1, status => $error }) if ($error); my $cmp_file = $fullfile->{file}; return $self->cmd_tar($self->{cgi}->{cmp_file}, $LANGUAGE{ERR_UNCOMPRESS}) if ($#$selected == -1); # Check the directory is exists, permission my $fulldir = $self->_safe_dir($input, { exist => 1, write => 1 }); return $self->cmd_tar($self->{cgi}->{cmp_file}, sprintf($LANGUAGE{ERR_INVALID}, $input || $work_path)) if ($fulldir == -1); # not safe return $self->cmd_tar($self->{cgi}->{cmp_file}, sprintf($LANGUAGE{ERR_DIR_NOT_EXISTS}, $input || $work_path || 'Root')) if (ref $fulldir eq 'HASH' and !$fulldir->{exist}); return $self->cmd_tar($self->{cgi}->{cmp_file}, sprintf($LANGUAGE{ERR_DIR_PEM} , $input || $work_path || 'Root')) if (ref $fulldir eq 'HASH' and !$fulldir->{write}); # Get file size my $full_path = (ref $fulldir eq 'HASH') ? $fulldir->{fulldir} : $fulldir; my $total_size = _tar_size($cmp_file); # Check free space and writeable if ($self->{cfg}->{allowed_space} > 0) { my $disk_space = $self->_checkspace($full_path); my $free_space = $disk_space->{free_space}; return $self->cmd_tar($self->{cgi}->{cmp_file}, sprintf($LANGUAGE{ERR_DISK_SPACE}, $free_space)) if ($total_size > $free_space * 1024); } my $filename = $cmp_file; $filename =~ s/$full_path\///; $self->page('progress_bar.html', { bar_name => "Un-tarring:", msg => sprintf($LANGUAGE{MSG_READING}, $filename) }); my ($last_width, $max_width, $copied) = (-1, 500, 0); if ($filename =~ /.zip$/i) { my $zip = Archive::Zip->new($cmp_file) or return $self->cmd_tar($self->{cgi}->{cmp_file}, $!); foreach ($zip->members) { my $name = $_->fileName; my $found = $untar_pg ? 0 : 1; if ($untar_pg) { foreach my $f (@$selected) { if ($f eq $name) { $found = 1; last; } } } $copied += $_->uncompressedSize; if ($found) { $zip->extractMember($name, "$full_path/$name"); } my $percent = 1 - ($total_size - $copied) / $total_size; my $img_width= int($max_width * $percent); my $wpercent = sprintf '%.f%%', 100 * $percent; if ($img_width != $last_width) { $self->page('copy_status.html', { msg => "$name file...".(( $found ) ? 'ok' : 'skip'), pxs => $img_width, percent => $wpercent }); $last_width = $img_width; } } } else { # Make sure tar file goes out of scope before loading directory. require GT::Tar; my $tar = GT::Tar->open ($cmp_file); my $files = $tar->files; foreach (@$files) { my $name = $_->{name}; my $found = $untar_pg ? 0 : 1; if ($untar_pg) { foreach my $f (@$selected) { if ($f eq $_->{name}) { $found = 1; last; } } } $copied += $_->{size}; if ($found) { $_->{name} = "$full_path/$name"; $_->write(); } my $percent = 1 - ($total_size - $copied) / $total_size; my $img_width= int($max_width * $percent); my $wpercent = sprintf '%.f%%', 100 * $percent; if ($img_width != $last_width) { $self->page('copy_status.html', { msg => "$name file...".(( $found ) ? 'ok' : 'skip'), pxs => $img_width, percent => $wpercent }); $last_width = $img_width; } } } $self->history("cmd_untar|$filename|$full_path") if ($self->{cfg}->{multi}); #save log info $self->{cgi}->{cmd_do} = 'cmd_tar'; $filename =~ s,$root_path/,,; $self->cmd_main_display({reload => 1, status => sprintf($LANGUAGE{MSG_UNCOMPRESS}, $filename)}); } END_OF_SUB $COMPILE{cmd_show_passwd} = __LINE__ . <<'END_OF_SUB'; sub cmd_show_passwd { my ($self, $msg) = @_; $self->cmd_main_display({ msg => $msg, show_passwd => 1 }); } END_OF_SUB $COMPILE{cmd_passwd} = __LINE__ . <<'END_OF_SUB'; sub cmd_passwd { # ------------------------------------------------------------------ # Save username and password # my $self = shift; my $pass_path = $self->{in}->cookie('def_passwd_dir'); my $work_path = $self->{work_path} || ''; my $url_opts = $self->{url_opts} || ''; my $htpasswd; if ($pass_path) { # create .htaccess and .htpasswd in Password directory my $file_name = $self->_safe_dir(); $file_name =~ s/[\/ \:]/\_/g; $htpasswd = "$pass_path/.htpass$file_name"; if (!-e $htpasswd) { open (FILE, "> $htpasswd"); close FILE; } } else { my $fpasswd = $self->_safe_file(".htpasswd", { fullfile => 1, exist => 1, size => 1}); $htpasswd = $fpasswd->{file}; if (!$fpasswd->{exist}) { open (FILE, "> $htpasswd"); close FILE; } } my $faccess = $self->_safe_file(".htaccess", { fullfile => 1, exist => 1, size => 1}); my $htaccess = $faccess->{file}; if (!$faccess->{exist}) { open (FILE, "> $htaccess"); close FILE; } unless (-w $htaccess and -w $htpasswd) { #check writeable print $self->{in}->header; print sprintf($LANGUAGE{ERR_FILE_PERM},$htaccess,$htpasswd),'
', sprintf($LANGUAGE{MSG_CONTINUE},$self->{http_ref},$work_path,$url_opts); return; } if ( !$faccess->{exist} or $faccess->{size} == 0 ) { _create_htaccess($htaccess, $htpasswd); } else { open (HTACC, "< $htaccess") or die "Unable to open: $htpasswd ($!)"; my @info = ; close HTACC; my $found; LINE: foreach ( @info ) { if ( $_ =~ /$htpasswd/ ) { $found = 1; last;<%delete_list%> } } _create_htaccess($htaccess, $htpasswd) if ( !$found ); } if ($self->{cgi}->{remove_all}) { if (! unlink($htpasswd)) { open (HTPAS, "> $htpasswd") or die "Unable to open: $htpasswd ($!)"; close HTPAS; } if (!unlink($htaccess)) {; # delete file open (HTACC, "> $htaccess") or die "Unable to open: $htaccess ($!)"; close HTACC; } return $self->cmd_show_passwd($LANGUAGE{MSG_USER_RMALL}); } my (@users,$msg); my $username = $self->{cgi}->{p_username} || ''; my $password = $self->{cgi}->{p_password} || ''; my $to_delete = ($self->{cgi}->{remove})? $self->{cgi}->{delete_user} : $username; if ($to_delete) { open (HTPAS, "< $htpasswd") or die "Unable to open: $htpasswd ($!)"; @users = grep { $_ !~ /^$to_delete:/ } ; close HTPAS; $msg = sprintf($LANGUAGE{MSG_USER_DELETED}, $to_delete); } if ($username and $password) { my @salt_chars = ('A' .. 'Z', 0 .. 9, 'a' .. 'z', '.', '/'); my $salt = join '', @salt_chars[rand 64, rand 64]; my $encrypted = crypt($password, $salt); push @users, "$username:$encrypted\n"; $msg = sprintf($LANGUAGE{MSG_USER_ADDED}, $username); } if (($username and $password) or $to_delete) { open (HTPAS, "> $htpasswd") or die "Unable to open: $htpasswd ($!)"; print HTPAS join ("", @users); close HTPAS; if (!@users) { if (! unlink($htpasswd)) { open (HTPAS, "> $htpasswd") or die "Unable to open: $htpasswd ($!)"; close HTPAS; } if (!unlink($htaccess)) {; # delete file open (HTACC, "> $htaccess") or die "Unable to open: $htaccess ($!)"; close HTACC; } } } $self->cmd_show_passwd($msg); } END_OF_SUB $COMPILE{printenv} = __LINE__ . <<'END_OF_SUB'; sub printenv { # ------------------------------------------------------------------ my $self = shift; ($self->{cfg}->{multi}) and die "It doesn't support for this version"; my $work_path = $self->{work_path} || ''; print $self->{in}->header ; print qq!

!; print $self->_environment(); } END_OF_SUB sub history { #--------------------------------------------------------------------- # Save the history # my ($self,$content) = @_; return if (!$content); my $priv_path = $self->{cfg}->{priv_path}; my $db_name = 'fileman_history.db'; $content = $self->{cfg}->{username} . '|' . $ENV{'REMOTE_ADDR'} . '|' . time . "|$content\n"; open (DATA,">>$priv_path/$db_name") or die sprintf($LANGUAGE{ERR_OPEN_FILE}, $db_name, $!); flock(DATA, 2); print DATA $content; close DATA; } sub _environment { # -------------------------------------------------------------------- # Return HTML formatted environment for error messages. # my $self = shift; my $info = '

';

# Print GT::SQL error if it exists.
    $info .= "System Information\n======================================\n";
    $info .= "Perl Version: $]\n";
    $info .= "FileMan Version: $self->{cfg}->{version}" if ($self->{cfg}->{version});
    $info .= "\n";
    my $cmds = $self->{commands};
    foreach  (keys %$cmds) {
        $info .= $_."\t:";
        $info .= ($cmds->{$_})?('enabled'):('disabled');
        $info .= "\n";
    }
    $info .= "Persistant Env: mod_perl (" . (MOD_PERL ? 1 : 0) . ") SpeedyCGI (" . (SPEEDY ? 1 : 0) . ")\n";
    $info .= "Mod Perl Version: " . MOD_PERL . "\n" if MOD_PERL;
    $info .= "\@INC = \n\t" . join ("\n\t", @INC) . "\n";
    $info .= "\$\@: $@\n" if ($@);
    $info .= "\n";

# CGI Parameters and Cookies.
    if (ref $self->{in} eq 'GT::CGI') {
        if ($self->{in}->param) {
            $info .= "CGI INPUT\n======================================\n";
            foreach (sort $self->{in}->param) { $info .= "$_ => " . $self->{in}->param($_) . "\n"; }
            $info .= "\n\n";
        }
        if ($self->{in}->cookie) {
            $info .= "CGI Cookies\n======================================\n";
            foreach (sort $self->{in}->cookie) { $info .= "$_ => " . $self->{in}->cookie($_) . "\n"; }
            $info .= "\n\n";
        }
    }

# Environement info.
    $info  .= "ENVIRONMENT\n======================================\n";
    foreach (sort keys %ENV) { $info .= "$_ => $ENV{$_}\n"; }
    $info .= "
"; return $info; } sub _zip_information { #---------------------------------------------------------------------- # Show the information about a zip file # my ($self, $filename, $status) = @_; my $fullfile = $self->_safe_file($filename, { fullfile => 1, exist => 1, size => 1 }); my $zip = new Archive::Zip($fullfile->{file}) or return $self->cmd_main_display({reload => 0, status => $!}); my $cmp_file = $fullfile->{file}; my $stat = [stat($cmp_file)]; my $hits = $zip->members + 1; my $pg = $self->{cgi}->{pg} || 1; my $mh = $self->{in}->cookie('def_files_page') || 25; my $start= ($pg == 1) ? 1 : (($pg - 1) * $mh + 1); my @results; my $total_size = $fullfile->{size}; my $skip = 0; if ( $hits > 0 ) { foreach ( $zip->members ) { $skip++; next if ($skip < $start); my $s = $_->compressedSize; my $icon = _get_icon($_->fileName); push @results, { icon => "{icon} )."' width=14 height=16>", name => $_->fileName, size => ( $s ) ? _print_filesize($s) : '', date => _get_date($_->lastModTime), chmod => _print_permissions($_->unixFileAttributes), uid => '', type => '', nsize => ( $s ) ? _print_filesize($s) : '' }; last if ( $#results + 1 >= $mh ); } } # Creates the speed bar my $speed_bar; if ( $hits > ($self->{in}->cookie('def_files_page') || 25) ) { $speed_bar = $self->speed_bar($hits, "$self->{http_ref}?cmd_do=cmd_edit&work_path=$self->{work_path}&c_edit=$filename;$self->{url_opts}", 1); } if (!$status) { $status = sprintf($LANGUAGE{MSG_FILE_EDITING},'The content of ', $filename, -s $cmp_file, $filename); } $self->page('tar_information.html', { results => \@results, count => $#results + 1, cmp_file => $filename, user => eval { getpwuid(@$stat[4]); } || '', total_size => $total_size, total_space => $total_size, num_objects => ($#results >= 0 ) ? $#results + 1 : 0, status => $status, speed_bar => $speed_bar }); } sub _tar_information { #---------------------------------------------------------------------- # Show information about a tar file # my ($self, $filename, $status) = @_; my $fullfile = $self->_safe_file($filename, {fullfile => 1, exist => 1, size => 1}); return $self->cmd_main_display({reload => 0, status => sprintf($LANGUAGE{ERR_INVALID}, $filename)}) if ($fullfile == -1); return $self->cmd_main_display({reload => 0, status => sprintf($LANGUAGE{ERR_FILE_NOT_EXISTS}, $filename)}) if (!$fullfile->{exist}); my $cmp_file = $fullfile->{file}; my $stat = [stat($cmp_file)]; if ($cmp_file =~ m,([^/]*[\.tar\.gz]$),) { my ($files, @results); my $pg = $self->{cgi}->{pg} || 1; my $mh = $self->{in}->cookie('def_files_page') || 25; my $start= ($pg == 1) ? 1 : (($pg - 1) * $mh + 1); require GT::Tar; my $tar = GT::Tar->open ($cmp_file) or return $self->cmd_main_display({reload => 1, status => sprintf($LANGUAGE{ERR_FILE_OPEN},$!)}); $files = $tar->files; my $total_size = 0; my $skip = 0; foreach my $file (@$files) { # get uncompressedsize $total_size += $file->{size} if ( $file->{size} ); } foreach my $file (@$files) { $skip++; next if ($skip < $start); my $spec = _get_icon($file->{name}); push @results, { icon => "", name => $file->{name}, size => ($file->{type} eq '5')? '': _print_filesize($file->{size}), date => _get_date($file->{mtime}), chmod => _print_permissions($file->{mode}), uid => eval { getpwuid($file->{uid}); } || '', type => $file->{type}, nsize => ($file->{type} eq '5')? '': $file->{size} }; last if ( $#results + 1 >= $mh ); } my $root_path = $self->{cfg}->{root_dir}; my $url_opts = $self->{url_opts} || ''; my $work_path = $self->{work_path} || ''; my $full_path = $root_path.(($work_path)?'/':'').$work_path; # Creates the speed bar my $speed_bar; if ( $#$files + 1 > ($self->{in}->cookie('def_files_page') || 25) ) { $speed_bar = $self->speed_bar($#$files, "$self->{http_ref}?cmd_do=cmd_edit&work_path=$self->{work_path}&c_edit=$filename;$self->{url_opts}", 1); } if (!$status) { $status = sprintf($LANGUAGE{MSG_FILE_EDITING},'The content of ', $filename,-s $cmp_file, $filename); } $self->page('tar_information.html', { results => \@results, count => $#$files+1, cmp_file => $filename, user => eval { getpwuid(@$stat[4]); } || '', total_size => $total_size, total_space => $total_size, num_objects => ($#results >=0)? $#results + 1:0, status => $status, speed_bar => $speed_bar }); } } sub _tar_check { my $file = shift; if ($file =~ /.zip$/i) { return $LANGUAGE{ERR_NO_AZIP} unless $GT::FileMan::HAVE_AZIP; } elsif ($file =~ /.gz$/i) { return $LANGUAGE{ERR_NO_GZIP} unless $GT::FileMan::HAVE_GZIP; } return; } sub _tar_size { my $file = shift; my $size = 0; if ($file =~ /.zip$/i) { my $zip = Archive::Zip->new($file) or return; foreach ( $zip->members ) { $size += $_->uncompressedSize; } } else { require GT::Tar; my $tar = GT::Tar->open($file); my $files = $tar->files; foreach (@$files) { $size += $_->{size}; } } return $size; } sub _checkspace { # ----------------------------------------------------- # Check for allowed disk space to determine whether we can allow # editing or uploads. # my $self = shift; my $directory = shift || $self->{cfg}->{root_dir}; return if (!$self->{cfg}->{allowed_space}); my ($used_space, $free_space, $allowed_space, $usage) = (0, 0, 0); find($directory, sub {$used_space += -s shift}); # Size in kb $allowed_space = $self->{cfg}->{allowed_space}/1024; $used_space /= 1024; $free_space = $allowed_space - $used_space; $usage = $used_space / $allowed_space * 100 if ($allowed_space > 0); return { free_space => int($free_space), allowed_space => int($allowed_space), used_space => int($used_space), usage => int($usage) }; } sub _file_info { #------------------------------------------------------------------ # Show file information # my ($self,$fullfile) = @_; my $hash; my $url_opts = $self->{url_opts} || ''; my $url = "$self->{http_ref}?fdo=cmd_main_display&$url_opts"; my $html_url = $self->{cfg}->{html_root_url}; my $name = $fullfile; my $work_path = $self->{work_path} || ''; my $full_path = $self->{cfg}->{root_dir}.'/'.$work_path.(($work_path)?'/':''); my $stat = [stat($fullfile)]; $name =~ s/$full_path//; $hash->{value} = $fullfile; if (-d _) { $hash->{name} = $name; $hash->{icon} = ""; $hash->{type} = 'Folder'; $hash->{isdir}= '1'; $hash->{size} = 0; } else { my $spec = _get_icon($fullfile); $hash->{name} = $name; $hash->{icon} = "{icon}."' width=14 height=16>"; $hash->{type} = $spec->{type}; $hash->{isdir} = '0'; $hash->{size} = @$stat[7]; $hash->{nsize} = @$stat[7]; } $hash->{date} = @$stat[9]; $hash->{perm} = @$stat[2]; my $user = eval { getpwuid(@$stat[4]); } || ''; $hash->{user} = $user; return $hash; } sub speed_bar { # ------------------------------------------------------------------ # Create a speed bar # my($self, $rows, $url, $off) = @_; return if ($self->{cgi}->{pg} eq 'all'); # display all my $work_path = $self->{work_path} || ''; my $sb = $self->{cgi}->{sb} || ''; my $sd = $self->{cgi}->{sd} || ''; my $url_opts = $self->{url_opts} || ''; $url ||= "$self->{http_ref}?fdo=cmd_main_display&work_path=$work_path&sb=$sb&sd=$sd&$url_opts"; my $cur_pg = $self->{cgi}->{pg} || '1'; my $pg = ($cur_pg eq 'all')? 1 : $cur_pg; my $rows_pg = $self->{in}->cookie('def_files_page') || 25; my $scre_pg = $self->{in}->cookie('def_pages_screen') || 10; my $pages = int($rows / $rows_pg) + (($rows % $rows_pg > 0) ? 1 : 0); my $next = ""; my $next_grey = ""; my $prev = ""; my $prev_grey = ""; my $first = ""; my $first_grey= ""; my $last = ""; my $last_grey = ""; my ($speed_bar, $pg_step, $start, $jj); if ( $scre_pg > 0 ) { $pg_step = ($pg % $scre_pg > 0) ? int($pg / $scre_pg) + 1 : ($pg / $scre_pg); } $start = 1; if ($pages > $scre_pg) { $start = ($pg == $pages) ? ($pg - $scre_pg) + 1 : (($pg_step - 1) * $scre_pg)+1; $start = ($pages - $start + 1 < $scre_pg) ? $start - ($scre_pg - ($pages - $start + 1)) : $start; } $speed_bar = ($pg > 1) ? "$first $prev " : "$first_grey $prev_grey "; $speed_bar .= ($pg > $scre_pg)? '...' : ''; for my $ii ( $start .. $pages) { $jj++; if ($cur_pg eq 'all') { $speed_bar .= "$ii " } else { $speed_bar .= ($cur_pg == $ii)? "$ii " : "$ii "; } if ($jj == $scre_pg) { $speed_bar .= ( ($pg_step * $scre_pg) < $pages) ? "..." : ""; last; } } $speed_bar .= ($pg < $pages) ? "$next $last" : "$next_grey $last_grey"; $speed_bar .= ($cur_pg eq 'all') ? " All " : " All " if ( !$off ); return $speed_bar; } sub qsort { # ------------------------------------------------------------------ my ($self,$list_file,$orderby,$sortdown) = @_; my $sorted; @$sorted = sort { my $da = lc $a->{$orderby}; #lower case my $db = lc $b->{$orderby}; my $res; if ($orderby eq 'size' or $orderby eq 'date') { $res = $db <=> $da; } else { $res = $db cmp $da; } if ($res == 0 and $orderby ne 'name') { lc $b->{name} cmp lc $a->{name}; } else { $res; } } @$list_file; ($sortdown) and @$sorted = reverse @$sorted; return $sorted; } sub _zip_process { #-------------------------------------------------------------- # Create a .zip file # my ($self, $to, $files) = @_; my $from = $self->_safe_dir(); if ($self->{cgi}->{cancel}) { #canceled create tar file $self->{cgi}->{cmd_do} = 'cmd_tar'; return $self->cmd_main_display({ reload => 1, status => $LANGUAGE{MSG_TAR_CANCEL}}); } my $history = 'cmd_tar|'; require Archive::Zip::Tree; my $zip = Archive::Zip->new(); my $member; foreach my $file (@$files) { if ( -f "$from/$file" ) { $member = $zip->addFile("$from/$file", $file) or warn "$!"; } elsif ( -d "$from/$file" ) { $member = $zip->addTree("$from/$file", $file) or warn "$!"; } } return $zip->writeToFileNamed($to) ? "$!" : 0; } sub _tar_process { #-------------------------------------------------------------- # Create tar file # my ($self, $to) = @_; my $from = $self->_safe_dir(); if ($self->{cgi}->{cancel}) { #canceled create tar file $self->{cgi}->{cmd_do} = 'cmd_tar'; return $self->cmd_main_display({ reload => 1, status => $LANGUAGE{MSG_TAR_CANCEL}}); } my $input = $self->{cgi}->{txt_input}; my $files = [$self->{in}->param('c_edit')]; my $history = 'cmd_tar|'; # Make sure tar file goes out of scope and cleans up temp files { my $tar; require GT::Tar; $tar = new GT::Tar($to) or return $self->cmd_main_display({ reload => 1, status => sprintf($LANGUAGE{ERR_TAR},$GT::Tar::error)}); foreach my $file (@$files) { my $fulldir = $self->_safe_dir($file); next if ($fulldir == 1); $tar->add_file($fulldir->{fulldir}); } my $items = $tar->files; foreach my $fl (@$items) { $fl->{name} =~ s/$from\///; } $tar->write("$to"); $history .= "|$to"; } } sub _safe_file { #------------------------------------------------------------------------ # Check a file make sure it safe # my ($self, $file, $options) = @_; my $root = $self->{cfg}->{root_dir}; return { file => $root } if ($file eq '/'); return -1 if ($self->{cfg}->{filename_check} and $file !~ m,^([-\w/. ]+)$,); return -1 if ($file =~ /$GT::FileMan::UNSAFE_PATH/); # Check if proper work_path (/ stands for root dir, otherwise use current dir) my $path_to_file = ($file =~ m,^/,) ? $file : "$self->{work_path}/$file"; $path_to_file =~ s,^/,,; my $fullfile = $root.'/'.$path_to_file; my ($e, $w, $t, $s, $f); foreach my $key (keys % $options) { if ($options->{$key} == 1) { ($key eq 'exist') and $e = -e $fullfile; ($key eq 'write') and $w = -w $fullfile; ($key eq 'text') and $t = -T $fullfile; ($key eq 'size') and $s = -s $fullfile; ($key eq 'isfile') and $f = -f $fullfile; } } return { file => ($options->{fullfile} == 1) ? $fullfile : $file, exist => $e, write => $w, text => $t, size => $s, isfile => $f, }; } sub _view_file { #------------------------------------------------------ # print the content of a file # my ($self,$filename) = @_; my $file = $self->_safe_file($filename,{ fullfile => 1, size => 1}); ($file == -1) and return; # not safe # Load content-type of a image file. my $fullfile = $file->{file}; my $file_size = $file->{size}; my $content_type = _load_mime($fullfile); my ($ext) = $fullfile =~ /\.([^.]+)$/; if(open(DATA, $fullfile)) { $self->{in}->reset_env(); if ((($content_type =~ m/text/) or -T $fullfile) and (uc($ext) ne 'PDF')) { my $url_opts = $self->{url_opts} || ''; my $work_path = $self->{work_path} || ''; print $self->{in}->header; print qq!
    !; print '
    ' if (not $content_type =~ m/htm/);
            }
            else {
                print $self->{in}->header({
                    '-force'          => 1,
                    '-type'           => $content_type,
                    '-Content-Disposition' => \"filename=$filename",
                    '-Content-Length' => $file_size,
                });
            }
            ($self->{cfg}->{winnt}) and binmode STDOUT;
            binmode DATA;
            my $buffer;
            print $buffer while (read(DATA, $buffer , $READ_SIZE));
            close(DATA);
        }
    }
    
    sub _safe_dir {
    #------------------------------------------------------------------------
    # Check a directory make sure it safe
    #
        my ($self, $dir, $options) = @_;
    
        my $root = $self->{cfg}->{root_dir};
        my $work = $self->{work_path};
    
        my $fulldir;
        unless ($dir) {
            return ($work) ? "$root/$work" : $root;
        }
        elsif ($dir eq '/') {
            return $root;
        }
    
        return -1 if ($self->{cfg}->{filename_check} and $dir !~ m,^([-\w/. ]+)$,);
        return -1 if ($dir =~ /$GT::FileMan::UNSAFE_PATH/);
    
        ($dir =~ m,^/,) ? ($fulldir = $root . $dir)
                        : ($fulldir = $root. ($work ? '/' : '') . $work . '/' . $dir);
        my ($e, $d, $w);
        foreach my $key (keys % $options) {
            if ($options->{$key} == 1) {
                $e = -e $fulldir if ($key eq 'exist');
                $d = -d $fulldir if ($key eq 'isdir');
                $w = -w $fulldir if ($key eq 'write');
            }
        }
        return { fulldir => $fulldir, exist => $e, isdir => $d, write => $w };
    }
    
    sub _command_show {
    #--------------------------------------------------------------------
    # Show path when execute cd command
    #
        my ($working_dir, $cmd) = @_;
        if ($cmd =~ m/^\s*cd\s*\.\./) { # cd ..
            my $tmp;
            my $parts = [split(/\//, $working_dir)];
            return '/' if ($#$parts == 1 or $working_dir eq '/');
    
            foreach my $ii( 0 .. $#$parts) {
                $tmp .= '/'.@$parts[$ii] if ($ii < $#$parts and @$parts[$ii]);
            }
            return $tmp;
        }
        return $working_dir if ($cmd =~ m/^\s*cd\s*\./); # cd.
        my $path = $cmd;
        $path    =~ s/\s*cd\s*//;
        return '/' if ($path =~ m,^(/+)$,);
        return ($path =~ m/^\//)? $path : $working_dir.(($working_dir and $working_dir ne '/')? '/' : '').$path;
    }
    
    sub _get_icon {
    # ------------------------------------------------------------------
    # Get the associated icon based on a files extension
    #
        my ($file) = shift;
        my ($ext)  = $file =~ /\.([^.]+)$/;
        return {icon => 'unknown.gif', type => 'unknown File'} if (!$ext);
        foreach (keys %{$ICONS}) {
            next if (/folder/);
            next if (/unknown/);
            next if (/parent/);
            ($_ =~ /\b\Q$ext\E\b/i) and return { icon => $ICONS->{$_}[0],type => $ICONS->{$_}[1]};
        }
        return {icon => 'unknown.gif', type => "$ext File"};
    }
    
    sub _get_date {
    # ------------------------------------------------------------------
        my $time = shift;
        $time or ($time = time);
        my @months = qw!Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec!;
    
        my ($min, $hr, $day, $mon, $yr) = (localtime($time))[1,2,3,4,5];
        $yr = $yr + 1900;
        ($min < 10) and ($min = "0$min");
        ($hr  < 10) and ($hr  = "0$hr");
        ($day < 10) and ($day = "0$day");
    
        return "$day-$months[$mon]-$yr $hr:$min";
    }
    
    sub _print_filesize {
    # ------------------------------------------------------------------
    # Prints out the file size.
    #
        my $size = shift;
        my $formatted_size = 0;
        $formatted_size = int($size / 1000) if ($size);
        return $formatted_size == 0 ? "$size bytes" : $formatted_size." kb";
    }
    
    sub _print_permissions {
    # ------------------------------------------------------------------
    # Takes permissions in octal and prints out in ls -al format.
    #
        my $octal  = shift;
        my $string = sprintf "%lo", ($octal & 07777);
        my $result = '';
        foreach (split(//, $string)) {
            if    ($_ == 7) { $result .= "rwx "; }
            elsif ($_ == 6) { $result .= "rw- "; }
            elsif ($_ == 5) { $result .= "r-x "; }
            elsif ($_ == 4) { $result .= "r-- "; }
            elsif ($_ == 3) { $result .= "-wx "; }
            elsif ($_ == 2) { $result .= "-w- "; }
            elsif ($_ == 1) { $result .= "--x "; }
            elsif ($_ == 0) { $result .= "--- "; }
            else            { $result .= "unkown '$_'!"; }
        }
        return $result;
    }
    
    sub _load_mime {
    # --------------------------------------------------------------------
    # Load the config file into a hash.
    #
        my $file = shift;
        require GT::MIMETypes;
        my $guess = GT::MIMETypes->guess_type($file);
        if (! $guess) {
            if (-e $file) {
                $guess = -T _ ? 'text/plain' : 'application/octet-stream';
            }
            else {
                $guess = 'application/octet-stream';
            }
        }
        return $guess;
    }
    
    sub _init_chmod {
    #---------------------------------------------------------------------
    # set chmod
    #
        my($from,$to) = @_;
        $from =~ m,^([/\w.-]+)$,;
        $from = $1;
    
        $to =~ m,^([/\w.-]+)$,;
        $to = $1;
    
        my $stat = [stat($from)];
        chmod(@$stat[2],$to);
    }
    
    sub _create_htaccess {
    # ------------------------------------------------------------------
    # Creates the htaccess file.
    #
        my ($htaccess, $htpasswd) = @_;
        my $raq = $ENV{GT_COBALT_RAQ} ? "AuthPAM_Enabled off\n" : '';
        open (HTAC, "> $htaccess") or die "Unable to open: $htaccess ($!)";
        print HTAC <$to") or return 0;
        open(SOURCE, "<$from") or return 0;
        binmode SOURCE;
        binmode TARGET;
        my $buffer;
        while (read SOURCE, $buffer, $READ_SIZE) {
            if ($repl) {
                ($cs)? ($buffer =~ s,$repl,$with,g)
                     : ($buffer =~ s,$repl,$with,ig);
            }
            print TARGET $buffer;
        }
        close SOURCE;
        close TARGET;
        _init_chmod($from,$to);
        return 1;
    }
    
    sub _valid_name_check {
    # ---------------------------------------------------
    # Checks to see if the input database/table name is a
    # valid one.  The function checks the following:
    # 1. if a name is entered at all;
    # 2. if there are spaces in the name;
    # 3. if the name is consisted of valid characters; and
    # 4. if the name is consisted of only numbers.
    
        my ($self, $name) = @_;
        my ($output);
    
        $name =~ s/^\s+//;
        $name =~ s/\s+$//;
        if (!$name) {
            $output = "Please provide a valid name.";
        }
        elsif ($self->{cfg}->{filename_check} and $name =~ /\s/) {
            $output = "Spaces are not allowed in name.";
        }
        return $output;
    }
    
    1;