#!/usr/bin/perl
#
# Authentic Theme (https://github.com/authentic-theme/authentic-theme)
# Copyright Ilia Rostovtsev <ilia@virtualmin.com>
# Licensed under MIT (https://github.com/authentic-theme/authentic-theme/blob/master/LICENSE)
#
use strict;
our (%in, %text, %gconfig, %request_uri, %userconfig, @allowed_paths, @remote_user_info, $cwd, $path);
do($ENV{'THEME_ROOT'} . "/extensions/file-manager/file-manager-lib.pl");
kill_previous($0, $$);
my %data;
my @list;
my @items;
my $auto_orient = " -auto-orient";
my $width = int($in{'width'});
my $height = int($in{'height'});
my $file_requested = $in{'file_requested'};
my $files_all = $in{'files_all'};
my $files_selected = $in{'files_selected'};
my $search = $in{'query'};
# Use only current file or read list of files
if (!$files_all) {
@list = ($file_requested);
if ($files_selected) {
@list = split(/\0/, $in{'name'});
}
} else {
if ($search) {
@list = exec_search();
} else {
unless (opendir(DIR, $cwd)) {
print_error("$text{'theme_xhred_global_error'}: [tt]`$cwd`[/tt]- $!.");
exit;
}
@list = grep {$_ ne '.' && $_ ne '..'} readdir(DIR);
closedir(DIR);
}
my $page = 1;
my $pagelimit = 4294967295;
my $pages = 0;
my $max_allowed = int($userconfig{'max_allowed'});
if ($max_allowed !~ /^[0-9,.E]+$/ || $max_allowed < 100 || $max_allowed > 10000) {
$max_allowed = 1000;
}
my $totals = scalar(@list);
my $totals_spliced = $totals;
my $tuconfig_per_page = get_user_config('config_portable_module_filemanager_records_per_page');
if (server_pagination_enabled($totals, $max_allowed, $search)) {
$page = int($in{'page'}) || 1;
$pagelimit = int($in{'paginate'}) || int($tuconfig_per_page) || 30;
$pages = ceil(($totals) / $pagelimit);
if ($page > $pages) {
$page = $pages;
$in{'page'} = $page;
}
my $splice_start = $pagelimit * ($page - 1);
my $splice_end = $pagelimit;
@list = sort {$a cmp $b} @list;
@list = splice(@list, $splice_start, $splice_end);
$totals_spliced = scalar(@list);
}
}
# Leave only allowed
if (test_allowed_paths()) {
my @tmp_list;
for $path (@allowed_paths) {
my $slashed = $path;
$slashed .= "/" if ($slashed !~ /\/$/);
push @tmp_list,
grep {string_starts_with($slashed, "$cwd/$_/") || index($slashed, $_) != -1 || index("$cwd/$_", $slashed) != -1}
@list;
}
my %hash = map {$_, 1} @tmp_list;
@list = keys %hash;
}
my $index = 0;
my $index_requested = 0;
if (has_command('identify')) {
foreach my $filename (@list) {
my $file = simplify_path("$cwd/$filename");
my $type = mimetype($file);
my $files_size = -s $file;
my $file_encoded;
my $processed = 0;
my ($w, $h, $o) = (0, 0, undef);
if (string_starts_with($type, 'image')) {
if ($files_all || $files_selected || $file_requested eq $filename) {
my $data_auto = ($auto_orient ? '%w %h %[orientation]' : '%w %h');
my $data = `identify -ping -format '$data_auto' @{[quotemeta($file)]}`;
($w, $h, $o) = $data =~ /(?|(\d+)\s(\d+)\s(\w+)|(\d+)\s(\d+))/;
my $orientation = ($w > $h ? $w : $h);
my $factor = ($w > $h ? $width : $height);
my $types_excluded = (string_contains($type, 'svg') || string_contains($type, 'microsoft.icon'));
if ($w && $h) {
# Process image in case it's larger than 600kb or its dimensions larger than user's screen resolution
if (!$types_excluded && ($orientation > $factor || $files_size > 600000)) {
# Fix orientation sizes
if ($auto_orient && $o) {
if (string_starts_with($o, 'Left') || string_starts_with($o, 'Right')) {
my $w_ = $w;
my $h_ = $h;
$h = $w_;
$w = $h_;
}
}
# Extract smaller version of the file
my $file_out = "$file.bak~";
my $convert_size = (($w > $h ? undef : 'x') . ($orientation > $factor ? $factor : $orientation));
system(
"convert -quality 60% -resize $convert_size @{[quotemeta($file)]} $auto_orient @{[quotemeta($file_out)]}");
# Store smaller version data
$file_encoded = encode_base64(read_file_contents($file_out));
if ($orientation > $factor) {
$h = int($factor / ($w / $h));
$w = $factor;
}
# Remove temporary file
unlink_file($file_out);
$processed++;
} else {
$file_encoded = encode_base64(read_file_contents($file));
}
}
if ($file_requested eq $filename) {
$index_requested = $index;
}
}
if ($file_encoded) {
push(@items,
{ index => $index,
title => html_escape("$filename (@{[theme_nice_size_local($files_size, -1)]})"),
file => $filename,
cwd => $cwd,
src => ("data:$type;base64,$file_encoded"),
p => $processed,
w => int($w),
h => int($h),
});
$index++;
}
}
}
if (@items) {
$data{'items'} = \@items;
$data{'index_requested'} = $index_requested;
} else {
$data{'warning'} = $text{'theme_xhred_filemanager_preview_images_error'};
}
} else {
# Let user install ImageMagick in single click
$data{'error'} = $text{'theme_xhred_filemanager_preview_images_deps_error1'};
my $package_updates = "package-updates";
if (foreign_available($package_updates)) {
my $redir = "../$request_uri{'module'}";
my $pkgname = ($gconfig{'os_type'} =~ /debian/ ? 'imagemagick' : 'ImageMagick');
my %package_updates_lang = load_language($package_updates);
my $update_failed = html_escape($package_updates_lang{'update_failed'});
my $update_ok = html_escape(text('global_deps_installed', "<code>$pkgname</code>"));
my $update_error = html_escape(text('global_deps_error', "<kbd>$pkgname</kbd>"));
my $installing_text = html_escape(text('global_deps_installing', "<code>$pkgname</code>"));
my $install_link =
"../$package_updates/update.cgi?source=3&confirm=1&mode=new&u=$pkgname&redir=$redir&redirdesc=File%20Manager&xnavigation=1";
$data{'error'} .= " "
.
text('theme_xhred_filemanager_preview_images_deps_error2',
ui_link('javascript:;',
$text{'theme_xhred_global_click_here'},
'text-darker',
" nref onclick='fm_install_deps(\"$install_link\", [\"$update_failed\", \"$update_ok\", \"$update_error\", \"$installing_text\"], this)'"
));
}
}
print_json([\%data]);