Files
webmin/filemin/filemin-lib.pl
2016-02-22 20:06:44 -08:00

405 lines
16 KiB
Perl

# filemin-lib.pl
BEGIN { push(@INC, ".."); };
use WebminCore;
&init_config();
use Encode qw(decode encode);
use File::Basename;
use POSIX;
sub get_paths {
%access = &get_module_acl();
# Switch to the correct user
if (&get_product_name() eq 'usermin') {
# In Usermin, the module only ever runs as the connected user
&switch_to_remote_user();
&create_user_config_dirs();
}
elsif ($access{'work_as_root'}) {
# Root user, so no switching
@remote_user_info = getpwnam('root');
}
elsif ($access{'work_as_user'}) {
# A specific user
@remote_user_info = getpwnam($access{'work_as_user'});
@remote_user_info ||
&error("Unix user $access{'work_as_user'} does not exist!");
&switch_to_unix_user(\@remote_user_info);
}
else {
# The Webmin user we are connected as
&switch_to_remote_user();
}
# Get and check allowed paths
@allowed_paths = split(/\s+/, $access{'allowed_paths'});
if (&get_product_name() eq 'usermin') {
# Add paths from Usermin config
push(@allowed_paths, split(/\t+/, $config{'allowed_paths'}));
}
if($remote_user_info[0] eq 'root' || $allowed_paths[0] eq '$ROOT') {
# Assume any directory can be accessed
$base = "/";
@allowed_paths = ( $base );
} else {
@allowed_paths = map { $_ eq '$HOME' ? @remote_user_info[7] : $_ }
@allowed_paths;
@allowed_paths = map { s/\$USER/$remote_user/g; $_ } @allowed_paths;
if (scalar(@allowed_paths == 1)) {
$base = $allowed_paths[0];
} else {
$base = '/';
}
}
$path = $in{'path'} ? $in{'path'} : '';
$cwd = &simplify_path($base.$path);
# Work out max upload size
if (&get_product_name() eq 'usermin') {
$upload_max = $config{'max'};
} else {
$upload_max = $access{'max'};
}
# Check that current directory is one of those that is allowed
my $error = 1;
for $allowed_path (@allowed_paths) {
if (&is_under_directory($allowed_path, $cwd) ||
$allowed_path =~ /^$cwd/) {
$error = 0;
}
}
if ($error) {
&error(&text('notallowed', &html_escape($cwd),
&html_escape(join(" , ", @allowed_paths))));
}
if (index($cwd, $base) == -1)
{
$cwd = $base;
}
# Initiate per user config
$confdir = "$remote_user_info[7]/.filemin";
if(!-e "$confdir/.config") {
&read_file_cached("$module_root_directory/defaultuconf", \%userconfig);
} else {
&read_file_cached("$confdir/.config", \%userconfig);
}
}
sub print_template {
$template_name = @_[0];
if (open(my $fh, '<:encoding(UTF-8)', $template_name)) {
while (my $row = <$fh>) {
print (eval "qq($row)");
}
} else {
print "$text{'error_load_template'} '$template_name' $!";
}
}
sub print_errors {
my @errors = @_;
&ui_print_header(undef, "Filemin", "");
print $text{'errors_occured'};
print "<ul>";
foreach $error(@errors) {
print("<li>$error</li>");
}
print "<ul>";
&ui_print_footer("index.cgi?path=$path", $text{'previous_page'});
}
sub print_interface {
# Some vars for "upload" functionality
local $upid = time().$$;
local @remote_user_info = getpwnam($remote_user);
local $uid = @remote_user_info[2];
$bookmarks = get_bookmarks();
@allowed_for_edit = split(/\s+/, $access{'allowed_for_edit'});
%allowed_for_edit = map { $_ => 1} @allowed_for_edit;
# Set things up according to currently used theme
if ($current_theme eq 'authentic-theme' or $current_theme eq 'bootstrap') {
# Interface for Bootstrap 3 powered themes
# Set icons variables
$edit_icon = "<i class='fa fa-edit' alt='$text{'edit'}'></i>";
$rename_icon = "<i class='fa fa-font' title='$text{'rename'}'></i>";
$extract_icon = "<i class='fa fa-external-link' alt='$text{'extract_archive'}'></i>";
$goto_icon = "<i class='fa fa-arrow-right' alt='$text{'goto_folder'}'></i>";
# Add static files
print "<script type=\"text/javascript\" src=\"unauthenticated/js/main.js\"></script>";
print "<script type=\"text/javascript\" src=\"unauthenticated/js/chmod-calculator.js\"></script>";
print "<script type=\"text/javascript\" src=\"unauthenticated/js/dataTables.bootstrap.js\"></script>";
print "<script type=\"text/javascript\" src=\"unauthenticated/js/bootstrap-hover-dropdown.min.js\"></script>";
print "<link rel=\"stylesheet\" type=\"text/css\" href=\"unauthenticated/css/style.css\" />";
print "<link rel=\"stylesheet\" type=\"text/css\" href=\"unauthenticated/css/dataTables.bootstrap.css\" />";
init_datatables();
# Set "root" icon
if($base eq '/') {
$root_icon = "<i class='fa fa-hdd-o'></i>";
} else {
$root_icon = "~";
}
# Breadcrumbs
print "<ol class='breadcrumb pull-left'><li><a href='index.cgi?path='>$root_icon</a></li>";
my @breadcr = split('/', $path);
my $cp = '';
for(my $i = 1; $i <= scalar(@breadcr)-1; $i++) {
chomp($breadcr[$i]);
$cp = $cp.'/'.$breadcr[$i];
print "<li><a href='index.cgi?path=$cp'>".
&html_escape($breadcr[$i])."</a></li>";
}
print "</ol>";
# And toolbar
if($userconfig{'menu_style'}) {
print_template("unauthenticated/templates/menu.html");
} else {
print_template("unauthenticated/templates/quicks.html");
}
$page = 1;
$pagelimit = 9001; # IT'S OVER NINE THOUSAND!
print_template("unauthenticated/templates/dialogs.html");
} else {
# Interface for legacy themes
# Set icons variables
$edit_icon = "<img src='images/icons/quick/edit.png' alt='$text{'edit'}' />";
$rename_icon = "<img src='images/icons/quick/rename.png' alt='$text{'rename'}' />";
$extract_icon = "<img src='images/icons/quick/extract.png' alt='$text{'extract_archive'}' />";
$goto_icon = "<img src='images/icons/quick/go-next.png' alt='$text{'goto_folder'}'";
# Add static files
$head = "<link rel=\"stylesheet\" type=\"text/css\" href=\"unauthenticated/css/style.css\" />";
$head.= "<script type=\"text/javascript\" src=\"unauthenticated/jquery/jquery.min.js\"></script>";
$head.= "<script type=\"text/javascript\" src=\"unauthenticated/jquery/jquery-ui.min.js\"></script>";
$head.= "<script type=\"text/javascript\" src=\"unauthenticated/js/legacy.js\"></script>";
$head.= "<link rel=\"stylesheet\" type=\"text/css\" href=\"unauthenticated/jquery/jquery-ui.min.css\" />";
$head.= "<script type=\"text/javascript\" src=\"unauthenticated/js/chmod-calculator.js\"></script>";
$head.= "<link rel=\"stylesheet\" type=\"text/css\" href=\"unauthenticated/dropdown/fg.menu.css\" />";
$head.= "<script type=\"text/javascript\" src=\"unauthenticated/dropdown/fg.menu.js\"></script>";
print $head;
# Set "root" icon
if($base eq '/') {
$root_icon = "<img src=\"images/icons/quick/drive-harddisk.png\" class=\"hdd-icon\" />";
} else {
$root_icon = "~";
}
# Legacy breadcrumbs
print "<div id='bread' style='float: left; padding-bottom: 2px;'><a href='index.cgi?path='>$root_icon</a> / ";
my @breadcr = split('/', $path);
my $cp = '';
for(my $i = 1; $i <= scalar(@breadcr)-1; $i++) {
chomp($breadcr[$i]);
$cp = $cp.'/'.$breadcr[$i];
print "<a href='index.cgi?path=$cp'>".
&html_escape($breadcr[$i])."</a> / ";
}
print "<br />";
# And pagination
$page = $in{'page'};
$pagelimit = $userconfig{'per_page'};
$pages = ceil((scalar(@list))/$pagelimit);
if (not defined $page or $page > $pages) { $page = 1; }
print "Pages: ";
for(my $i = 1;$i <= $pages;$i++) {
if($page eq $i) {
print "<a class='pages active' ".
"href='?path=$path".
"&page=$i".
"&query=$query".
"'>".&html_escape($i)."</a>";
} else {
print "<a class='pages' ".
"href='?path=$path".
"&page=$i".
"&query=$query'>".&html_escape($i)."</a>";
}
}
print "</div>";
# And toolbar
print_template("unauthenticated/templates/legacy_quicks.html");
print_template("unauthenticated/templates/legacy_dialogs.html");
}
print "<div class='total'>" . &text('info_total', scalar @files, scalar @folders) . "</div>";
# use Data::Dumper;
# print Dumper(\%allowed_for_edit);
# Render current directory entries
print &ui_form_start("", "post", undef, "id='list_form'");
@ui_columns = (
'<input id="select-unselect" type="checkbox" onclick="selectUnselect(this)" />',
''
);
push @ui_columns, $text{'name'};
push @ui_columns, $text{'type'} if($userconfig{'columns'} =~ /type/);
push @ui_columns, $text{'actions'};
push @ui_columns, $text{'size'} if($userconfig{'columns'} =~ /size/);
push @ui_columns, $text{'owner_user'} if($userconfig{'columns'} =~ /owner_user/);
push @ui_columns, $text{'permissions'} if($userconfig{'columns'} =~ /permissions/);
push @ui_columns, $text{'last_mod_time'} if($userconfig{'columns'} =~ /last_mod_time/);
print &ui_columns_start(\@ui_columns);
#foreach $link (@list) {
for(my $count = 1 + $pagelimit*($page-1);$count <= $pagelimit+$pagelimit*($page-1);$count++) {
if ($count > scalar(@list)) { last; }
my $class = $count & 1 ? "odd" : "even";
my $link = $list[$count - 1][0];
$link =~ s/\Q$cwd\E\///;
$link =~ s/^\///g;
$vlink = html_escape($link);
$vlink = quote_escape($vlink);
$vlink = decode('UTF-8', $vlink, Encode::FB_CROAK);
$path = html_escape($path);
$vpath = quote_escape($vpath);
$vpath = decode('UTF-8', $vpath, Encode::FB_CROAK);
my $type = $list[$count - 1][14];
$type =~ s/\//\-/g;
my $img = "images/icons/mime/$type.png";
unless (-e $img) { $img = "images/icons/mime/unknown.png"; }
$size = &nice_size($list[$count - 1][8]);
$user = getpwuid($list[$count - 1][5]) ? getpwuid($list[$count - 1][5]) : $list[$count - 1][5];
$group = getgrgid($list[$count - 1][6]) ? getgrgid($list[$count - 1][6]) : $list[$count - 1][6];
$permissions = sprintf("%04o", $list[$count - 1][3] & 07777);
$mod_time = POSIX::strftime('%Y/%m/%d - %T', localtime($list[$count - 1][10]));
$actions = "<a class='action-link' href='javascript:void(0)' onclick='renameDialog(\"$vlink\")' title='$text{'rename'}' data-container='body'>$rename_icon</a>";
if ($list[$count - 1][15] == 1) {
$href = "index.cgi?path=".&urlize("$path/$link");
} else {
$href = "download.cgi?file=".&urlize($link)."&path=".&urlize($path);
if($0 =~ /search.cgi/) {
($fname,$fpath,$fsuffix) = fileparse($list[$count - 1][0]);
if($base ne '/') {
$fpath =~ s/^\Q$base\E//g;
}
$actions = "$actions<a class='action-link' ".
"href='index.cgi?path=".&urlize($fpath)."' ".
"title='$text{'goto_folder'}'>$goto_icon</a>";
}
if (
index($type, "text-") != -1 or
exists($allowed_for_edit{$type})
) {
$actions = "$actions<a class='action-link' href='edit_file.cgi?file=".&urlize($link)."&path=".&urlize($path)."' title='$text{'edit'}' data-container='body'>$edit_icon</a>";
}
if (index($type, "zip") != -1 or index($type, "compressed") != -1) {
$actions = "$actions <a class='action-link' href='extract.cgi?path=".&urlize($path)."&file=".&urlize($link)."' title='$text{'extract_archive'}' data-container='body'>$extract_icon</a> ";
}
}
@row_data = (
"<a href='$href'><img src=\"$img\"></a>",
"<a href=\"$href\" data-filemin-path=\"$href\">$vlink</a>"
);
push @row_data, $type if($userconfig{'columns'} =~ /type/);
push @row_data, $actions;
push @row_data, $size if($userconfig{'columns'} =~ /size/);
push @row_data, $user.':'.$group if($userconfig{'columns'} =~ /owner_user/);
push @row_data, $permissions if($userconfig{'columns'} =~ /permissions/);
push @row_data, $mod_time if($userconfig{'columns'} =~ /last_mod_time/);
print &ui_checked_columns_row(\@row_data, "", "name", $link);
}
print ui_columns_end();
print &ui_hidden("path", $path),"\n";
print &ui_form_end();
}
sub init_datatables {
my ($a, $b, $c);
$a = '0, 1, 3';
$b = '4';
$c = '';
if ($userconfig{'columns'} =~ /type/) {
$a = '0, 1, 4';
$b = '5';
}
if ($userconfig{'columns'} =~ /size/) {
$c = '{ "type": "file-size", "targets": [' . $b . '] },';
}
if($userconfig{'disable_pagination'}) {
$bPaginate = 'false';
} else {
$bPaginate = 'true';
}
print "<script>";
print "\$( document ).ready(function() {";
print "\$.fn.dataTableExt.sErrMode = 'throw';";
print "\$('#list_form > table').dataTable({";
print "\"order\": [],";
print "\"aaSorting\": [],";
print "\"bDestroy\": true,";
print "\"bPaginate\": $bPaginate,";
print " \"fnDrawCallback\": function(oSettings) {
if (oSettings.fnRecordsTotal() <= oSettings._iDisplayLength) {
\$('.dataTables_paginate').hide();
} else {
\$('.dataTables_paginate').show();
}
},";
print " \"initComplete\": function() {
\$('div.dataTables_filter input').val('').trigger('keyup');
\$('div.dataTables_filter input').focus();
\$(document).on('keydown', function (event) {
var keycode = event.keyCode ? event.keyCode : event.which;
if (!\$('input').is(':focus') && !\$('select').is(':focus') && !\$('textarea').is(':focus')) {
if (keycode === 39) {
\$('.paginate_button.next').trigger('click');
}
if (keycode === 37) {
\$('.paginate_button.previous').trigger('click');
}
}
});
},";
print "\"bInfo\": false,";
print "\"destroy\": true,";
print "\"oLanguage\": {";
print "\"sSearch\": \" \"";
print "},";
print "\"columnDefs\": [ { \"orderable\": false, \"targets\": [$a] }, $c ],";
print "\"bStateSave\": true,";
print "\"iDisplayLength\": 50,";
print "});";
print "\$(\"form\").on('click', 'div.popover', function() {";
print "\$(this).prev('input').popover('hide');";
print "});";
print "});";
print "</script>";
}
sub get_bookmarks {
$confdir = "$remote_user_info[7]/.filemin";
if(!-e "$confdir/.bookmarks") {
return "<li><a>$text{'no_bookmarks'}</a></li>";
}
my $bookmarks = &read_file_lines($confdir.'/.bookmarks', 1);
$result = '';
foreach $bookmark(@$bookmarks) {
$result.= "<li><a href='index.cgi?path=$bookmark'>".
&html_escape($bookmark)."</a><li>";
}
return $result;
}
# get_paste_buffer_file()
# Returns the location of the file for temporary copy/paste state
sub get_paste_buffer_file
{
if (&get_product_name() eq 'usermin') {
return $user_module_config_directory."/.buffer";
}
else {
my $tmpdir = "$remote_user_info[7]/.filemin";
&make_dir($tmpdir, 0700) if (!-d $tmpdir);
return $tmpdir."/.buffer";
}
}
1;