#!/usr/bin/perl
#
# filechucker.cgi
#
######################################################################
#
# DO NOT EDIT THIS FILE unless absolutely necessary; in most cases you
# should be editing filechucker_prefs.cgi instead. If you do edit
# this file, be sure to make a backup copy first.
#
######################################################################
#
# This program is the copyrighted work of Encodable Industries.
# Redistribution is prohibited, and copies are permitted only for
# backup purposes. You are free to modify the program for your
# own use, but you may not distribute any modified copies of it.
#
# Use of this program requires a one-time license fee. You can
# obtain a license here:
#
# http://encodable.com/filechucker/#download
#
# This software comes with no warranty. It is our hope that you
# find it useful, but it comes with no guarantees. Under no
# circumstances shall Encodable Industries be held liable in any
# situation arising from your use of this program.
#
# For more information about this program, as well as for help
# and support, please visit the following pages:
#
# Homepage: http://encodable.com/filechucker/
# Contact: http://encodable.com/contact/
my $version = "4.86";
use CGI::Carp 'fatalsToBrowser';
$ENV{PATH} = '/bin:/usr/bin:/usr/local/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
($ENV{DOCUMENT_ROOT}) = ($ENV{DOCUMENT_ROOT} =~ /(.*)/); # untaint.
#$ENV{DOCUMENT_ROOT} = 'c:\some\dir'; # If autodetection fails, uncomment & set this.
#$ENV{SCRIPT_NAME} = '/cgi-bin/filechucker.cgi'; # If autodetection fails, uncomment & set this.
use lib './perlmodules';
use lib '../cgi-bin/perlmodules';
use lib '../../cgi-bin/perlmodules';
use lib "$ENV{DOCUMENT_ROOT}/cgi-bin/perlmodules";
use lib "$ENV{DOCUMENT_ROOT}/../cgi-bin/perlmodules";
my (%PREF,%TEXT,%COOKIE) = ();
#use Time::HiRes 'gettimeofday'; $PREF{script_start_time_highres} = gettimeofday();
my $debuglog = undef;
$| = 1;
use strict;
#use warnings;
use Fcntl;
use POSIX;
use File::Copy;
use Digest::MD5 'md5_hex';
sub printd;
sub die_nice;
sub enc_warn;
sub encdebug;
sub encdebuglog;
sub exit_with_error;
# Set globals. TODO: some of these need to be re-scoped.
my ($qs, $starttime, $total_upload_size, %temp, $num_files_in_progress_or_done, $total_file_count, $shortdatetime, $shortdatetime_forfilename, $datestring8) = ();
sub print_new_upload_form()
{
exit_with_access_denied('upload') unless user_is_allowed_to('upload');
$PREF{userdir} = $PREF{enable_userdirs} = '' if $PREF{enforce_userdir_restrictions_on_upload_page} =~ /no/i;
my $juststatus = $qs =~ /(?:^|&)juststatus(?:&|$)/ ? 1 : 0;
my $hiddenstyle = qq`style="position: absolute; left: -10000px; overflow: hidden; height: 0;"`;
$PREF{on_page} = $juststatus ? 'popupstatus' : 'uploader';
print_http_headers();
print_new_upload_form___firsthalf( $juststatus,$hiddenstyle) unless $qs =~ /output=secondhalf/;
print_new_upload_form___secondhalf($juststatus,$hiddenstyle) unless $qs =~ /output=firsthalf/;
}
sub print_new_upload_form___firsthalf
{
my ($juststatus,$hiddenstyle) = @_;
my @dirs = get_all_writable_directories();
exit_with_access_denied() unless @dirs;
start_html_output($PREF{subtitle___uploader});
my $numitems = $total_file_count;
$numitems = 1 if $numitems > $PREF{max_files_allowed};
$numitems = $PREF{num_custom_file_elements} if $PREF{using_custom_file_elements} =~ /yes/i;
if($PREF{in_reprocessing_mode})
{
$numitems = 0;
my @qsitems = split(/&/, $qs);
foreach my $item (@qsitems)
{
if($item =~ /^ffs\d+=file-(.+)/)
{
my $filename = $1;
enc_urldecode($filename);
$numitems++;
$PREF{reprocessing_file_names}{$numitems} = $filename;
}
}
}
# The onsubmit() in this
`;
print $juststatus
? qq`$PREF{progress_bar_placeholder_message__popup}
`
: qq`$PREF{progress_bar_placeholder_message}
`
;
my $chosen_filenames_element = qq`
` if $PREF{show_chosen_filenames_during_upload} =~ /yes/i;
print qq`
$chosen_filenames_element
? $PREF{KB}/s
$TEXT{Connecting_please_wait_}
? %
` . ($PREF{show_progress_table_during_uploads} =~ /yes/i ? qq`
$total_file_count ? ??:??:??
0 0 00:00:00
$total_file_count ? ??:??:??
` : undef) . qq`
$PREF{cancelbutton}
`;
print qq`\n` if $PREF{use_iframe_for_upload} =~ /yes/i;
print qq`\n`;
print qq`
\n` if $PREF{debug};
print qq`
\n` if $PREF{clear_page_during_upload} =~ /yes/i;
print qq`
\n` if $PREF{show_progress_table_during_uploads} =~ /yes/i;
print qq`
\n` if $juststatus;
print qq`
\n` if $PREF{upload_progress_bar_disabled} =~ /yes/i;
print qq`\n` if $PREF{show_upload_status_in_popup_window} =~ /yes/i;
print qq`
\n` if $PREF{human_test_is_invisible} =~ /yes/i;
print qq`
\n` if $PREF{only_allow_one_subdir_dropdown_per_upload} =~ /yes/i;
print qq`
\n` if $PREF{only_allow_one_new_subdir_per_upload} =~ /yes/i;
print qq`
\n` if $PREF{use_iframe_for_upload} =~ /yes/i;
delete_old_files();
finish_html_output();
}
sub hook
{
my ($current_filename, $buffer, $bytes_read, $logfh) = @_;
my $current_file_has_been_logged = 0;
my ($progress,$currentfile,$totalfiles,$totalsize,$start_time) = ();
my $serial = $PREF{serial};
my @logcontents = ();
# We're still the original process that's accepting the upload, so
# we don't need to ask the backend for this now, we can store it
# in a hash for easier retrieval:
#
$progress = $PREF{uploaddata}{$serial}{progress};
$currentfile = $PREF{uploaddata}{$serial}{currentfile};
$totalfiles = $PREF{uploaddata}{$serial}{totalfiles};
$totalsize = $PREF{uploaddata}{$serial}{totalsize};
$start_time = $PREF{uploaddata}{$serial}{start_time};
# There are three possibilities here:
#
# 1. $current_filename has already been logged (i.e. it's in @allfiles)
# and its size has either gone up, or stayed the same;
#
# 2. $current_filename is in @allfiles but its size appears to have gone
# down, meaning the user has uploaded two files that have the same
# filename, so we'll handle this with if(!$current_file_has_been_logged);
#
# 3. $current_filename is NOT in @allfiles, which we'll also handle with
# if(!$current_filename_has_been_logged).
my $new_progress = ();
my (@allfiles) = split(m!///!, $progress);
for(@allfiles)
{
if(/(.+)=(\d+)$/)
{
my ($file,$old_progress) = ($1,$2);
if($file eq $current_filename && $bytes_read >= $old_progress)
{
$new_progress .= "${current_filename}=${bytes_read}";
$current_file_has_been_logged = 1;
}
else
{
$new_progress .= "${file}=${old_progress}";
}
$new_progress .= "///";
}
}
if(!$current_file_has_been_logged)
{
unless(!$current_filename || $bytes_read !~ /^\d+$/)
{
$new_progress .= "${current_filename}=${bytes_read}";
$num_files_in_progress_or_done++;
}
}
# Update our hash for the next time hook() is called. We'll still update
# the backend below, so the client can get the info too.
#
$PREF{uploaddata}{$serial}{progress} = $new_progress;
$PREF{uploaddata}{$serial}{currentfile} = $num_files_in_progress_or_done;
$PREF{uploaddata}{$serial}{totalfiles} = $total_file_count;
$PREF{uploaddata}{$serial}{totalsize} = $total_upload_size;
$PREF{uploaddata}{$serial}{start_time} = $starttime;
if($PREF{use_database_for_temp_data} =~ /yes/i)
{
sql_untaint($new_progress, $num_files_in_progress_or_done, $total_file_count, $total_upload_size, $starttime, $PREF{serial});
my $sth = $PREF{dbh}->prepare("UPDATE $PREF{table_name_for_temp_data} SET progress='$new_progress', currentfile='$num_files_in_progress_or_done', totalfiles='$total_file_count', totalsize='$total_upload_size', start_time='$starttime' WHERE serial='$PREF{serial}';");
$sth->execute or die "$0: $DBI::errstr\n";
}
else
{
seek $logfh, 0, 0; # seek to the beginning again, before we start writing.
my $logline = "${new_progress}:|:${num_files_in_progress_or_done}:|:${total_file_count}:|:${total_upload_size}:|:${starttime}:|:ppd_false";
print $logfh "$logline\n"; # print the static info
truncate $logfh, tell $logfh; # truncate the file (on the off chance that the new size is less than the old)
flock $logfh, 8; # release the lock
if(0)
{
# this has promise, but still doesn't seem to work around write-caching nonsense.
do_alt_progbar_logging_stage1($serial, $logline) if !$PREF{num_hook_calls} || time() =~ /[02468]$/;
}
}
$PREF{num_hook_calls}++;
}
sub do_alt_progbar_logging_stage1($$)
{
my ($serial, $logline) = @_;
enc_urlencode($logline);
my $url = "$PREF{protoprefix}$ENV{HTTP_HOST}$ENV{SCRIPT_NAME}?action=altprogbarlog&serial=$serial&logline=$logline";
print STDERR "$$: about to call lynx for url: $url\n";
`lynx -dump '$url'`;
# TODO: if/when we get this working (currently it's still defeated by those
# idiotic write-caching servers), we might want to do a module-based request
# rather than an external call to lynx, etc. But until then, keep this
# commented so as not to pull in that extra code needlessly.
#use LWP::Simple qw(!head);
#my $content = get $url; # that's LWP::Simple's get() function.
}
sub do_alt_progbar_logging_stage2()
{
my ($serial) = get_qs_var('serial');
my ($logline) = get_qs_var('logline');
return if length($logline) > $PREF{max_logline_length_for_alt_progbar_logging}; # security precaution.
print STDERR "$$: about to do altprogbarlogging stage2 for logline: $logline\n";
my $altlogfile = get_progbar_log_alt_filename($serial);
open(my $outfh, ">$altlogfile") or die_nice qq`Couldn't open altlog '$altlogfile' for writing: $!`;
flock $outfh, 2;
seek $outfh, 0, 0;
print $outfh "$logline\n";
truncate $outfh, tell $outfh; # unlikely but just in case.
close $outfh or die_nice qq`Couldn't close altlog '$altlogfile' after writing: $!`;
print_http_headers();
exit;
}
sub get_progbar_log_filename($)
{
my $serial = shift; return "$PREF{datadir}/$serial.fctemp.log";
}
sub get_progbar_log_alt_filename($)
{
my $serial = shift; return "$PREF{datadir}/$serial.fctemp.altlog";
}
sub ajax_get_progress
{
print_xml_headers();
my $output = '';
my ($serial) = ($qs =~ /(?:^|&)serial=([0-9a-zA-Z]+)(?:&|$)/);
if(!$serial)
{
$output = "ERROR: the URL is missing its serial number (serial=NNNNNN...).";
}
else
{
my $fcvar = get_progress_and_size($serial);
if($$fcvar{progress} eq 'ENOLOG')
{
#$output = qq`ERROR: the log file hasn't been created yet. Your server is probably doing some write-caching so the log doesn't get created when we create it; instead, it actually gets created AFTER the upload is complete, making progress reporting impossible. Your upload is most likely proceeding normally, though, just without the progress bar. See this FAQ item for details.`;
$output = qq`Warning: your upload is most likely proceeding normally, but the progress bar can't be displayed due to a server issue. See this FAQ item for details.`;
}
elsif($$fcvar{progress} eq 'ENORAWPOST')
{
# TODO: on servers with ancient versions of Perl (i.e. where ENORAWPOST can happen), when using the popup status window, how do we know when to close the window?
$output = qq`ERROR: the rawpost file hasn't been created yet. Your server is probably doing some write-caching so the file doesn't get created when we create it; instead, it actually gets created AFTER the upload is complete, making progress reporting impossible. Your upload is most likely proceeding normally, though, just without the progress bar. See this FAQ item for details.`;
}
else
{
if($$fcvar{total_size} > $CGI::POST_MAX) { $$fcvar{size_error} = 'toobig'; $$fcvar{size_limit} = $CGI::POST_MAX; }
if($$fcvar{total_file_count} > $PREF{max_files_allowed}){ $$fcvar{count_error} = 'toomany'; $$fcvar{count_limit} = $PREF{max_files_allowed}; }
if(data_exceeds_global_quota($$fcvar{total_size})) { $$fcvar{size_error} = 'globalquotaexceeded'; $$fcvar{size_limit} = $PREF{quota_for_entire_upload_directory}; }
if(data_exceeds_user_quota($$fcvar{total_size})) { $$fcvar{size_error} = 'userquotaexceeded'; $$fcvar{size_limit} = $PREF{quota_for_member_userdirs}; }
foreach my $var (sort keys %$fcvar)
{
$output .= "$var=$$fcvar{$var}|:|:|";
}
}
}
#print qq`\n\n`;
print qq`\n\n`;
print $output;
print qq` \n \n`;
}
sub get_progress_and_size
{
printd(qq`starting get_progress_and_size()\n`);
unless(user_is_allowed_to('upload')) { exit_with_access_denied('upload'); }
my $serial = shift;
$serial = enc_untaint($serial);
my ($progress,$currentfile,$totalfiles,$totalprogress,$totalsize,$start_time,$elapsedtime,$ppd_status) = ('','','','','','','','');
if($PREF{using_upload_hook} =~ /yes/i)
{
if($PREF{use_database_for_temp_data} =~ /yes/i)
{
sql_untaint($serial);
my $sth = $PREF{dbh}->prepare("SELECT progress,currentfile,totalfiles,totalsize,start_time FROM $PREF{table_name_for_temp_data} WHERE serial='$serial';");
$sth->execute;
($progress,$currentfile,$totalfiles,$totalsize,$start_time) = $sth->fetchrow;
}
else
{
my $reglog = get_progbar_log_filename($serial);
my $altlog = get_progbar_log_alt_filename($serial);
my $logfile = -e $reglog ? $reglog : -e $altlog ? $altlog : undef;
#my $logfile = -e $altlog ? $altlog : undef;
if($logfile)
{
open(READLOGFILE,"<$logfile") or die "$0: couldn't open $logfile for reading: $!\n";
flock READLOGFILE, 1;
seek READLOGFILE, 0, 0;
my $line = ;
chomp $line;
close READLOGFILE or die "$0: couldn't close $logfile after reading: $!\n";
($progress,$currentfile,$totalfiles,$totalsize,$start_time,$ppd_status) = split(/:\|:/, $line);
}
else
{
$totalprogress = 'ENOLOG';
}
}
unless($totalprogress eq 'ENOLOG')
{
my (@allfiles) = split(m!///!, $progress);
for(@allfiles)
{
my ($file,$progress) = (/(.+)=(\d+)$/);
$progress = 0 unless $progress;
$totalprogress += $progress;
}
$elapsedtime = offsettime() - $start_time;
}
}
else
{
# If we're not using the upload hook from CGI.pm, then we can't detect
# the file boundaries within the raw post data, which means we can't
# display the info for files total/completed/remaining. So we just
# need the totalsize, already-uploaded-size, and starttime/elapsedtime
# here.
if($PREF{use_database_for_temp_data} =~ /yes/i)
{
sql_untaint($serial);
my $sth = $PREF{dbh}->prepare("SELECT progress,currentfile,totalfiles,totalsize,start_time FROM $PREF{table_name_for_temp_data} WHERE serial='$serial';");
$sth->execute;
($progress,$currentfile,$totalfiles,$totalsize,$start_time) = $sth->fetchrow;
($totalprogress) = ($progress =~ /.+=(\d+)/);
}
else
{
opendir(GETPROGRESSDIRFH, $PREF{datadir}) or die "$0: couldn't read directory $PREF{datadir}: $!\n";
my $dirh = \*GETPROGRESSDIRFH; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
my (@rawposts) = grep { /^$serial\.CL_\d+\.ST_\d+\.rawpost$/ } readdir($dirh);
closedir $dirh or enc_warn "$0: couldn't close directory $PREF{datadir}: $!\n"; #FIXME: why doesn't this close properly?
my $rawpost = $rawposts[0];
if(-e "$PREF{datadir}/$rawpost")
{
($totalsize,$start_time) = ($rawpost =~ /^$serial\.CL_(\d+)\.ST_(\d+)\.rawpost$/);
$totalprogress = -s "$PREF{datadir}/$rawpost";
}
else
{
$totalprogress = 'ENORAWPOST';
}
}
$elapsedtime = offsettime() - $start_time;
($currentfile,$totalfiles) = (1,1);
}
my %fcvar = (
progress => $totalprogress,
total_size => $totalsize,
elapsed_time => $elapsedtime,
finished_file_count => $currentfile ? $currentfile - 1 : 0,
total_file_count => $totalfiles,
ppd_status => $ppd_status eq 'ppd_true' ? 1 : 0,
);
return \%fcvar;
}
sub tainted
{
return ! eval { eval("#" . substr(join("", @_), 0, 0)); 1 };
}
sub data_exceeds_global_quota
{
my $datasize = shift;
if($PREF{quota_for_entire_upload_directory} =~ /^\d+$/ && $PREF{quota_for_entire_upload_directory} > 0)
{
if( ($datasize + get_dir_size($PREF{uploaded_files_realpath})) > $PREF{quota_for_entire_upload_directory} )
{
return 1;
}
}
return 0;
}
sub data_exceeds_user_quota
{
my $datasize = shift;
if($PREF{quota_for_member_userdirs} =~ /^\d+$/ && $PREF{quota_for_member_userdirs} > 0 && $PREF{userdir} && !$PREF{admin_is_logged_in})
{
if( ($datasize + get_dir_size("$PREF{uploaded_files_realpath}/$PREF{userdir_folder_name}/$PREF{userdir}")) > $PREF{quota_for_member_userdirs} )
{
return 1;
}
}
return 0;
}
sub get_special_upload_note
{
my $note = '';
if($PREF{in_replace_mode})
{
$note .= "Note: in Replace Mode. Any file that you upload must have the exact same name as one of these files on the server: ";
my @qsitems = split(/&/, $qs);
foreach my $item (@qsitems)
{
if($item =~ /^rfn\d+=file-(.+)/)
{
my $filename = $1;
enc_urldecode($filename);
$PREF{replacement_file_names}{$filename} = 1;
$note .= " $1";
}
}
}
if($PREF{in_reprocessing_mode})
{
$note .= "Note: in Reprocessing Mode. Using your selected files from the server instead of uploading new files. ";
}
if($PREF{in_addfile_mode})
{
$note .= "Note: in AddFile Mode. Upload your new file(s) to existing sets. ";
}
if($note)
{
$note = qq`$note
`;
}
return $note;
}
sub process_upload()
{
## Debug: show the raw POST data and then exit:
#my $input = ''; $input .= $_ for ();
#print "Content-type: text/plain\n\n";
#print $input;
#exit;
printd( qq`010: starting process_upload()` );
unless(user_is_allowed_to('upload')) { exit_with_access_denied('upload'); }
$PREF{userdir} = $PREF{enable_userdirs} = '' if $PREF{enforce_userdir_restrictions_on_upload_page} =~ /no/i;
if($PREF{urls_allowed_to_post_to_us_01})
{
my $url_allowed = 0;
foreach my $pref (sort keys %PREF)
{
if($pref =~ /urls_allowed_to_post_to_us_\d+$/)
{
$url_allowed = 1 if $ENV{HTTP_REFERER} =~ m!^$PREF{$pref}!i;
}
}
die_nice("Error: posting from a non-allowed URL.") unless $url_allowed;
}
die_nice(qq`Error: you didn't pass the upload serial number (serial=NNNNNN...) on the URL.\n`) unless $PREF{serial};
$PREF{serial} = enc_untaint($PREF{serial});
my $serial = $PREF{serial};
$total_upload_size = $ENV{CONTENT_LENGTH};
my ($logfile,$logfh) = ();
# We'll use this hash in the main/parent/original-getting-POSTed-to process,
# so we never need to read from the backend, only write to it.
#
$PREF{uploaddata}{$serial}{progress} = 0;
$PREF{uploaddata}{$serial}{currentfile} = $num_files_in_progress_or_done;
$PREF{uploaddata}{$serial}{totalfiles} = $total_file_count;
$PREF{uploaddata}{$serial}{totalsize} = $total_upload_size;
$PREF{uploaddata}{$serial}{start_time} = $starttime;
if($PREF{use_database_for_temp_data} =~ /yes/i)
{
sql_untaint($PREF{serial}, $num_files_in_progress_or_done, $total_file_count, $total_upload_size, $starttime);
my $sth = $PREF{dbh}->prepare("INSERT INTO $PREF{table_name_for_temp_data} (serial,progress,currentfile,totalfiles,totalsize,start_time) VALUES('$PREF{serial}', '0', '$num_files_in_progress_or_done', '$total_file_count', '$total_upload_size', '$starttime');");
$sth->execute or die "$0: $DBI::errstr\n";
}
else
{
$logfile = "$PREF{datadir}/$PREF{serial}.fctemp.log";
printd( qq`011: about to sysopen() logfile $logfile` );
unlink($logfile) if -e $logfile; # in case the user has hit their "Back" button after a failed upload, leaving the log behind.
sysopen(LOGFHFORTEMPDATA, $logfile, O_RDWR | O_EXCL | O_CREAT) or die "$0: couldn't create logfile $logfile for R/W: $!\n";
$logfh = \*LOGFHFORTEMPDATA; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
# RDWR=R/W, EXCL=die if already exists, CREAT=create if DNE.
select((select($logfh), $| = 1)[0]);
flock $logfh, 2;
close $logfh or die "$0: couldn't write new (empty) file $logfile to disk: $!\n";
sysopen(LOGFHFORTEMPDATA, $logfile, O_RDWR) or die "$0: couldn't open $logfile for R/W: $!\n";
$logfh = \*LOGFHFORTEMPDATA; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
select((select($logfh), $| = 1)[0]);
flock $logfh, 2;
seek $logfh, 0, 0;
my $firstline = "0:|:${num_files_in_progress_or_done}:|:${total_file_count}:|:${total_upload_size}:|:${starttime}:|:ppd_false";
print $logfh $firstline;
truncate $logfh, tell $logfh; # unlikely but just in case.
flock $logfh, 8;
printd( qq`015: wrote first line to logfile` );
printd( qq`016: firstline: $firstline` );
printd( qq`017: unlocked logfile` );
}
if($ENV{CONTENT_LENGTH} > $CGI::POST_MAX)
{
print "Content-type: text/plain\n\n";
print "Error: your upload was too big.\nYou tried to upload " . format_filesize_nicely($ENV{CONTENT_LENGTH}) . ",\nbut the current limit is " . format_filesize_nicely($CGI::POST_MAX) . ".\nPlease go back and choose a smaller file.\n";
exit;
# TODO: why does printing the error as above work properly, while
# calling exit_with_error() causes the script to hang?
#
#exit_with_error("Error: your upload was too big.\nYou tried to upload " . format_filesize_nicely($ENV{CONTENT_LENGTH}) . ",\nbut the current limit is " . format_filesize_nicely($CGI::POST_MAX) . ".\nPlease go back and choose a smaller file.\n");
}
if(data_exceeds_global_quota($ENV{CONTENT_LENGTH})) { enc_redirect("$PREF{here_error}?error=globalquotaexceeded&size=$ENV{CONTENT_LENGTH}&limit=$PREF{quota_for_entire_upload_directory}$PREF{default_url_vars}"); }
if(data_exceeds_user_quota($ENV{CONTENT_LENGTH})) { enc_redirect("$PREF{here_error}?error=userquotaexceeded&size=$ENV{CONTENT_LENGTH}&limit=$PREF{quota_for_member_userdirs}}$PREF{default_url_vars}"); }
my ($query,$rawpost) = ();
if($PREF{using_upload_hook} =~ /yes/i)
{
$query = CGI->new(\&hook,$logfh);
}
else
{
# Receive the upload data manually and save it to a temporary file,
# rather than using "my $query = CGI->new(\&hook,$logfh);" , so
# that we can function on servers whose CGI.pm is too old to support
# the upload hook functionality. We'll still use CGI.pm to parse
# the post-data afterwards.
#
$rawpost = "$PREF{datadir}/$PREF{serial}.CL_${total_upload_size}.ST_" . (offsettime()) . ".rawpost";
$rawpost = enc_untaint($rawpost,'keep_path');
unlink($rawpost) if -e $rawpost; # in case the user has hit their "Back" button after a failed upload, leaving the rawpost behind.
sysopen(UPLOADRAWDATAFH, $rawpost, O_RDWR | O_EXCL | O_CREAT) or die "$0: couldn't create $rawpost for R/W: $!\n";
my $upfh = \*UPLOADRAWDATAFH; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
flock $upfh, 2;
close $upfh or die "$0: couldn't write new (empty) file $rawpost to disk: $!\n";
sysopen(UPLOADRAWDATAFH, $rawpost, O_RDWR) or die "$0: couldn't open $rawpost for R/W: $!\n";
$upfh = \*UPLOADRAWDATAFH; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
flock $upfh, 2;
seek $upfh, 0, 0;
select((select($upfh), $| = 1)[0]);
my ($bytes_uploaded_so_far, $chunk) = (0, '');
while( ($bytes_uploaded_so_far < $total_upload_size)
&&
($bytes_uploaded_so_far += read(STDIN, $chunk, 8192))
)
{
select(undef, undef, undef, $PREF{sleep_time_during_nonhook_uploads}); # sleep for a few ms (see "perldoc -f select")
print $upfh $chunk;
# We don't use the logfile at all in nonhook mode, so this call is unnecessary.
# TODO: maybe we should, then we wouldn't need to check for using_upload_hook
# in the get_progress_and_size() sub? And then the ENORAWPOST+popup-status
# issue would be resolved?
#hook('dummy_filename_for_nonhook_version.foo', undef, $bytes_uploaded_so_far, $logfh);
}
truncate $upfh, tell $upfh;
close $upfh or die "$0: couldn't write post-data to file $rawpost: $!\n";
# Re-open it on STDIN so that CGI.pm can process it.
open(STDIN,"<$rawpost") or die "$0: couldn't open post-data file $rawpost on STDIN: $!\n";
flock STDIN, 1;
seek STDIN, 0, 0;
$query = new CGI();
}
if($logfh)
{
flock $logfh, 2;
seek $logfh, 0, 0;
print $logfh "$PREF{uploaddata}{$serial}{progress}:|:$PREF{uploaddata}{$serial}{currentfile}:|:$PREF{uploaddata}{$serial}{totalfiles}:|:$PREF{uploaddata}{$serial}{totalsize}:|:$PREF{uploaddata}{$serial}{start_time}:|:ppd_true";
truncate $logfh, tell $logfh; # unlikely but just in case.
flock $logfh, 8;
}
$PREF{uploaddata}{$serial}{end_time} = offsettime();
# For hosts like GoDaddy that drop MySQL connections every 10 seconds:
get_db_connection('force') if (database_required() && $PREF{reconnect_to_db_after_upload} =~ /yes/i);
if($PREF{enable_human_test} =~ /yes/i && image_humantest_possible())
{
my $passed_test = do_human_test(param("fcht1"), param("fcht2"));
die_nice($TEXT{Error__failed_human_test__please_try_again_}) unless $passed_test;
}
if($PREF{enable_upload_counter_number} =~ /yes/i)
{
my $cfile = $PREF{datadir} . '/' . '_fc_counter_value.txt';
create_file_if_DNE($cfile,$PREF{writable_file_perms});
open(CFILE,"+<$cfile") or die_nice("$PREF{internal_appname}: process_upload(): could not open file '$cfile' for R/W: $!\n");
flock CFILE, 2;
seek CFILE, 0, 0;
$PREF{upload_counter_value} = ;
chomp $PREF{upload_counter_value};
unless($PREF{upload_counter_value} =~ /^\d+$/)
{
enc_warn "$PREF{internal_appname}: process_upload(): invalid counter value '$PREF{upload_counter_value}'; using 1 instead.\n";
$PREF{upload_counter_value} = 1;
}
seek CFILE, 0, 0;
print CFILE ($PREF{upload_counter_value} + 1) . "\n";
truncate CFILE, tell CFILE;
close CFILE or die_nice("$PREF{internal_appname}: process_upload(): could not close file '$cfile' after R/W: $!\n");
if($PREF{pad_with_zeros_to_this_length} =~ /^\d+$/ && $PREF{pad_with_zeros_to_this_length} > 0)
{
while($PREF{upload_counter_value} !~ /^\d{$PREF{pad_with_zeros_to_this_length}}$/)
{
$PREF{upload_counter_value} = '0' . $PREF{upload_counter_value};
}
}
}
my (%output, %textboxes, %files_left_blank_by_user, %cookies_to_set, $at_least_one_file_successfully_uploaded, %upload_info, $some_files_were_blocked, $textbox_values_for_qs) = (); my $numitems = $query->param('numitems'); my $f = $ENV{chr(72).chr(84).chr(84).chr(80)."_".chr(72).chr(79).chr(83).chr(84)}; $f =~ s/^w{3}\.//i; $f =~ s/:\d+$//i; $f =~ s/^(?:[^\.]+\.)+([^\.]+\.[^\.]+)$/$1/; if(uc(($f =~ /\.(\w+)$/)[0]) ne chr(76).chr(79).chr(67).chr(65).chr(76) && $f =~ /^([a-zA-Z0-9]).*([a-zA-Z0-9])\.([a-zA-Z]).*([a-zA-Z])$/) { unless((ord($1)==115&&ord($2)==107&&ord($3)==99&&ord($4)==109)) { print "Content-type: text/html\n\n"; print chr(93)."\n"; exit; } }
printd( qq`030: numitems=$numitems` );
my $i = 1;
foreach my $formfield (get_textbox_pref_keys('top', 'bottom'))
{
next if $PREF{"${formfield}_is_group_master"} =~ /yes/i;
my $shortname = $PREF{"${formfield}_shortname"};
my $formfield_value = $query->param($shortname);
#enc_warn qq`Raw formfield value straight from param(): $shortname='$formfield_value'\n`;
#use Encode;
#my $decoded_value = Encode::decode("UTF-8",$formfield_value);
#enc_warn qq`Decoded formfield value: $shortname='$decoded_value'\n`;
next if $PREF{"${formfield}_skip_if_null"} =~ /yes/i && !$formfield_value;
# Checkbox processing:
#
if($PREF{"${formfield}_group"}) # the groups feature here is intended for formfields that are checkboxes.
{
# since we're aggregating all members of this group into a single string,
# we want the value to be null (not "off" etc) if the box is unchecked.
#
#$formfield_value = $query->param($PREF{$formfield}) =~ /on/i ? $PREF{$formfield} : '';
$formfield_value = $formfield_value =~ /on/i ? $PREF{$formfield} : '';
my $groupname = $PREF{"${formfield}_group"};
$formfield = "formfield_${groupname}";
}
elsif($PREF{"${formfield}_checkbox"} =~ /yes/i && $PREF{"${formfield}_binary"} =~ /yes/i)
{
$formfield_value = $formfield_value =~ /on/i ? 1 : 0;
}
elsif($PREF{"${formfield}_checkbox"} =~ /yes/i && $PREF{"${formfield}_raw"} !~ /yes/i)
{
$formfield_value = $formfield_value =~ /on/i ? $TEXT{checkbox_yes} : $TEXT{checkbox_no};
}
$formfield_value = $PREF{"${formfield}_transform_${formfield_value}"} if exists $PREF{"${formfield}_transform_${formfield_value}"};
$formfield_value = $PREF{upload_counter_value} if $PREF{enable_upload_counter_number} =~ /yes/i && $PREF{"${formfield}_iscounter"} =~ /yes/i;
$textboxes{$formfield}{multiline} = $PREF{"${formfield}_multiline"} =~ /yes/i ? 1 : 0;
$textboxes{$formfield}{name} = $PREF{$formfield} ? $PREF{$formfield} : $shortname;
if($textboxes{$formfield}{value}) { $textboxes{$formfield}{value} .= $formfield_value ? $PREF{"${formfield}_group_separator"} . $formfield_value : ''; }
else { $textboxes{$formfield}{value} = $formfield_value; }
clean_up_text($textboxes{$formfield}{value}) if $PREF{"${formfield}_clean"} =~ /yes/i;
$textboxes{$formfield}{value} =~ s/\r\n/\n/g;
if( $PREF{"${formfield}_email"} =~ /yes/i )
{
my $j = 1;
for( split(/[,\s]+/, $formfield_value) )
{
if($PREF{email_notifications_to_userEntered_addresses} =~ /yes/i && $PREF{"${formfield}_dont_send_email"} !~ /yes/i)
{
$PREF{"${formfield}_emailtemplate"} =~ /(\w+)/ ? $PREF{"email_notification_recipient_fromtextbox_${1}template_${i}_${j}"} = $_ : $PREF{"email_notification_recipient_fromtextbox_${i}_${j}"} = $_;
}
if($j == 1)
{
$PREF{first_user_entered_email_address} = $_ unless $PREF{first_user_entered_email_address};
}
$j++;
}
}
if( $PREF{"${formfield}_save"} =~ /yes/i )
{
$cookies_to_set{$shortname} = $formfield_value;
}
$textboxes{_by_shortname}{$shortname} = $textboxes{$formfield}{value};
$i++;
}
#print "Content-type: text/plain\n\n";
my %uploadedfiles = ();
my $num_files_really_sent = 0;
my $num_file_elements = param('numfileelements');
for(my $h=1; $h<=$num_file_elements; $h++)
{
my $filename = $query->param("$PREF{filefield_namebase}$h");
if(!$filename)
{
$files_left_blank_by_user{$h} = 1;
next;
}
foreach my $tmpfile ($query->upload("$PREF{filefield_namebase}$h")) # what upload() returns is apparently both a handle and a filename?
{
$num_files_really_sent++;
#print "filename from query->upload($PREF{filefield_namebase}$h): $tmpfile\n";
$uploadedfiles{$num_files_really_sent}{param} = $query->param("$PREF{filefield_namebase}$h");
$uploadedfiles{$num_files_really_sent}{handle} = $tmpfile;
$uploadedfiles{$num_files_really_sent}{filename} = $tmpfile;
$uploadedfiles{$num_files_really_sent}{file_subgroup_num} = $h;
}
}
$numitems = $PREF{uploaddata}{$serial}{totalfiles} = $num_files_really_sent;
if($num_files_really_sent > $PREF{max_files_allowed})
{
# For small quick uploads, the AJAX never has a chance to catch & report
# this error, so we need to check for it here on the backend, too.
$TEXT{upload_too_many_files_error} =~ s!%%upload_count%%!$num_files_really_sent!g;
$TEXT{upload_too_many_files_error} =~ s!%%limit%%!$PREF{max_files_allowed}!g;
exit_with_error($TEXT{upload_too_many_files_error});
}
exit_with_error(qq`No files included in upload.`) if $PREF{allow_form_submissions_without_files} eq 'no' && $num_files_really_sent == 0; # for spambots who POST directly to the script.
my $recipient_i = 0;
# $num_file_elements is the total number of s,
# whereas numitems is the number of file elements that the user
# actually filled in.
#
#my $num_file_elements = param('numfileelements');
$i = 0; # no "my" because we used $i above.
#for(my $h=1; $h<=$num_file_elements; $h++)
foreach my $g (sort { $a <=> $b } keys %uploadedfiles)
{
my $h = $uploadedfiles{$g}{file_subgroup_num};
#my $filename = $query->param("$PREF{filefield_namebase}$h");
my $filename = $uploadedfiles{$g}{filename};
$i++;
my $rawname = $filename;
$rawname =~ s!.*[/\\](.+)!$1!; # remove any path info that's sometimes present (on IE/Windows uploads only?)
my $extension = ($filename =~ /.*\.(.+)/)[0] || ''; # the $extension variable doesn't contain a dot.
printd( qq`040: file $i of $numitems: $filename` );
#print STDERR "020: filename=$filename\n";
$filename = enc_untaint($filename);
#print STDERR "025: filename=$filename\n";
unless($PREF{in_reprocessing_mode}) # if we're using files from the server, then we can't block them; they're already there, and must be OK.
{
if(filename_is_illegal($filename))
{
$output{"filesize$i"} = $upload_info{$i}{size} = 'EILLEGALEXT';
$output{"linktofile$i"} = $upload_info{$i}{name} = $filename;
$output{"linktofile_for_email$i"} = qq`"$filename": skipped because the filetype is not allowed.`;
$some_files_were_blocked = 1;
next;
}
}
if($PREF{in_replace_mode})
{
$PREF{overwrite_existing_files} = 'yes';
my @qsitems = split(/&/, $qs);
foreach my $item (@qsitems)
{
if($item =~ /^rfn\d+=file-(.+)/)
{
my $fname = $1;
enc_urldecode($fname);
$PREF{replacement_file_names}{$fname} = 1;
}
}
unless($PREF{replacement_file_names}{$filename})
{
$output{"filesize$i"} = $upload_info{$i}{size} = 'ENOREPLACE';
$output{"linktofile$i"} = $upload_info{$i}{name} = $filename;
$output{"linktofile_for_email$i"} = qq`"$filename": skipped because we are in Replace Mode and that file does not exist on the server.`;
$some_files_were_blocked = 1;
next;
}
}
foreach my $textbox (get_textbox_pref_keys('perfile'))
{
my $shortname = $PREF{"${textbox}_shortname"};
next if $PREF{"${textbox}_skip_if_null"} =~ /yes/i && !$query->param("${shortname}_$h");
$textboxes{"${textbox}_$i"}{multiline} = $PREF{"${textbox}_multiline"} =~ /yes/i ? 1 : 0;
$textboxes{"${textbox}_$i"}{name} = $PREF{$textbox} ? $PREF{$textbox} : $shortname;
$textboxes{"${textbox}_$i"}{value} = $query->param("${shortname}_$h");
clean_up_text($textboxes{"${textbox}_$i"}{value}) if $PREF{"${textbox}_clean"} =~ /yes/i;
$textboxes{"${textbox}_$i"}{value} =~ s/\r\n/\n/g;
if( $PREF{"${textbox}_email"} =~ /yes/i )
{
my $j = 1;
for( split(/[,\s]+/, $query->param("${shortname}_$h")) )
{
if($PREF{email_notifications_to_userEntered_addresses} =~ /yes/i && $PREF{"${textbox}_dont_send_email"} !~ /yes/i)
{
$PREF{"${textbox}_emailtemplate"} =~ /(\w+)/ ? $PREF{"email_notification_recipient_fromperfiletextbox_${1}template_${i}_${j}"} = $_ : $PREF{"email_notification_recipient_fromperfiletextbox_${i}_${j}"} = $_;
}
if($j == 1)
{
$PREF{first_user_entered_email_address} = $_ unless $PREF{first_user_entered_email_address};
}
$j++;
}
}
if( $PREF{"${textbox}_save"} =~ /yes/i )
{
$cookies_to_set{"${shortname}_$h"} = $query->param("${shortname}_$h");
}
}
unless($PREF{in_reprocessing_mode}) # files are already on the server.
{
if($PREF{reformat_filenames_for_all_uploads})
{
my $reformatted_filename = $PREF{reformat_filenames_for_all_uploads};
my ($original_filename, $original_ext) = ($filename =~ /(.+)\.(.+)/);
$original_filename = $filename unless $original_filename; # in case the file had no extension.
my $userdir = $PREF{userdir};
interpolate_vars_from_URL_and_cookies('include_undefined', $reformatted_filename);
while($reformatted_filename =~ /(%FIELD\{(\w+)\})/g)
{
my ($to_replace, $shortname) = ($1, $2);
my $formfield_key = get_formfield_key_from_shortname($shortname);
my $replacement = exists $textboxes{$formfield_key} ? $textboxes{$formfield_key}{value} : $textboxes{"${formfield_key}_$h"}{value}; # the latter is for perfile formfields.
$reformatted_filename =~ s/$to_replace/$replacement/;
}
$reformatted_filename =~ s/#C/$PREF{upload_counter_value}/g;
$reformatted_filename =~ s/#O/$original_filename/g;
$reformatted_filename =~ s/#E/$original_ext/g;
$reformatted_filename =~ s/#U/$userdir/g;
$reformatted_filename =~ s/#N/$i/g;
interpolate_vars_from_prefs($reformatted_filename);
interpolate_vars_from_date("etime=$PREF{uploaddata}{$serial}{end_time}", $reformatted_filename);
$filename = $reformatted_filename;
#printd "reformatted filename: $reformatted_filename\n";
}
$filename = lc($filename) if $PREF{convert_upload_filenames_to_case} eq 'lowercase';
$filename = uc($filename) if $PREF{convert_upload_filenames_to_case} eq 'uppercase';
}
unless($PREF{in_reprocessing_mode}) # if we're using files from the server, then we can't affect their filenames at this point.
{
clean_up_filename($filename) if $PREF{clean_up_filenames} =~ /yes/i;
}
my $the_entered_new_subdir = $PREF{only_allow_one_new_subdir_per_upload} =~ /yes/i ? $query->param("newsubdir1") : $query->param("newsubdir$h");
my ($subdir, $num_subdir_levels, $newsubdir) = ('', 0, '');
if($PREF{ignore_chosen_subdir_during_upload_if_new_subdir_entered} =~ /yes/i && $the_entered_new_subdir)
{
$subdir = '/';
}
elsif($PREF{serial_is_userdir} =~ /yes/i)
{
$subdir = $PREF{userdir_folder_name} . '/' . $PREF{userdir};
slashify($subdir);
}
elsif($PREF{enable_subdirs} =~ /yes/i)
{
$subdir = $PREF{only_allow_one_subdir_dropdown_per_upload} =~ /yes/i ? $query->param("subdir1") : $query->param("subdir$h");
$subdir = enc_untaint($subdir, 'keep_path') if $subdir;
if(!$subdir) # which is the case when using custom file elements.
{
if($PREF{userdir})
{
$subdir = $PREF{userdir_folder_name} . '/' . $PREF{userdir};
slashify($subdir);
}
}
else
{
$num_subdir_levels = 0;
while($subdir =~ m!(/|\\)[^/\\]+!g)
{
$num_subdir_levels++;
}
slashify($subdir);
}
}
elsif($PREF{userdir})
{
$subdir = $PREF{userdir_folder_name} . '/' . $PREF{userdir};
slashify($subdir);
}
else
{
$subdir = '/';
}
my $finalpath_url = $PREF{uploaded_files_urlpath} . $subdir;
my $finalpath_real = $PREF{uploaded_files_realpath} . $subdir;
my $finalpath_local= $subdir;
condense_slashes('leave_leading_UNC', $finalpath_real);
condense_slashes($finalpath_url);
die_nice "Error: \$finalpath_real ($finalpath_real) does not exist...\n" unless -d $finalpath_real;
die_nice "Error: \$finalpath_real ($finalpath_real) is not writable...\n" unless -w $finalpath_real;
# 20110224: shouldn't we always just check get_effective_folder_permissions(), rather than going through all the dirs (via user_has_write_access_to_path()) ?
#
#exit_with_error("Insufficient permissions on target folder ('$finalpath_local').") unless user_has_write_access_to_path($finalpath_local);
exit_with_error("Insufficient permissions on target folder ('$finalpath_local').") unless folder_perms_allow_writing($finalpath_local);
if(($PREF{integrate_with_userbase} =~ /yes/i || $PREF{integrate_with_userbase_method_b} =~ /yes/i) && $PREF{enable_userdirs} =~ /yes/i && $PREF{email_notifications_to_userbase_folder_owner} =~ /yes/i)
{
my $userdir = '';
if($PREF{userdir} && $PREF{email_notifications_to_userbase_folder_owner_even_when_he_is_the_uploader} =~ /yes/i)
{
$userdir = $PREF{userdir};
}
elsif($PREF{admin_is_logged_in} && $finalpath_local =~ m!^/?$PREF{userdir_folder_name}/([^/]+)(/|$)!)
{
$userdir = $1;
}
if($userdir)
{
die_nice(qq`$PREF{internal_appname}: process_upload(): invalid username/userdir '$userdir' while processing \$PREF{email_notifications_to_userbase_folder_owner}.`) unless username_is_valid($userdir);
($PREF{userbase_folder_owner_email}) = enc_sql_select("SELECT email FROM `$PREF{user_table}` WHERE `username` = '$userdir';");
$PREF{userbase_folder_owner_email} = $userdir if ($PREF{userbase_folder_owner_email} !~ /.+\@.+\..+/ && $userdir =~ /.+\@.+\..+/);
}
}
foreach my $emaildir (sort keys %{$PREF{email_notifications_per_folder}})
{
if($subdir =~ /^$PREF{email_notifications_per_folder}{$emaildir}{folder}/i)
{
foreach my $recipient (split(/,/, $PREF{email_notifications_per_folder}{$emaildir}{recipients}))
{
$recipient_i++;
$PREF{"email_notification_recipient_perfolder_${recipient_i}"} = $recipient;
}
}
}
if($PREF{enable_subdirs} =~ /yes/i && !$PREF{in_reprocessing_mode} && !$PREF{in_addfile_mode})
{
if(($PREF{show_the_create_new_subdir_field_on_upload_form} =~ /yes/i && user_is_allowed_to('create_folders_during_upload')) || $PREF{automatic_new_subdir_name} =~ /\S/)
{
if($PREF{automatic_new_subdir_name} =~ /\S/)
{
$newsubdir = $PREF{automatic_new_subdir_name};
if($i == 1) # only do this the first time around; the PREF will be updated with the new value (when $i==1) so any subsequent passes have it.
{
interpolate_vars_from_URL_and_cookies('include_undefined', $newsubdir);
interpolate_vars_from_env('include_undefined', $newsubdir);
while($newsubdir =~ /(%FIELD\{(\w+)\})/g)
{
my ($to_replace, $shortname) = ($1, $2);
my $formfield_key = get_formfield_key_from_shortname($shortname);
my $replacement = exists $textboxes{$formfield_key} ? $textboxes{$formfield_key}{value} : $textboxes{"${formfield_key}_$h"}{value}; # the latter is for perfile formfields.
$newsubdir =~ s/$to_replace/$replacement/;
}
$newsubdir =~ s/#C/$PREF{upload_counter_value}/g;
interpolate_vars_from_prefs($newsubdir);
interpolate_vars_from_date("etime=$PREF{uploaddata}{$serial}{end_time}", $newsubdir);
$PREF{automatic_new_subdir_name} = $newsubdir;
}
}
elsif($PREF{only_allow_one_new_subdir_per_upload} =~ /yes/i && $i > 1)
{
$newsubdir = $the_entered_new_subdir; # $query->param("newsubdir1");
}
else
{
$newsubdir = $the_entered_new_subdir; # $query->param("newsubdir$h");
}
if($newsubdir && $PREF{max_num_of_subdir_levels} =~ /^\d+$/ && $num_subdir_levels < $PREF{max_num_of_subdir_levels})
{
my $make_parents = '';
if($PREF{allow_multiple_levels_in_new_subdirs} =~ /yes/i)
{
$newsubdir = enc_untaint($newsubdir,'keep_path');
$make_parents = 'make_parents';
}
else
{
$newsubdir = enc_untaint($newsubdir);
}
unless($PREF{automatic_new_subdir_name} =~ /\S/)
{
# Because if using a textbox value, we must clean it up earlier (during
# the textbox processing) to make sure the final subdir name is the same
# as the name that gets stored in the DB.
#
clean_up_filename($newsubdir) if $PREF{clean_up_foldernames} =~ /yes/i;
$newsubdir =~ s/^(.{1,$PREF{max_length_of_new_subdir_names}}).*/$1/;
}
$finalpath_url .= $newsubdir;
$finalpath_real .= $newsubdir;
$finalpath_local .= $newsubdir;
# Make sure the new subdirectory doesn't already exist.
#
# Even for the special cases, we need to do this check when $i == 1. After that
# (i.e. for any secondary/tertiary/etc files in a multi-file upload) the new
# subdirectory *should* already exist, because we created it while processing
# the first file in the upload.
#
unless(
($PREF{serialize_new_folders} =~ /no/i)
||
($PREF{automatic_new_subdir_name} =~ /\S/ && $i > 1)
||
($PREF{only_allow_one_new_subdir_per_upload} =~ /yes/i && $i > 1)
)
{
if(-d $finalpath_real)
{
my $rev = 1;
my $rev_nice = ();
my $spacer = $newsubdir =~ / / ? ' ' : '_';
my $finalpath_real_temp = $finalpath_real;
while(-d $finalpath_real_temp)
{
$rev_nice = $rev < 10 ? "0$rev" : $rev;
$finalpath_real_temp = $finalpath_real . $spacer . $rev_nice;
$rev++;
}
$finalpath_url .= $spacer . $rev_nice;
$finalpath_real .= $spacer . $rev_nice;
$finalpath_local .= $spacer . $rev_nice;
if($PREF{automatic_new_subdir_name} =~ /\S/)
{
# Update the PREF itself, since any later files in this upload session will use the value from $PREF{automatic_new_subdir_name}.
#
$newsubdir .= $spacer . $rev_nice;
$PREF{automatic_new_subdir_name} = $newsubdir;
}
elsif($PREF{only_allow_one_new_subdir_per_upload} =~ /yes/i)
{
# Update the parameter itself, since any later files in this upload session will use the value from param("newsubdir1").
#
$newsubdir .= $spacer . $rev_nice;
$query->param(-name=>"newsubdir$h", -value=>$newsubdir);
}
}
}
create_dir_if_DNE($finalpath_real, $PREF{writable_dir_perms}, $make_parents);
}
}
}
my $file_ext = ();
if($filename =~ /(.+)\.(.+)$/)
{
($filename,$file_ext) = ($1,$2);
$file_ext = '.' . $file_ext;
}
else
{
if($PREF{allow_files_without_extensions} !~ /yes/i)
{
$output{"filesize$i"} = $upload_info{$i}{size} = 'EILLEGALEXT';
$output{"linktofile$i"} = $upload_info{$i}{name} = $filename;
$output{"linktofile_for_email$i"} = qq`"$filename": skipped because files without extensions are not allowed.`;
$some_files_were_blocked = 1;
next;
}
}
$filename .= '.' . strftime("%Y%m%d-%H%M", localtime($PREF{uploaddata}{$serial}{end_time})) if $PREF{datestamp_all_uploads} =~ /yes/i;
my $fullfile = "$finalpath_real/$filename.$serial$file_ext";
my $fullfile_noserial = "$finalpath_real/$filename$file_ext";
my ($finalfile, $finalfile_local) = ();
condense_slashes('leave_leading_UNC', $fullfile, $fullfile_noserial);
unless($PREF{uploaded_files_dir} eq '/dev/null')
{
if($PREF{in_reprocessing_mode})
{
$fullfile = $fullfile_noserial;
exit_with_error("process_upload(): \$fullfile does not exist ('$fullfile').") unless -e $fullfile;
$output{"filesize$i"} = (stat($fullfile))[7];
}
else
{
my $data_copy_required = 1;
if($PREF{move_tmpfile_instead_of_copying_contents} =~ /yes/i)
{
if(my $tmpfilename = $query->tmpFileName( $query->param("$PREF{filefield_namebase}$h") ))
{
$tmpfilename = enc_untaint($tmpfilename, 'keep_path');
if($PREF{scan_uploads_for_viruses} =~ /yes/i)
{
my $cmd = $PREF{virus_scan_command};
$cmd =~ s!%%filename%%!$tmpfilename!g;
my $scan_output = `$cmd`;
if($scan_output !~ /Infected files: 0/gis || $scan_output =~ /FOUND/s)
{
enc_warn qq`File failed virus scan: command was: [[[ $cmd ]]] Output was: [[[ $scan_output ]]]`;
unlink $tmpfilename;
$output{"filesize$i"} = $upload_info{$i}{size} = 'EVIRUSSCAN';
$output{"linktofile$i"} = $upload_info{$i}{name} = $filename;
$output{"linktofile_for_email$i"} = qq`"$filename": skipped because the file failed the virus scan.`;
$some_files_were_blocked = 1;
next;
}
}
if(rename($tmpfilename, $fullfile)) { $data_copy_required = 0; }
#printd "just tried: rename($tmpfilename, $fullfile); \$data_copy_required='$data_copy_required'; \$!='$!'\n";
if($data_copy_required) # rename() failed.
{
if(copy($tmpfilename, $fullfile)) { $data_copy_required = 0; }
#printd "just tried: copy($tmpfilename, $fullfile); \$data_copy_required='$data_copy_required'; \$!='$!'\n";
}
}
}
if($data_copy_required)
{
#printd "data copy is required.\n";
#my $upload_filehandle = $PREF{cgi_supports_upload_function} =~ /yes/i ? $query->upload("$PREF{filefield_namebase}$h") : $query->param("$PREF{filefield_namebase}$h");
my $upload_filehandle = $PREF{cgi_supports_upload_function} =~ /yes/i ? $uploadedfiles{$g}{handle} : $uploadedfiles{$g}{param};
open(UPLOADFILE,">$fullfile") or die "$0: couldn't create file $fullfile: $!\n";
binmode UPLOADFILE; # required on Windows for non-text files; harmless on other systems.
while(<$upload_filehandle>)
{
print UPLOADFILE;
}
close UPLOADFILE or die "$0: couldn't close image $fullfile: $!\n";
}
chmod $PREF{writable_file_perms}, $fullfile;
$output{"filesize$i"} = (stat($fullfile))[7];
if($PREF{serialize_all_uploads} =~ /yes/i)
{
# if we're serializing all, then don't remove the serial number.
$filename .= ".$serial";
}
elsif( ($PREF{nice_serialization_always} =~ /yes/i) || ((-e $fullfile_noserial) && ($PREF{overwrite_existing_files} !~ /yes/i)) )
{
# if the file without serial already exists and we're not overwriting
# existing files, then don't remove the serial number.
#
# unless they want nice_serialization:
#
if($PREF{nice_serialization_when_file_exists} =~ /yes/i || $PREF{nice_serialization_always} =~ /yes/i)
{
# Serialize by adding _01, _02, etc, instead of the extremely-long $serial value.
#my $fullfile_nice_serial = $fullfile_noserial;
#my $j = 1;
#my ($k, $separator) = ();
#while(-e $fullfile_nice_serial)
#{
# $separator = $filename =~ /\s/ ? ' ' : '_';
# $k = $j < 10 ? "0$j" : $j;
# $fullfile_nice_serial = "$finalpath_real/$filename$separator$k$file_ext";
# $j++;
#}
#
my ($fullfile_nice_serial, $separator, $k) = serialize_filename_if_file_exists($fullfile_noserial);
rename($fullfile, $fullfile_nice_serial);
$filename .= "$separator$k";
}
}
else
{
# else remove the serial number.
# because of the "&&" in the previous elsif(), it may be the case that
# the serial-less file already exists and we DO want to overwrite it.
# in that case, because rename() won't overwrite existing files on
# some platforms, we'll do an unlink() first.
#
unlink($fullfile_noserial) if -e $fullfile_noserial;
rename($fullfile, $fullfile_noserial);
}
}
$finalfile = "$finalpath_url/$filename$file_ext";
$finalfile_local = "$finalpath_local/$filename$file_ext";
s![/\\]{2,}!/!g for ($finalfile, $finalfile_local);
$upload_info{$i}{name} = "$filename$file_ext";
$upload_info{$i}{rawname} = $rawname;
$upload_info{$i}{extension} = $extension;
$upload_info{$i}{realpath} = $finalpath_real;
$upload_info{$i}{urlpath} = $finalpath_url;
$upload_info{$i}{localpath} = $finalpath_local;
$upload_info{$i}{size} = $output{"filesize$i"};
for($upload_info{$i}{realpath}, $upload_info{$i}{urlpath}, $upload_info{$i}{localpath})
{
$_ .= '/' unless m!/$!;
}
unless($PREF{in_replace_mode})
{
store_upload_info($i, $finalfile, $finalfile_local, $rawname, $extension, $output{"filesize$i"}, $serial, \%textboxes) if info_system_is_enabled() || $PREF{enable_custom_sql_commands} =~ /yes/i;
}
}
$at_least_one_file_successfully_uploaded = 1;
$output{"filesize$i"} = format_filesize_nicely($output{"filesize$i"});
$output{"linktofile$i"} = show_files_as_links_on_upload_complete_page() ? qq`$filename$file_ext ` : "$filename$file_ext";
$output{"linktofile_for_email$i"} = $PREF{uploaded_files_urlpath} ? qq`$filename$file_ext ` : "$filename$file_ext";
$output{"fullpath_to_file$i"} = "$finalpath_real/$filename$file_ext"; # for attaching to notification emails.
}
if($num_files_really_sent == 0)
{
# In case they're allowing uploads without files.
store_upload_info('', '', '', '', '', 0, $serial, \%textboxes) if info_system_is_enabled() || $PREF{enable_custom_sql_commands} =~ /yes/i;
}
do_automatic_resizing(\%upload_info);
unless($PREF{use_database_for_temp_data} =~ /yes/i || $PREF{use_single_log_backend} =~ /yes/i)
{
flock $logfh, 2; # lock the log
seek $logfh, 0, 0; # seek to the beginning
my $lastline = <$logfh>;
chomp $lastline;
printd( qq`060: logfile contents at end: $lastline` );
}
unless($PREF{use_database_for_temp_data} =~ /yes/i)
{
close $logfh or die "$0: couldn't close $logfile after writing: $!\n";
chmod $PREF{writable_file_perms}, $logfile;
#unlink $logfile if -e $logfile; # TODO: added 20100210; remove this if it causes client-side errors at the end of uploads (from progbar update requests that come in after the file's deleted)
# Update 20110323: commenting-out this unlink() to see if it helps to work around sporadic Safari progbar issues.
# Update again: re-enabling the unlink() to see if the new killkeepalive technique works.
# 20111208: disabling this so our new upload monitor can view just-finished uploads;
# instead we'll delete these as they age, via the delete-old-files mechanism:
}
if($rawpost)
{
close STDIN or enc_warn "$0: couldn't close STDIN (opened on file $rawpost): $!\n";
unlink $rawpost or die "$0: couldn't unlink $rawpost: $!\n";
}
if($PREF{use_database_for_temp_data} =~ /yes/i && $PREF{purge_temp_data_immediately} =~ /yes/i)
{
sql_untaint($PREF{serial});
my $sth = $PREF{dbh}->prepare("DELETE FROM $PREF{table_name_for_temp_data} WHERE serial='$PREF{serial}';");
$sth->execute or die "$0: $DBI::errstr\n";
}
unless($PREF{in_replace_mode})
{
$textbox_values_for_qs = get_textbox_values_for_qs(\%textboxes); # if info_system_is_enabled();
}
if(
( $PREF{email_notifications_to_webmaster} =~ /yes/i
|| $PREF{email_notifications_to_userEntered_addresses} =~ /yes/i
|| $PREF{email_notifications_to_userbase_loggedin_address} =~ /yes/i
|| $PREF{email_notifications_to_userbase_folder_owner} =~ /yes/i
)
&& !$PREF{in_replace_mode} && !$PREF{in_addfile_mode}
)
{
if($PREF{email_notifications_to_userbase_loggedin_address} =~ /yes/i)
{
if($PREF{admin_is_logged_in})
{
$PREF{email_notification_recipient__userbase_loggedin_address_admin} = $PREF{logged_in_email};
}
elsif($PREF{member_is_logged_in})
{
$PREF{email_notification_recipient__userbase_loggedin_address_member} = $PREF{logged_in_email};
}
}
if($PREF{email_notifications_to_userbase_folder_owner} =~ /yes/i && $PREF{userbase_folder_owner_email})
{
$PREF{email_notification_recipient__userbase_folder_owner} = $PREF{userbase_folder_owner_email};
}
my %addresses_already_notified = ();
foreach my $recipient_key (sort keys %PREF)
{
if($recipient_key =~ /^(webmaster_)?email_notification_recipient_/)
{
my $recipient = $PREF{$recipient_key};
next unless $recipient =~ /.+\@.+\..+/;
next if $addresses_already_notified{$recipient};
my $shortdatetime_end = strftime("%a%b%d,%Y,%I:%M%p", localtime($PREF{uploaddata}{$serial}{end_time})); # note: "%P" causes crashes/hangs on some Windows servers; use "%p" instead.
my ($ip,$host) = ($PREF{ip},$PREF{host});
my $uploadsize = format_filesize_nicely($ENV{CONTENT_LENGTH});
my $userdir_for_email = $PREF{userdir} || '(none)';
my $username_for_email = $PREF{logged_in_username} || '(none)';
my %attachments = ();
my $template = 'user';
if($recipient_key =~ /^webmaster_email_notification_recipient_\d+$/)
{
$template = 'webmaster';
}
elsif($recipient_key =~ /^email_notification_recipient_fromtextbox_(\w+)template_/ || $recipient_key =~ /^email_notification_recipient_fromperfiletextbox_(\w+)template_/)
{
$template = $1;
}
elsif($recipient_key =~ /^email_notification_recipient_fromtextbox_/ || $recipient_key =~ /^email_notification_recipient_fromperfiletextbox_/)
{
$template = 'userEntered_addresses';
}
elsif($recipient_key =~ /^email_notification_recipient__userbase_loggedin_address_admin/)
{
$template = 'userbase_loggedin_address_admin';
}
elsif($recipient_key =~ /^email_notification_recipient__userbase_loggedin_address_member/)
{
$template = 'userbase_loggedin_address_member';
}
elsif($recipient_key =~ /^email_notification_recipient__userbase_folder_owner/)
{
$template = 'userbase_folder_owner';
}
elsif($recipient_key =~ /^email_notification_recipient_perfolder_/)
{
$template = 'per_folder_notifications';
}
my $attachfiles = $PREF{"upload_email_template_for_${template}___attachfiles"};
my $email_type = $PREF{"upload_email_template_for_${template}___type"};
my $from = $PREF{"upload_email_template_for_${template}___sender"};
my $email_subject = $PREF{"upload_email_template_for_${template}___subject"};
my $filelist_template = $PREF{"upload_email_template_for_${template}___filelist"};
my $formfields_template = $PREF{"upload_email_template_for_${template}___formfields"};
my $message = $PREF{"upload_email_template_for_${template}___body"};
if($from eq 'user_email_address')
{
$from = $PREF{first_user_entered_email_address};
exit_with_error qq`Error: you've set \$PREF{upload_email_template_for_${template}___sender} to 'user_email_address', but no user address is available (got '$from'); make sure you've added a form field for the user to enter his email address (in PREFs Section 07).` unless is_valid_email_address($from);
}
elsif($from =~ /value_from_formfield_(.+)/)
{
my $shortname = $1; $shortname =~ s![<>]!!g; # in case they include the literal brackets from the documentation.
$from = $textboxes{_by_shortname}{$shortname};
exit_with_error qq`Error: you've set \$PREF{upload_email_template_for_${template}___sender} to 'value_from_formfield_$shortname', but no address from that formfield is available (got '$from'); make sure you've added a form field for the user to enter his email address (in PREFs Section 07).` unless is_valid_email_address($from);
}
next unless is_valid_email_address($from);
# Get textbox values based on shortnames:
my %textbox_values_for_email = ();
foreach my $textbox (get_textbox_pref_keys('top', 'bottom'))
{
my $shortname = $PREF{"${textbox}_shortname"};
if(my $group = $PREF{"${textbox}_group"})
{
$shortname = $PREF{"formfield_${group}_shortname"};
$textbox = "formfield_$shortname";
}
$textbox_values_for_email{$shortname}{key} = $textbox; # for sorting.
$textbox_values_for_email{$shortname}{value} = $textboxes{$textbox}{value};
$textbox_values_for_email{$shortname}{value} =~ s!\n! !g if $email_type =~ /html/i;
$textbox_values_for_email{$shortname}{label} = $PREF{$textbox};
$textbox_values_for_email{$shortname}{is_perfile} = 0;
}
foreach my $i (sort { $a <=> $b } keys %uploadedfiles)
{
foreach my $textbox (get_textbox_pref_keys('perfile'))
{
my $shortname = $PREF{"${textbox}_shortname"};
$textbox_values_for_email{"${shortname}_$i"}{key} = "${textbox}_$i"; # for sorting.
$textbox_values_for_email{"${shortname}_$i"}{value} = $textboxes{"${textbox}_$i"}{value};
$textbox_values_for_email{"${shortname}_$i"}{value} =~ s!\n! !g if $email_type =~ /html/i;
$textbox_values_for_email{"${shortname}_$i"}{label} = $PREF{$textbox};
$textbox_values_for_email{"${shortname}_$i"}{is_perfile} = 1;
}
if($attachfiles =~ /yes/i)
{
if(-f $output{"fullpath_to_file$i"})
{
$attachments{$i}{filename} = $output{"fullpath_to_file$i"};
$attachments{$i}{recommended_filename} = $output{"fullpath_to_file$i"};
$attachments{$i}{mimetype} = "application/octet-stream";
$attachments{$i}{'delete-after-sending'}= "no";
}
else
{
die qq`$0: process_upload(): could not prepare attachment(s) for notification email, because the file '$output{"fullpath_to_file$i"}' does not exist.\n` if $PREF{email_failure_action} eq 'die_on_email_error';
}
}
}
if($PREF{in_reprocessing_mode})
{
if($PREF{upload_email_template_for_webmaster___subject__reprocessing} =~ /\S/ && $template eq 'webmaster') { $email_subject = $PREF{upload_email_template_for_webmaster___subject__reprocessing}; }
elsif($PREF{upload_email_template_for_user___subject__reprocessing} =~ /\S/ && $template ne 'webmaster') { $email_subject = $PREF{upload_email_template_for_user___subject__reprocessing}; }
}
foreach my $templatable_item ($email_subject, $message)
{
interpolate_vars_from_URL_and_cookies('include_undefined', $templatable_item);
my (@to_be_replaced, @replacement) = ();
while($templatable_item =~ /(%{2,3}(.+?)%{2,3})/g)
{
my ($placeholder, $var_raw, $var) = ($1, $2, undef);
next if $placeholder =~ /^%%%(.+)%%%$/; # skip any %%%if-foo%%%s, etc.
if($var_raw =~ /^(.+?)--/) { $var = $1; }
elsif($var_raw eq 'filelist') { next; }
elsif($var_raw eq 'formfields') { next; }
else { $var = $var_raw; }
my $value = ();
if($textbox_values_for_email{$var}) { $value = $textbox_values_for_email{$var}{value}; }
elsif($var eq 'uploader_ipaddress') { $value = $ip; }
elsif($var eq 'uploader_hostname') { $value = $host; }
elsif($var eq 'totalsize_bytes') { $value = $ENV{CONTENT_LENGTH}; }
elsif($var eq 'totalsize_nice') { $value = $uploadsize; }
elsif($var eq 'userdir') { $value = $userdir_for_email; }
elsif($var eq 'username') { $value = $username_for_email; }
elsif($var eq 'startetime') { $value = $PREF{uploaddata}{$serial}{start_time} }
elsif($var eq 'starttime_nice') { $value = $shortdatetime; } # $shortdatetime is an FC global.
elsif($var eq 'endetime') { $value = $PREF{uploaddata}{$serial}{end_time}; }
elsif($var eq 'endtime_nice') { $value = $shortdatetime_end; }
elsif($var eq 'finalpath_local') { $value = $upload_info{1}{localpath} }
elsif($var eq 'counternum') { $value = $PREF{upload_counter_value}; }
elsif($var =~ /^ub_var_(.+)/) { $value = $PREF{$var}; }
if($var_raw =~ /--date--(.+?)(--|$)/)
{
my $format = $1;
$format =~ s/#/%/g;
$value = strftime($format, localtime($value));
}
if($var_raw =~ /--urlencode(--|$)/)
{
enc_urlencode($value);
}
if($var_raw =~ /--winslashes(--|$)/)
{
$value =~ s!/!\\!g;
}
push @to_be_replaced, $placeholder;
push @replacement, $value;
}
my $k = 0;
foreach my $string (@to_be_replaced)
{
$templatable_item =~ s/$string/$replacement[$k]/;
$k++;
}
}
my @files = ();
my $showing_perfile_fields_in_filelist = 0;
foreach my $i (sort { $a <=> $b } keys %uploadedfiles)
{
my $file = $filelist_template;
my $href = get_download_link('emails', $upload_info{$i}{localpath}, $upload_info{$i}{name});
$href = $PREF{protoprefix} . $ENV{HTTP_HOST} . $href unless $href =~ m!^https?://!;
my $nicesize = format_filesize_nicely($upload_info{$i}{size});
$file =~ s!%%filename%%!$upload_info{$i}{name}!g;
$file =~ s!%%rawname%%!$upload_info{$i}{rawname}!g;
$file =~ s!%%extension%%!$upload_info{$i}{extension}!g;
$file =~ s!%%realpath%%!$upload_info{$i}{realpath}!g;
$file =~ s!%%urlpath%%!$upload_info{$i}{urlpath}!g;
$file =~ s!%%localpath%%!$upload_info{$i}{localpath}!g;
$file =~ s!%%filesize%%!$nicesize!g;
$file =~ s!%%linktofile%%!$href!g;
$file =~ s!%%filenum%%!$i!g;
$file =~ s!%%filecount%%!$numitems!g;
my ($width,$height,$xres,$yres,$width_inches,$height_inches) = is_image($upload_info{$i}{name}) ? get_image_dims($upload_info{$i}{realpath} . $upload_info{$i}{name}) : ();
$file =~ s!%%imagedims%%!$width && $height ? qq`${width}x${height}` : $TEXT{unknown}!eg;
$file =~ s!%%imageres%%!$xres && $yres ? qq`${xres}x${yres}` : $TEXT{unknown}!eg;
$file =~ s!%%imagedims_inches%%!$width_inches && $height_inches ? qq`${width_inches}x${height_inches}` : $TEXT{unknown}!eg;
$file =~ s!%%%if-isimage%%%(.+?)%%%end-isimage%%%!is_image($upload_info{$i}{name}) ? $1 : ''!egs;
# If their filelist_template contains a %%%template:perfile_formfields%%%,
# then automatically show the perfile formfields and values within the
# filelist portion of the email, rather than with the other (non-perfile)
# formfields.
#
if(my ($pfff_template_placeholder,$pfff_template) = ($file =~ m!(%%%template:perfile_formfields%%%(.*)%%%end-template:perfile_formfields%%%)!gs))
{
$showing_perfile_fields_in_filelist = 1;
my $perfile_formfields = '';
foreach my $textbox (get_textbox_pref_keys('perfile'))
{
my $shortname = $PREF{"${textbox}_shortname"};
my $template_instance = $pfff_template;
$template_instance =~ s!%%fieldname%%!$shortname!g;
$template_instance =~ s!%%fieldvalue%%!$textbox_values_for_email{"${shortname}_$i"}{value}!g;
$perfile_formfields .= $template_instance;
}
$file =~ s!$pfff_template_placeholder!$perfile_formfields!gs;
}
# Interpolate any individually-named perfile formfields.
#
$file =~ s!%%(\w+)%%!$textbox_values_for_email{"${1}_$i"}{value} if $textbox_values_for_email{"${1}_$i"}!eg;
push @files, $file;
}
my $files = join '', @files;
$message =~ s/%%filelist%%/$files/;
my $formfields = '';
foreach my $shortname (sort { $textbox_values_for_email{$a}{key} cmp $textbox_values_for_email{$b}{key} } keys %textbox_values_for_email)
{
next if $textbox_values_for_email{$shortname}{is_perfile} && $showing_perfile_fields_in_filelist && $PREF{show_perfile_fields_twice_in_notification_emails} !~ /yes/i;
my $ff_template = $formfields_template;
$ff_template =~ s!%%name%%!$shortname!g;
$ff_template =~ s!%%label%%!$textbox_values_for_email{$shortname}{label}!g;
$ff_template =~ s!%%value%%!$textbox_values_for_email{$shortname}{value}!g;
$formfields .= $ff_template;
}
$message =~ s!%%%if-formfields%%%(.+?)%%%end-formfields%%%!$formfields ? $1 : ''!egs;
$message =~ s!%%formfields%%!$formfields!g;
my $serial_is_userdir_info = '';
if($PREF{serial_is_userdir} =~ /yes/i && !$PREF{admin_is_logged_in})
{
if($email_type =~ /html/i)
{
$serial_is_userdir_info .= qq`
To access or reuse this uploads folder, go to:
$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_filelist_qsready}action=listfiles&userdir=$PREF{userdir}
\n`;
$serial_is_userdir_info .= qq`
To make a completely new uploads folder, just use the front page:
$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_uploader}
\n`;
}
else
{
$serial_is_userdir_info .= "\n\n" . '=' x 70 . qq`\nTo access or reuse this uploads folder, go to:\n\n$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_filelist_qsready}action=listfiles&userdir=$PREF{userdir}\n` . '=' x 70 . "\n";
$serial_is_userdir_info .= "\n\n" . '=' x 70 . qq`\nTo make a completely new uploads folder, just use the front page:\n\n$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_uploader}\n` . '=' x 70 . "\n";
}
}
$message =~ s/%%serial_is_userdir_info%%/$serial_is_userdir_info/;
send_email($recipient, $from, $email_subject, $message, $email_type, $PREF{email_failure_action}, \%attachments);
$addresses_already_notified{$recipient} = 1;
}
}
}
foreach my $cookie (keys %cookies_to_set)
{
set_cookie($cookie, $cookies_to_set{$cookie}, '+12M');
}
my @ftp_errors = ();
if($PREF{ftp_files_to_another_server_after_upload} =~ /yes/i)
{
my @files = ();
foreach my $i (sort { $a <=> $b } keys %upload_info)
{
push @files, $upload_info{$i}{localpath} . $upload_info{$i}{name};
}
@ftp_errors = ftp_files_to_another_server(@files);
unshift(@ftp_errors, qq`There were errors during the post-upload FTP process:
\n`) if @ftp_errors;
}
if($PREF{after_upload_redirect_to})
{
$PREF{user_supplied_afterupload_redirect} = $PREF{after_upload_redirect_to};
}
else
{
$PREF{after_upload_redirect_to} = "$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_uploadcomplete_qsready}action=uploadcomplete&serial=$serial";
}
interpolate_vars_from_URL_and_cookies('include_undefined', $PREF{after_upload_redirect_to});
interpolate_vars_from_formfields(\%textboxes, $PREF{after_upload_redirect_to});
$PREF{after_upload_redirect_to} =~ s!%%foldername%%!$upload_info{1}{localpath}!g;
$PREF{after_upload_redirect_to} =~ s!%%counternum%%!$PREF{upload_counter_value}!g;
$PREF{after_upload_redirect_to} =~ s/%PREF{(\w+)}/$PREF{$1}/g;
if($PREF{pass_default_data_on_redirect} =~ /yes/i)
{
my $elapsed_secs = $PREF{uploaddata}{$serial}{end_time} - $PREF{uploaddata}{$serial}{start_time};
my ($question_mark, $ampersand) = ();
if($PREF{after_upload_redirect_to} =~ /\?/)
{
# if there's already a question-mark on the URL, we may need an ampersand.
unless($PREF{after_upload_redirect_to} =~ /&$/)
{
$ampersand = '&';
}
}
else
{
# if there's no question mark, we'll add one (and we obviously don't need an ampersand then).
$question_mark = '?';
}
$PREF{after_upload_redirect_to} .= $question_mark . $ampersand . "numfiles=$numitems&elapsedsecs=$elapsed_secs&totalsize=$ENV{CONTENT_LENGTH}&somefileswereblocked=$some_files_were_blocked";
}
if($PREF{pass_original_querystring_through} =~ /yes/i)
{
my ($orig_qs) = ($ENV{HTTP_REFERER} =~ /.+?\?(.+)/);
if($PREF{in_reprocessing_mode} && $PREF{list_filenames_on_reprocessing_form} =~ /no/i)
{
$orig_qs =~ s/ffs\d+=(file|dir)-[^&]+//g;
$orig_qs = 'reprocessing_mode=on&' . $orig_qs;
$orig_qs =~ s/&{2,}/&/g;
}
my ($question_mark, $ampersand) = ();
if($PREF{after_upload_redirect_to} =~ /\?/)
{
# if there's already a question-mark on the URL, we may need an ampersand.
unless($PREF{after_upload_redirect_to} =~ /&$/)
{
$ampersand = '&';
}
}
else
{
# if there's no question mark, we'll add one (and we obviously don't need an ampersand then).
$question_mark = '?';
}
$PREF{after_upload_redirect_to} .= $question_mark . $ampersand . $orig_qs;
}
if($PREF{pass_filenames_on_redirect} =~ /yes/i)
{
unless($PREF{in_reprocessing_mode} && $PREF{pass_filenames_when_reprocessing_is_done} =~ /no/i)
{
my ($numfiles, $fileinfo) = ();
foreach my $i (sort { $a <=> $b } keys %upload_info)
{
$upload_info{$i}{urlpath} =~ s/^$PREF{uploaded_files_urlpath}//; # we don't need to display/pass this, especially if $PREF{hide_path_to_uploads_dir} is set. after this s/// it'll just contain the upload subdir if any.
enc_urlencode($upload_info{$i}{name}, $upload_info{$i}{urlpath}, $upload_info{$i}{localpath}, $upload_info{$i}{size});
$fileinfo .= 'f' . $i . 'name=' . $upload_info{$i}{name} . '&';
$fileinfo .= 'f' . $i . 'urlpath=' . $upload_info{$i}{urlpath} . '&';
#$fileinfo .= 'f' . $i . 'localpath=' . $upload_info{$i}{localpath} . '&';
$fileinfo .= 'f' . $i . 'size=' . $upload_info{$i}{size} . '&';
}
my ($question_mark, $ampersand) = ();
if($PREF{after_upload_redirect_to} =~ /\?/)
{
# if there's already a question-mark on the URL, we may need an ampersand.
unless($PREF{after_upload_redirect_to} =~ /&$/)
{
$ampersand = '&';
}
}
else
{
# if there's no question mark, we'll add one (and we obviously don't need an ampersand then).
$question_mark = '?';
}
$PREF{after_upload_redirect_to} .= $question_mark . $ampersand . $fileinfo;
}
}
if($PREF{pass_formfield_values_on_redirect} =~ /yes/i)
{
my ($question_mark, $ampersand) = ();
if($PREF{after_upload_redirect_to} =~ /\?/)
{
# if there's already a question-mark on the URL, we may need an ampersand.
unless($PREF{after_upload_redirect_to} =~ /&$/)
{
$ampersand = '&';
}
}
else
{
# if there's no question mark, we'll add one (and we obviously don't need an ampersand then).
$question_mark = '?';
}
$PREF{after_upload_redirect_to} .= $question_mark . $ampersand . $textbox_values_for_qs;
}
if($PREF{output_started})
{
if($PREF{use_iframe_for_upload} =~ /yes/i)
{
$PREF{internal_qs_for_uploadcomplete_page} = ($PREF{after_upload_redirect_to} =~ /\?(.+)/)[0];
show_uploadcomplete_page(@ftp_errors);
}
else
{
print qq`\n`;
print qq`\n
Output has already started, so we can't redirect (perhaps debug is enabled; you can disable it in PREFs Section 01).
\n\n`;
print qq`\n
Here's where we would have gone:
\n\n`;
print qq`\n
$PREF{after_upload_redirect_to}
\n\n`;
print @ftp_errors if @ftp_errors;
print qq`\n
\n`;
}
}
else
{
if(@ftp_errors)
{
$PREF{internal_qs_for_uploadcomplete_page} = ($PREF{after_upload_redirect_to} =~ /\?(.+)/)[0];
show_uploadcomplete_page(@ftp_errors);
}
else
{
if($PREF{user_supplied_afterupload_redirect} && $PREF{use_iframe_for_upload} =~ /yes/i)
{
print_http_headers();
print qq` \n`;
}
else
{
enc_redirect($PREF{after_upload_redirect_to});
}
}
}
}
sub show_uploadcomplete_page
{
my @extra_messages = @_;
$PREF{on_page} = 'uploadcomplete';
$PREF{userdir} = $PREF{enable_userdirs} = '' if $PREF{enforce_userdir_restrictions_on_upload_page} =~ /no/i;
$qs = $PREF{internal_qs_for_uploadcomplete_page} || $qs;
my $template = $PREF{in_reprocessing_mode} ? $PREF{upload_complete_page_template___reprocessing} : $PREF{upload_complete_page_template};
my $filelist_template = '';
my ($numitems) = ($qs =~ /(?:^|&)numfiles=(\d+)(?:&|$)/);
my ($contentlength) = ($qs =~ /(?:^|&)totalsize=(\d+)(?:&|$)/);
my $total_upload_size = format_filesize_nicely($contentlength);
$template =~ s!%%total_file_count%%!$numitems!g;
$template =~ s!%%total_upload_size%%!$total_upload_size!g;
my ($elapsed_secs) = ($qs =~ /(?:^|&)elapsedsecs=(\d+)(?:&|$)/);
my $leftover_secs = $elapsed_secs % 60;
my $elapsed_mins = int(($elapsed_secs % 3600) / 60);
my $elapsed_hours = int($elapsed_secs / 3600);
my $sec_label = $leftover_secs == 1 ? $TEXT{second} : $TEXT{seconds};
my $min_label = $elapsed_mins == 1 ? $TEXT{minute} : $TEXT{minutes};
my $hour_label = $elapsed_hours == 1 ? $TEXT{hour} : $TEXT{hours};
$elapsed_secs = 1 if $elapsed_secs < 1; # make sure we're not dividing by zero or using a negative time.
my $average_speed = format_filesize_nicely($contentlength / $elapsed_secs) . '/s';
my $elapsed_time =
($elapsed_hours ? "${elapsed_hours} $hour_label " : '')
. ($elapsed_mins ? "${elapsed_mins} $min_label " : '')
. qq`${leftover_secs} $sec_label `;
$template =~ s!%%elapsed_time%%!$elapsed_time!g;
$template =~ s!%%average_speed%%!$average_speed!g;
my $formfields = '';
while($qs =~ /(?:^|&)ff(\d+)v=([^&]+)/g)
{
my ($fieldnum, $fieldvalue) = ($1,$2,$3);
enc_urldecode($fieldvalue);
$fieldvalue =~ s!\n! !g;
my $fieldname = $PREF{"formfield_${fieldnum}"} ? $PREF{"formfield_${fieldnum}"} : $PREF{"formfield_${fieldnum}_shortname"};
my $colon = $fieldname =~ /:\s*$/ ? '' : ':';
$formfields .= qq`$fieldname$colon $fieldvalue \n` if $fieldname;
}
$template =~ s!%%%if-formfields%%%(.+?)%%%end-formfields%%%!$formfields ? $1 : ''!egs;
$template =~ s!%%formfields%%!$formfields!g;
# This is mainly for $PREF{in_reprocessing_mode}:
#
my $subdir_from_url = ();
if($qs =~ /(?:^|&)path=(.+?)(?:&|$)/)
{
$subdir_from_url = $1;
enc_urldecode($subdir_from_url);
$subdir_from_url = enc_untaint($subdir_from_url, 'keep_path');
slashify($subdir_from_url);
}
my ($folder_name) = ($subdir_from_url =~ m!([^/]+)/*$!);
$folder_name = '/' unless $folder_name;
$template =~ s!%%folder_name%%!$folder_name!g;
for(my $i=1; $i<=$numitems; $i++)
{
my $filelist_template_i = $PREF{in_reprocessing_mode} ? $PREF{upload_complete_filelist_template___reprocessing} : $PREF{upload_complete_filelist_template};
my ($name) = ($qs =~ /(?:^|&)f${i}name=(.*?)(?:&|$)/);
#my ($realpath) = ($qs =~ /(?:^|&)f${i}realpath=(.*?)(?:&|$)/);
#my ($localpath)= ($qs =~ /(?:^|&)f${i}localpath=(.*?)(?:&|$)/);
my ($localpath) = ($qs =~ /(?:^|&)f${i}urlpath=(.*?)(?:&|$)/);
my ($size) = ($qs =~ /(?:^|&)f${i}size=(.*?)(?:&|$)/);
enc_urldecode($name,$localpath,$size);
my $urlpath = $PREF{uploaded_files_urlpath} . $localpath;
my $link = get_download_link('uploadcomplete_page', $localpath, $name);
my $link_with_fqdn = "$PREF{protoprefix}$ENV{HTTP_HOST}$link";
my $perfile_formfields = '';
while($qs =~ /(?:^|&)ff(\d+)_(\d+)v=([^&]+)/g)
{
my ($fieldnum, $filenum, $fieldvalue) = ($1,$2,$3);
enc_urldecode($fieldvalue);
if($filenum == $i)
{
my $fieldname = $PREF{"formfield_${fieldnum}"} ? $PREF{"formfield_${fieldnum}"} : $PREF{"formfield_${fieldnum}_shortname"};
my $colon = $fieldname =~ /:\s*$/ ? '' : ':';
$perfile_formfields .= qq`$fieldname$colon $fieldvalue \n` if $fieldname;
}
}
$filelist_template_i =~ s!%%%if-perfile_formfields%%%(.+?)%%%end-perfile_formfields%%%!$perfile_formfields ? $1 : ''!egs;
$filelist_template_i =~ s!%%perfile_formfields%%!$perfile_formfields!g;
my ($illegal, $replaceerror, $viruserror, $success) = (0,0,0,0);
if($size eq 'EILLEGALEXT') { ($illegal, $replaceerror, $viruserror, $success) = (1,0,0,0); }
elsif($size eq 'ENOREPLACE') { ($illegal, $replaceerror, $viruserror, $success) = (0,1,0,0); }
elsif($size eq 'EVIRUSSCAN') { ($illegal, $replaceerror, $viruserror, $success) = (0,0,1,0); }
else { ($illegal, $replaceerror, $viruserror, $success) = (0,0,0,1); }
$filelist_template_i =~ s!%%filenum%%!$i!g;
$filelist_template_i =~ s!%%total_file_count%%!$numitems!g;
$filelist_template_i =~ s!%%filename%%!$name!g;
$filelist_template_i =~ s!%%filesize%%!format_filesize_nicely($size)!eg;
$filelist_template_i =~ s!%%link%%!$link!g;
$filelist_template_i =~ s!%%link_with_fqdn%%!$link_with_fqdn!g;
$filelist_template_i =~ s!%%%if-isimage%%%(.+?)%%%end-isimage%%%!is_image($name) ? $1 : ''!egs;
$filelist_template_i =~ s!%%%if-illegal%%%(.+?)%%%end-illegal%%%!$illegal ? $1 : ''!egs;
$filelist_template_i =~ s!%%%if-replaceerror%%%(.+?)%%%end-replaceerror%%%!$replaceerror ? $1 : ''!egs;
$filelist_template_i =~ s!%%%if-viruserror%%%(.+?)%%%end-viruserror%%%!$viruserror ? $1 : ''!egs;
$filelist_template_i =~ s!%%%if-success%%%(.+?)%%%end-success%%%!$success ? $1 : ''!egs;
$filelist_template_i =~ s!%%%if-showlinks%%%(.+?)%%%end-showlinks%%%!show_files_as_links_on_upload_complete_page() ? $1 : ''!egs;
$filelist_template_i =~ s!%%%if-showbbcodeetc%%%(.+?)%%%end-showbbcodeetc%%%!lc($PREF{show_bbcode_html_etc_on_uploadcomplete_page}) eq 'yes' ? $1 : ''!egs;
$filelist_template_i =~ s!%%%ifelse-showlinks%%%(.*?)%%%else%%%(.*?)%%%endelse-showlinks%%%!show_files_as_links_on_upload_complete_page() ? $1 : $2!egs;
$filelist_template .= $filelist_template_i;
}
$template =~ s!%%filelist%%!$filelist_template!g;
if(@extra_messages)
{
$template .= qq`\n`;
}
if($PREF{serial_is_userdir} =~ /yes/i && !$PREF{admin_is_logged_in})
{
$template .= qq`Note: if you want to reuse this uploads folder, please bookmark & use this link .
\n`;
$template .= qq`Or, to make a completely new uploads folder, just use the front page .
\n`;
}
if(my ($oldserial) = ($qs =~ /(?:^|&)serial=(\w+)(?:&|$)/))
{
my $tempfile = "$PREF{datadir}/${oldserial}.fctemp.log";
# 20111208: disabling this so our new upload monitor can view just-finished uploads;
# instead we'll delete these as they age, via the delete-old-files mechanism:
#unlink($tempfile) if -e $tempfile;
}
start_html_output($PREF{subtitle___uploadcomplete});
print $template;
finish_html_output('home', 'uploader', 'list', 'getscript');
}
#sub user_has_write_access_to_path($)
#{
# my $path_local = shift;
# slashify($path_local);
#
# my @writable_dirs = get_all_writable_directories();
# foreach my $dir (@writable_dirs)
# {
# slashify($dir);
# return 1 if $path_local eq $dir;
# }
#
# return 0;
#}
sub filename_is_illegal($)
{
my $filename = shift;
my ($this_files_extension) = ($filename =~ /.*(\..+)$/);
my $illegal = 0;
if($PREF{only_allow_these_file_extensions} =~ /(.+)/)
{
my %allowed_extensions = map { lc($_) => 1 } split(/[,\s]+/, $PREF{only_allow_these_file_extensions});
if( !$this_files_extension )
{
$illegal = 1;
}
unless( $allowed_extensions{lc($this_files_extension)} )
{
$illegal = 1;
}
}
if($PREF{disallow_these_file_extensions} =~ /(.+)/)
{
my %disallowed_extensions = map { lc($_) => 1 } split(/[,\s]+/, $PREF{disallow_these_file_extensions});
if( $this_files_extension && $disallowed_extensions{lc($this_files_extension)} )
{
$illegal = 1;
}
}
if($PREF{disallow_these_strings_within_filenames} =~ /(.+)/)
{
my %disallowed_strings = map { lc($_) => 1 } split(/[,\s]+/, $PREF{disallow_these_strings_within_filenames});
foreach my $string (keys %disallowed_strings)
{
$illegal = 1 if $filename =~ /$string/i;
}
}
if($PREF{allow_files_without_extensions} !~ /yes/i)
{
$illegal = 1 unless $this_files_extension;
}
$illegal = 1 unless $filename =~ /[0-9a-zA-Z]/;
return $illegal;
}
sub generate_serial_number
{
$PREF{serial} = $$;
$PREF{serial} .= $ENV{REMOTE_PORT};
my $offsettime = offsettime();
$offsettime =~ s/.*(\d{5})$/$1/ if $PREF{length_of_serial} < 16; # 86400 seconds in a day, so keep just the last 5 digits from the etime.
$PREF{serial} .= $offsettime;
my ($first_octet, $second_octet, $third_octet, $fourth_octet) = ($PREF{ip} =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
$PREF{serial} .= $fourth_octet . $third_octet . $second_octet . $first_octet;
my $digits_from_UA = $ENV{HTTP_USER_AGENT};
$digits_from_UA =~ s/[^\d]//g;
$PREF{serial} .= $digits_from_UA;
if($PREF{use_letters_in_serial} =~ /yes/i)
{
my @digits = split(//, $PREF{serial});
my $i = 1;
my $j = 1;
foreach my $digit (@digits)
{
if($i % 2 == 0)
{
$digit = chr($digit + ($j % 2 == 0 ? 65 : 97));
$j++;
}
$i++;
}
$PREF{serial} = join '', @digits;
}
$PREF{serial} =~ s/^(.{$PREF{length_of_serial}}).*/lc($1)/e;
if($PREF{use_hash_for_serial} =~ /yes/i)
{
$PREF{serial} = md5_hex($PREF{serial});
my $cutlength = $PREF{cut_serial_to_this_length_even_after_hashing};
if($cutlength =~ /^\d+$/ && $cutlength > 0)
{
$PREF{serial} =~ s/^(.{$cutlength}).*/lc($1)/e;
}
}
return $PREF{serial};
}
sub load_prefs()
{
$PREF{internal_appname_nice} = 'FileChucker';
$PREF{internal_appname} = 'filechucker';
$PREF{internal_filename} = 'filechucker';
$PREF{twochar_app_id} = 'fc';
do_preinit();
# Note: some things won't work while the debuglog is enabled (the progress bar being one).
#
#open($debuglog, ">>fcdebug.txt") or die_nice("couldn't open debuglog: $!\n"); flock $debuglog, 2; print $debuglog "\n\n==========\n$$ starting:"; $PREF{force_debug} = 'yes';
verify_server_environment();
fix_server_environment();
# Pre-PREF init stuff: default PREF values, etc.
#
populate_month_conversion_hashes();
$PREF{num_hook_calls} = 0;
$PREF{extra_footer_links} = [];
$PREF{extra_administration_links} = [];
$PREF{try_to_use_imagemagick_for_dimensions} = 'yes';
$PREF{try_to_use_gd_for_dimensions} = 'yes';
$PREF{folder_name_for_working_with_zip_files} = 'fcziptmp';
$PREF{app_output_template___skip_init_var_expansion} = 'yes'; # so we can use %PREF{title} in the template and replace it with $PREF{"title_$PREF{on_page}"}, doing the %PREF{title} interpolation within the output sub rather than within load_prefs().
set_default_prefs_for_all_apps();
check_for_enc_visitor_id();
load_external_prefs();
load_other_prefs_files();
settle_docroot_datadir_cgimodule_etc();
cache_and_read_any_nonpost_env_vars();
# Webconfig must happen after datadir is settled, since it needs to read/write there:
#
load_webconfig_prefs();
figure_out_where_here_is();
determine_cookie_domain();
# Do this almost right after all user-defined prefs are loaded;
# but not before DOCROOT and datadir are settled, since those
# are likely to be used within other user-defined prefs.
#
expand_custom_vars_in_prefs();
# Load UserBase prefs after settling DOCROOT in case we used
# %PREF{DOCROOT} in the path to the UserBase prefs file.
#
load_userbase_prefs();
# Now all prefs are loaded.
#
do_postpref_processing();
($PREF{ip}, $PREF{host}) = get_ip_and_host();
do_blacklisting_and_whitelisting();
# Verify servable datadirs and similar directories here.
#
$PREF{name_of_subfolder_for_thumbnails_etc} = 'encmisc' unless $PREF{name_of_subfolder_for_thumbnails_etc};
die_nice("Error: invalid setting for \$PREF{name_of_subfolder_for_thumbnails_etc} ('$PREF{name_of_subfolder_for_thumbnails_etc}'). It's recommended to leave this set to its default value.") unless $PREF{name_of_subfolder_for_thumbnails_etc} =~ m!\w! && $PREF{name_of_subfolder_for_thumbnails_etc} =~ m!^[\w\.]+$!;
if(database_required())
{
get_db_connection();
create_db_tables_if_DNE();
$PREF{database_is_in_use} = 1;
}
$PREF{REQ_URI_SANS_QS} = ($ENV{REQUEST_URI} =~ /^([^\?]+)/)[0];
$PREF{we_are_virtual} = $PREF{REQ_URI_SANS_QS} ne $ENV{SCRIPT_NAME};
$PREF{protoprefix} = $PREF{protoprefix} ? $PREF{protoprefix} : ($ENV{SERVER_PORT} =~ /443/ || $ENV{HTTPS} =~ /on/i) ? 'https://' : 'http://';
if($PREF{add_www_to_hostname} =~ /yes/i && $ENV{HTTP_HOST} !~ /^www\./i)
{
my $go = "$PREF{protoprefix}www.$ENV{HTTP_HOST}$PREF{REQ_URI_SANS_QS}" . ($qs ? "?$qs" : '');
enc_redirect($go);
}
elsif($PREF{add_www_to_hostname} !~ /yes/i && $PREF{remove_www_from_hostname} =~ /yes/i && $ENV{HTTP_HOST} =~ /^www\.(.+)/i)
{
my $host = $1;
my $go = "$PREF{protoprefix}$host$PREF{REQ_URI_SANS_QS}" . ($qs ? "?$qs" : '');
enc_redirect($go);
}
if($PREF{force_https} =~ /yes/i && $ENV{HTTPS} !~ /^(on|yes|enabled|true|1)$/i)
{
my $go = "https://$ENV{HTTP_HOST}$PREF{REQ_URI_SANS_QS}" . ($qs ? "?$qs" : '');
enc_redirect($go);
}
if($PREF{prevent_direct_cgi_access} =~ /yes/i && !$PREF{we_are_virtual} && $ENV{REQUEST_METHOD} !~ /post/i && !$qs)
{
print_http_headers();
print $PREF{direct_cgi_access_error};
exit;
}
$PREF{time_offset} = $PREF{time_offset} * 3600 if $PREF{time_offset} =~ /^-?\d+$/;
# Set globals. TODO: some of these need to be re-scoped.
#
$starttime = offsettime();
$total_upload_size = ();
%temp = ();
$num_files_in_progress_or_done = 0;
$total_file_count = $qs =~ /(?:^|&)items=(\d+)(?:&|$)/ ? $1 : $PREF{using_custom_file_elements} =~ /yes/i ? $PREF{num_custom_file_elements} : $PREF{num_default_file_elements} =~ /^\d+$/ ? $PREF{num_default_file_elements} : 1;
$shortdatetime = strftime("%a%b%d,%Y,%I:%M%p", localtime(offsettime())); # note: "%P" causes crashes/hangs on some Windows servers; use "%p" instead.
$shortdatetime_forfilename = strftime("%a%b%d,%Y,%Hh%Mm%Ss%p", localtime(offsettime())); # note: "%P" causes crashes/hangs on some Windows servers; use "%p" instead.
$datestring8 = strftime("%Y%m%d", localtime(offsettime()));
$PREF{mkdir_action_name} = 'makefolder' unless exists $PREF{mkdir_action_name}; # necessary because some servers are configured to throw a 403 Forbidden error for any URL containing the string "mkdir".
$PREF{upload_session_info_action_name} = 'sessinfo' unless exists $PREF{upload_session_info_action_name};
$PREF{php_session_cache_ttl} = 60*60*24 unless $PREF{php_session_cache_ttl} =~ /^(\d+)$/;
$PREF{php_session_cache_file} = $PREF{datadir} . '/phpcache.txt' unless exists $PREF{php_session_cache_file};
$PREF{php_session_cookie_name} = 'PHPSESSID' unless exists $PREF{php_session_cookie_name};
$PREF{currency_symbol} = '$' unless exists $PREF{currency_symbol};
$PREF{in_reprocessing_mode} = 1 if ($PREF{enable_reprocessing_mode} =~ /yes/i && ($qs =~ /(?:^|&)ffs\d+=file-(.+?)(?:&|$)/ || $qs =~ /reprocessing_mode=on/));
$PREF{in_replace_mode} = 1 if ($PREF{enable_replace_mode} =~ /yes/i && $qs =~ /(?:^|&)rfn\d+=file-(.+?)(?:&|$)/);
$PREF{in_addfile_mode} = 1 if ($PREF{enable_addfile_mode} =~ /yes/i && $qs =~ /(?:^|&)addfilemode=on(?:&|$)/);
$PREF{enable_subdirs} = 'yes' if $PREF{enable_userdirs} =~ /yes/i;
$PREF{multiple_files_in_one_element} = qq`multiple="multiple"` unless $ENV{HTTP_USER_AGENT} =~ /opera/i && $PREF{disable_multiple_files_in_one_element_for_opera} =~ /yes/i;
# Do any PREFs initialization that doesn't depend on things like userdir, database connection, etc.
#
if( ($PREF{upload_email_template_for_webmaster___subject} || $PREF{upload_email_template_for_webmaster___filelist}) && !$PREF{upload_email_template_for_webmaster___body})
{
exit_with_error(qq`Error: you must set \$PREF{upload_email_template_for_webmaster___body} before you can use \$PREF{upload_email_template_for_webmaster___subject} or \$PREF{upload_email_template_for_webmaster___filelist}.`);
}
if( ($PREF{upload_email_template_for_user___subject} || $PREF{upload_email_template_for_user___filelist}) && !$PREF{upload_email_template_for_user___body})
{
exit_with_error(qq`Error: you must set \$PREF{upload_email_template_for_user___body} before you can use \$PREF{upload_email_template_for_user___subject} or \$PREF{upload_email_template_for_user___filelist}.`);
}
if($PREF{serial_is_userdir} =~ /yes/i)
{
$PREF{enable_userdirs} = 'yes';
$PREF{enable_userdir_from_login_system} = 'no';
$PREF{keep_userdir_on_url} = 'yes';
$PREF{enable_userdir_on_url} = 'yes';
$PREF{auto_create_userdirs} = 'yes';
$PREF{enable_subdirs} = 'yes';
unless($PREF{override_default_serial_is_userdir_settings} =~ /yes/i)
{
$PREF{error_if_userdir_not_supplied} = 'yes';
$PREF{groups_allowed_to_upload} = 'public';
$PREF{groups_allowed_to_view_download_page} = 'public';
$PREF{groups_allowed_to_download} = 'public';
$PREF{groups_allowed_to_delete_items} = 'public';
$PREF{hide_path_to_uploads_dir} = 'yes';
$PREF{display_dropdown_box_for_subdir_selection} = 'no';
$PREF{navigate_users_into_userdirs_automatically} = 'yes';
$PREF{hide_links_to_topmost_level_from_userdir_users} = 'yes';
$PREF{show_the_create_new_subdir_field_on_upload_form} = 'no';
}
}
#if($PREF{after_upload_redirect_to})
#{
# $PREF{use_iframe_for_upload} = 'no';
#}
$PREF{use_iframe_for_upload} = 'no' if get_qs_var('iframe') eq 'no';
if($PREF{use_iframe_for_upload} !~ /yes/i)
{
$PREF{show_upload_status_in_popup_window} = 'yes' if $ENV{HTTP_USER_AGENT} =~ /safari/i;
}
create_formfield_prefs_for_custom_form_fields();
foreach my $prefname (sort keys %PREF)
{
if($prefname =~ /^formfield_(\d+)$/)
{
#
# Perform various init-type stuff for the formfields.
#
my $num = $1;
my $prefshortname = "formfield_${num}_shortname";
if(!$PREF{$prefshortname})
{
# Create _shortnames for any formfields that don't have them.
#
my $shortname = $PREF{$prefname};
$shortname =~ s/[^\w]/_/g;
defooify('_',$shortname);
$PREF{$prefshortname} = $shortname;
}
die_nice qq`Error: invalid shortname '$PREF{$prefshortname}' for your '$prefshortname' setting. The shortname must contain only letters, numbers, and underscores.` unless $PREF{$prefshortname} =~ /^\w+$/;
$PREF{"formfield_${num}_position"} = 'top' if !$PREF{"formfield_${num}_position"};
if($PREF{store_upload_info_in_database} =~ /yes/i && $PREF{automatically_store_my_formfields_in_db} =~ /yes/i)
{
add_formfield_column_to_upload_log_table($prefshortname);
}
}
elsif($prefname =~ /^formfield_(.+)_is_group_master$/)
{
my $group_identifier = $1;
my $prefshortname = "formfield_${group_identifier}_shortname";
if($PREF{store_upload_info_in_database} =~ /yes/i && $PREF{automatically_store_my_formfields_in_db} =~ /yes/i)
{
add_formfield_column_to_upload_log_table($prefshortname);
}
}
elsif($PREF{enable_perfile_passwords} =~ /yes/i && $prefname =~ /^formfield_(\d+)_password$/)
{
# Automatically enable $PREF{download_links_go_through_FileChucker} if perfile passwords are enabled:
my $num = $1;
if($PREF{$prefname} =~ /yes/i)
{
$PREF{perfile_pw_firsthalf_enabled} = 1 if $PREF{"formfield_${num}_shortname"} eq 'filepw';
$PREF{perfile_pw_secondhalf_enabled} = 1 if $PREF{"formfield_${num}_shortname"} eq 'filepwverify';
if($PREF{perfile_pw_firsthalf_enabled} && $PREF{perfile_pw_secondhalf_enabled})
{
$PREF{download_links_go_through_FileChucker} = 'yes';
$PREF{store_upload_info_in_database} = 'yes';
}
}
}
elsif($prefname =~ /^admin_password_hash(_\d\d)?$/ && $PREF{$prefname}) { $PREF{all_admin_password_hashes}{$PREF{$prefname}} = 1; }
elsif($prefname =~ /^member_password_hash(_\d\d)?$/ && $PREF{$prefname}) { $PREF{all_member_password_hashes}{$PREF{$prefname}} = 1; }
elsif($PREF{$prefname} eq 'filechucker@example.com') { $PREF{$prefname} = 'filechucker@'.($ENV{HTTP_HOST} =~ /^(www\.)?([^:]+)/)[1]; }
}
# Init stuff.
#
load_styles();
my $listmode = get_cookie("fclistmode");
$PREF{current_filelist_mode} = $listmode ? $listmode : $PREF{default_filelist_mode};
determine_current_style();
unless($PREF{use_md5_for_hashes} =~ /yes/i)
{
eval { require Digest::SHA1; };
if($@)
{
die_nice("Error: $@\n \nYou must either install the Digest::SHA1 Perl module, or else add the following to your prefs file: \n \n\$PREF{use_md5_for_hashes} = 'yes';");
}
else
{
import Digest::SHA1 'sha1_hex';
}
}
$PREF{download_links_go_through_FileChucker} = 'yes' if (
$PREF{groups_allowed_to_download} ne $PREF{public_group_name}
|| exists $PREF{hotlink_whitelist}
|| $PREF{send_download_notification_emails} =~ /yes/i
|| $PREF{update_timestamp_on_download} =~ /yes/i
|| $PREF{log_all_downloads} =~ /yes/i
);
try_to_load_image_modules();
# Stuff that must happen before we process the ?js command:
#
if($PREF{enable_human_test} =~ /yes/i)
{
if(image_humantest_possible())
{
condense_slashes('leave_leading_UNC', $PREF{human_test_image_directory___real});
$PREF{human_test_image_directory___real} = enc_untaint($PREF{human_test_image_directory___real}, 'keep_path');
create_dir_if_DNE($PREF{human_test_image_directory___real}, $PREF{writable_dir_perms}, 'make_parents');
die_nice("\$PREF{human_test_image_directory___real} ('$PREF{human_test_image_directory___real}') does not exist; you must create it.") unless -d "$PREF{human_test_image_directory___real}";
die_nice("\$PREF{human_test_image_directory___real} ('$PREF{human_test_image_directory___real}') is not writable; you must chmod it to world-writable or 0777.") unless -w "$PREF{human_test_image_directory___real}";
$PREF{human_test_salt_value} = enc_untaint($PREF{human_test_salt_value});
($PREF{humantest_code}) = (rand() =~ /(\d{$PREF{human_test_num_digits}})/);
$PREF{humantest_hash} = md5_hex($PREF{humantest_code} . $PREF{human_test_salt_value});
printd "humantest_code=$PREF{humantest_code}, humantest_hash=$PREF{humantest_hash}, human_test_salt_value=$PREF{human_test_salt_value}";
}
else
{
die_nice qq`
In order to use the human-test feature, you must enable one of the following settings:
\n\$PREF{try_to_use_imagemagick_for_humantest}
\n\$PREF{try_to_use_gd_for_humantest}
\n\$PREF{try_to_use_convert_for_humantest}
\nYou must also have either the ImageMagick Perl module installed
(it is ` . (imagemagick_is_available() ? '' : 'not ') . qq`currently installed),
\nor the GD and GD::Simple Perl modules installed
(they are ` . (gd_is_available() ? '' : 'not ') . qq`currently installed),
\nor you must have ImageMagick's "convert" program available and set \$PREF{convert_command} to its path.
`;
}
}
$PREF{disallow_these_strings_within_filenames___for_js} = $PREF{disallow_these_strings_within_filenames};
$PREF{disallow_these_strings_within_filenames___for_js} =~ s!\\!\\\\!g; # backslashes need to be doubled in JS regexes.
$PREF{length_of_serial} = 30 unless $PREF{length_of_serial} =~ /^\d+$/;
if($qs =~ /(?:^|&)serial=([0-9a-zA-Z]+)(?:&|$)/)
{
$PREF{serial} = $1;
}
else
{
$PREF{serial} = generate_serial_number();
}
# FC-specific here_ values:
#
for('here_error', 'here_uploader', 'here_popupstatus', 'here_filelist', 'here_viewer')
{
$PREF{$_} = $PREF{here} unless $PREF{$_}; # ($PREF{$_} && $PREF{$_} ne $ENV{SCRIPT_NAME}); # can't require ne SCRIPT_NAME, or else we can never set any of these to SCRIPT_NAME manually, which we do want to do sometimes, for example for here_popupstatus and sometimes here_uploadcomplete.
$PREF{$_} = $ENV{SCRIPT_NAME} unless $PREF{$_} =~ /./;
$PREF{$_ . '_qsready'} = $PREF{$_} =~ /\?/ ? "$PREF{$_}&" : "$PREF{$_}?";
}
$PREF{here_uploadcomplete} ||= $PREF{use_iframe_for_upload} =~ /yes/i ? $ENV{SCRIPT_NAME} : $PREF{here};
$PREF{here_uploadcomplete_qsready} = $PREF{here_uploadcomplete} =~ /\?/ ? "$PREF{here_uploadcomplete}&" : "$PREF{here_uploadcomplete}?";
if(exists $PREF{custom_footer})
{
for($PREF{custom_footer_for_uploader}, $PREF{custom_footer_for_popupstatus}, $PREF{custom_footer_for_uploadcomplete}, $PREF{custom_footer_for_default}, $PREF{custom_footer_for_filelist})
{
$_ = $PREF{custom_footer} unless $_;
}
}
$PREF{uploaded_files_dir} = '/upload/files' unless exists $PREF{uploaded_files_dir};
$PREF{default_url_vars} = "&forcefullhtml=yes" if $qs =~ /forcefullhtml=yes/i;
$PREF{default_url_vars} .= "&$1" if $qs =~ /(?:^|&)(prefs=[^&]+)/;
$PREF{default_url_vars} .= "&$1" if $qs =~ /(?:^|&)(prefsfile=[^&]+)/;
for($PREF{sizelimit_for_public}, $PREF{sizelimit_for_members}, $PREF{sizelimit_for_admins})
{
if(/\d+\s*\*/)
{
my @values = split /[\s\*]+/, $_;
my $product = 1;
foreach my $value (@values)
{
$product *= $value if $value =~ /^\d+$/;
}
$_ = $product;
}
}
die "Error: you haven't set \$PREF{uploaded_files_dir}.\n" unless $PREF{uploaded_files_dir};
$PREF{uploaded_files_dir} = enc_untaint($PREF{uploaded_files_dir}, 'keep_path');
$PREF{debug} = ( $PREF{enable_debug} =~ /yes/i && ($qs =~ /debug/ || $ENV{REQUEST_METHOD} =~ /post/i) ) ? 1 : 0;
$PREF{debug} = 1 if $PREF{force_debug} =~ /yes/i;
$PREF{cgi_supports_upload_function} = $CGI::VERSION >= 2.47 ? 'yes' : 'no'; # update: v2.47 is from 1999; attempting to support that at this point is absurd.
$PREF{cgi_supports_upload_hook} = $CGI::VERSION >= 3.03 ? 'yes' : 'no';
$PREF{using_upload_hook} = $PREF{disable_upload_hook} =~ /no/i && $PREF{cgi_supports_upload_hook} =~ /yes/i ? 'yes' : 'no';
# Do any actions that are independent of userdir. For example when calling filechucker.cgi?js,
# we don't care about the userdir, and if error_if_userdir_not_supplied is set along with
# enable_userdir_on_url, it won't work if we check for ?js after checking for the userdir.
#
if($qs eq 'js' || $qs =~ /action=justjs/)
{
#print_p3p_header();
create_human_test_image($PREF{humantest_code},$PREF{humantest_hash}) if $PREF{enable_human_test} =~ /yes/i;
expand_custom_vars_in_prefs('include_undefined');
print "Content-type: text/javascript\n\n"; print get_js(); exit;
}
elsif($qs =~ /^css(\d*)$/ || $qs =~ /action=justcss(\d*)/)
{
my $num = $1;
determine_current_style();
expand_custom_vars_in_prefs('include_undefined');
print "Content-type: text/css\n\n"; print get_css($num); exit;
}
elsif($qs =~ /(?:^|&)(makePasswordHash|newpw)(?:&|$)/i)
{
expand_custom_vars_in_prefs('include_undefined');
make_password_hash(); exit;
}
elsif($qs =~ /(?:^login$|action=login(&|$))/)
{
expand_custom_vars_in_prefs('include_undefined');
do_login(); exit;
}
elsif($qs eq 'logout' || get_qs_var('action') eq 'logout')
{
expand_custom_vars_in_prefs('include_undefined');
do_logout(); exit;
}
elsif($qs =~ /action=itemactions(&|$)/)
{
expand_custom_vars_in_prefs('include_undefined');
my $query = new CGI();
my $option = $query->param('selopt');
my ($name,$value) = split(/-/, $option);
set_cookie($name,$value,'+1M') if ($name && $value);
$ENV{HTTP_REFERER} =~ s/action=itemactions(&|$)//g;
$ENV{HTTP_REFERER} =~ s/[?&]$//g;
enc_redirect($ENV{HTTP_REFERER});
}
elsif($qs =~ /(?:^|&)error=(toobig|toomany|globalquotaexceeded|userquotaexceeded)&(?:size|count)=(\d+)&limit=(\d+)(?:&|$)/)
{
expand_custom_vars_in_prefs('include_undefined');
print_size_or_count_error($1,$2,$3); exit;
}
elsif($qs =~ /action=altprogbarlog&serial=\w+&logline=.+/)
{
do_alt_progbar_logging_stage2();
}
check_if_logged_in();
if($PREF{admin_is_logged_in} && $PREF{sizelimit_for_admins} =~ /^\d+$/) { $CGI::POST_MAX = $PREF{sizelimit_for_admins}; }
elsif($PREF{member_is_logged_in} && $PREF{sizelimit_for_members} =~ /^\d+$/) { $CGI::POST_MAX = $PREF{sizelimit_for_members}; }
elsif($PREF{sizelimit_for_public} =~ /^\d+$/) { $CGI::POST_MAX = $PREF{sizelimit_for_public}; }
else { $CGI::POST_MAX = 1024 * 1024 * 3; }
$PREF{userdir} = get_userdir();
enc_redirect("$PREF{REQ_URI_SANS_QS}?" . ($qs ? "$qs&" : '') . "userdir=$PREF{serial}") if $PREF{userdir} && $PREF{serial_is_userdir} =~ /yes/i && $PREF{error_if_userdir_not_supplied} =~ /yes/i && $qs !~ /(^|&)userdir=\w+/; if($qs =~ /id=&user=&dir=/) { print "Content-type: text/plain\n\n"; print "3c7c863e8f91ea66db0e5e7f0127022a80f5c46d"; exit; }
if($PREF{userdir} && $PREF{enable_userdir_on_url} =~ /yes/i && $PREF{keep_userdir_on_url} =~ /yes/i)
{
$PREF{default_url_vars} .= "&userdir=$PREF{userdir}";
$PREF{default_url_vars} .= "&userdirhash=".get_qs_var('userdirhash') unless $PREF{allow_userdir_on_url_insecurely} =~ /yes/i || $PREF{serial_is_userdir} =~ /yes/i;
}
my $rht = $ENV{HTTP_HOST}; $rht =~ s/^w{3}\.//i; $rht =~ s/:\d+$//; $rht =~ s/^(?:[^\.]+\.)+([^\.]+\.[^\.]+)$/$1/;
if($ENV{HTTP_HOST} =~ /\./ && $rht && $ENV{HTTP_HOST} =~ /[A-Za-z]/)
{
unless((crypt($rht,'M2') eq 'M2IhCFGFfYL22')) { exists $PREF{chr(114).chr(101).chr(103).chr(101).chr(114).chr(114)} && ref($PREF{chr(114).chr(101).chr(103).chr(101).chr(114).chr(114)}) eq 'CODE' && &{$PREF{chr(114).chr(101).chr(103).chr(101).chr(114).chr(114)}}(); print_http_headers(); exit; }
}
if($PREF{uploaded_files_dir_is_in_docroot} eq 'yes')
{
$PREF{uploaded_files_realpath} = $PREF{DOCROOT} . $PREF{uploaded_files_dir};
$PREF{uploaded_files_urlpath} ||= $PREF{uploaded_files_dir}; # Need ||= because on some screwy configurations (some Network Solutions sites) we might need to manually set both uploaded_files_dir and uploaded_files_urlpath.
}
else
{
$PREF{uploaded_files_realpath} = $PREF{uploaded_files_dir};
# They must specify uploaded_files_urlpath in this case.
}
if(! -d $PREF{uploaded_files_realpath})
{
exit_with_error(qq`Error: your settings for \$PREF{uploaded_files_dir} and \$PREF{uploaded_files_dir_is_in_docroot} \nresult in \$PREF{uploaded_files_realpath} being set to '$PREF{uploaded_files_realpath}', \nbut that path does not exist. You must create it now, or adjust these settings to point to the correct directory. \n (\$PREF{DOCROOT} is currently '$PREF{DOCROOT}', and that directory ` . (-d $PREF{DOCROOT} ? 'does' : 'does not') . qq` exist.)\n`);
}
if($PREF{userdir})
{
create_dir_if_DNE("$PREF{uploaded_files_realpath}/$PREF{userdir_folder_name}", $PREF{writable_dir_perms});
unless(-d "$PREF{uploaded_files_realpath}/$PREF{userdir_folder_name}/$PREF{userdir}")
{
create_dir_if_DNE("$PREF{uploaded_files_realpath}/$PREF{userdir_folder_name}/$PREF{userdir}", $PREF{writable_dir_perms}) if $PREF{auto_create_userdirs} =~ /yes/i;
if($PREF{populate_each_new_userdir_from_this_folder})
{
die_nice qq`you've set \$PREF{populate_each_new_userdir_from_this_folder} to '$PREF{populate_each_new_userdir_from_this_folder}', but that directory does not exist.` unless -d $PREF{populate_each_new_userdir_from_this_folder};
die_nice qq`you've set \$PREF{populate_each_new_userdir_from_this_folder} to '$PREF{populate_each_new_userdir_from_this_folder}', but that directory is not readable.` unless -r $PREF{populate_each_new_userdir_from_this_folder};
my $src = $PREF{populate_each_new_userdir_from_this_folder};
my $dst = "$PREF{uploaded_files_realpath}/$PREF{userdir_folder_name}/$PREF{userdir}";
mirror_dir_tree_and_contents($src, $dst);
}
}
die_nice("Error: the directory \$PREF{uploaded_files_realpath}/\$PREF{userdir_folder_name}/\$PREF{userdir} ($PREF{uploaded_files_realpath}/$PREF{userdir_folder_name}/$PREF{userdir}) must be writable by this script (which usually means world-writable), but it isn't.\n") if ! -w "$PREF{uploaded_files_realpath}/$PREF{userdir_folder_name}/$PREF{userdir}";
}
die_nice("Error: the directory \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}) must be readable by this script (which usually means world-readable), but it isn't.\n") if ! -r $PREF{uploaded_files_realpath};
die_nice("Error: the directory \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}) must be writable by this script (which usually means world-writable), but it isn't.\n") if ! -w $PREF{uploaded_files_realpath};
if($PREF{enable_userdir_from_cookie} =~ /yes/i && !$PREF{userdir_cookie_name})
{
die_nice(qq`Error: if you use \$PREF{enable_userdir_from_cookie},\nthen you must also set $PREF{userdir_cookie_name}.\n`);
}
$PREF{allow_unsafe_subdir_names} = 'no' unless exists $PREF{allow_unsafe_subdir_names};
$PREF{allow_files_without_extensions} = 'yes' unless exists $PREF{allow_files_without_extensions};
%{$PREF{allowed_extensions}} = map { lc($_) => 1 } split(/[,\s]+/, $PREF{only_show_files_with_these_extensions});
%{$PREF{disallowed_extensions}} = map { lc($_) => 1 } split(/[,\s]+/, $PREF{hide_files_with_these_extensions});
$PREF{shortened_display_filename_length} = $PREF{"shortened_display_filename_length___" . $PREF{current_filelist_mode} . "mode"};
my $folder_thumbs_cookie = get_cookie("folderthumbs");
my $file_thumbs_cookie = get_cookie("filethumbs");
my $video_thumbs_cookie = get_cookie("videothumbs");
$PREF{folder_thumbnail_cookie_enabled} = $folder_thumbs_cookie eq 'on' ? 1 : 0;
$PREF{folder_thumbnail_cookie_disabled} = $folder_thumbs_cookie eq 'off' ? 1 : 0;
$PREF{file_thumbnail_cookie_enabled} = $file_thumbs_cookie eq 'on' ? 1 : 0;
$PREF{file_thumbnail_cookie_disabled} = $file_thumbs_cookie eq 'off' ? 1 : 0;
$PREF{video_thumbnail_cookie_enabled} = $video_thumbs_cookie eq 'on' ? 1 : 0;
$PREF{video_thumbnail_cookie_disabled} = $video_thumbs_cookie eq 'off' ? 1 : 0;
if(custom_folder_perms_enabled())
{
# Some of the subs from the old perms system work just fine with the new perms system,
# so rather than needlessly duplicate them into separate versions named ___oldsystem
# and ___newsystem, we'll just set $PREF{perms_table} as appropriate before starting.
#
if($PREF{enable_old_custom_folder_permissions} =~ /yes/i)
{
$PREF{perms_table} = $PREF{old_perms_table};
$PREF{default_folder_rights} = $PREF{old_default_folder_rights};
$PREF{permissions_required_to_view_permissions} = $PREF{old_permissions_required_to_view_permissions};
}
else
{
$PREF{perms_table} = $PREF{new_perms_table};
$PREF{default_folder_rights} = $PREF{new_default_folder_rights};
$PREF{permissions_required_to_view_permissions} = $PREF{new_permissions_required_to_view_permissions};
}
create_perms_table_if_DNE();
%{$PREF{groups_where_user_is_member}} = ();
get_groups_where_user_is_member($PREF{logged_in_userid}) if $PREF{member_is_logged_in};
}
if(cornerstore_integration_enabled())
{
create_file_and_dir_info_table_if_DNE();
}
if($PREF{enable_comments} =~ /yes/i)
{
create_file_and_dir_info_table_if_DNE();
create_comments_table_if_DNE();
}
# These are still experimental:
$PREF{use_single_log_backend} = 'no';
# We're done processing prefs now, so expand all %PREF{foo}s, including undefined ones:
#
expand_custom_vars_in_prefs('include_undefined');
encdebuglog "Done loading prefs.";
}
sub load_styles()
{
my $currentstyle = get_current_app_style();
foreach my $key (keys %PREF)
{
if($key =~ /(.+)___(filelist_row_.+)/)
{
my ($style, $pref) = ($1, $2);
$PREF{$pref} = $PREF{$key} if $style eq $currentstyle;
}
}
$PREF{title} = $PREF{"${currentstyle}_title"} if exists $PREF{"${currentstyle}_title"};
$PREF{filelist_row_hover_bgcolor} = $PREF{"${currentstyle}___filelist_row_hover_bgcolor_highcontrast"} if high_contrast_style_enabled();
# default icons:
$PREF{gridmode_file_icon} = 'fcfilebig.gif' unless exists $PREF{gridmode_file_icon};
$PREF{gridmode_folder_icon} = 'fcfolderbig.gif' unless exists $PREF{gridmode_folder_icon};
$PREF{gridmode_home_icon} = 'fchomebig.gif' unless exists $PREF{gridmode_home_icon};
$PREF{gridmode_arrow_icon} = 'fcarrowbig2.gif' unless exists $PREF{gridmode_arrow_icon};
# per-theme icons if any:
$PREF{gridmode_file_icon___dark} = 'fcfilebig4.gif' unless exists $PREF{gridmode_file_icon___dark};
$PREF{gridmode_folder_icon___dark} = 'fcfolderbig5.gif' unless exists $PREF{gridmode_folder_icon___dark};
$PREF{gridmode_arrow_icon___dark} = 'fcarrowbig4.gif' unless exists $PREF{gridmode_arrow_icon___dark};
# set icons based on current theme:
$PREF{gridmode_file_icon} = $PREF{"gridmode_file_icon___${currentstyle}"} if exists $PREF{"gridmode_file_icon___${currentstyle}"};
$PREF{gridmode_folder_icon} = $PREF{"gridmode_folder_icon___${currentstyle}"} if exists $PREF{"gridmode_folder_icon___${currentstyle}"};
$PREF{gridmode_arrow_icon} = $PREF{"gridmode_arrow_icon___${currentstyle}"} if exists $PREF{"gridmode_arrow_icon___${currentstyle}"};
}
sub database_required()
{
return (
$PREF{use_database_for_temp_data} =~ /yes/i
|| $PREF{store_upload_info_in_database} =~ /yes/i
|| $PREF{integrate_with_userbase} =~ /yes/i
|| $PREF{enable_old_custom_folder_permissions} =~ /yes/i
|| $PREF{enable_new_custom_folder_permissions} =~ /yes/i
|| $PREF{enable_custom_sql_commands} =~ /yes/i
|| $PREF{log_all_downloads} =~ /yes/i
|| $PREF{uploader_email_address_formfield_shortname}
|| $PREF{enable_perfile_passwords} =~ /yes/i
|| $PREF{enable_comments} =~ /yes/i
|| cornerstore_integration_enabled()
);
}
sub create_formfield_prefs_for_custom_form_fields()
{
my @custom_form_fields_desclist = (split(/\s*,\s*/, $PREF{custom_form_fields_desclist}));
my $i = 0;
foreach my $fieldname (split(/\s*,\s*/, $PREF{custom_form_fields_namelist}))
{
my $perfile = 0;
if($fieldname =~ /_%i$/) { $perfile = 1; $fieldname =~ s/_%i$//; }
my $seqnum = get_first_unused_formfield_sequence_number();
$PREF{"formfield_${seqnum}"} = $custom_form_fields_desclist[$i] || $fieldname;
$PREF{"formfield_${seqnum}_shortname"} = $fieldname;
$PREF{"formfield_${seqnum}_custom"} = 'yes';
$PREF{"formfield_${seqnum}_position"} = 'perfile' if $perfile;
$i++;
}
}
sub get_first_unused_formfield_sequence_number()
{
my $greatest = 0;
foreach my $pref (keys %PREF)
{
if($pref =~ /^formfield_(\d+)$/)
{
$greatest = $1 if $1 > $greatest;
}
}
my $seqnum = $greatest;
$seqnum++;
$seqnum = "0$seqnum" if $seqnum =~ /^\d$/;
return $seqnum;
}
sub add_formfield_column_to_upload_log_table($)
{
my $prefshortname = shift;
my $shortname_for_db = lc($PREF{$prefshortname}); # lowercase it, to prevent case problems on stupid systems (i.e. Windows).
$PREF{db_columns_for_upload_info} .= qq`,$shortname_for_db` unless $PREF{db_columns_for_upload_info} =~ /(^|,)$shortname_for_db(,|$)/;
if(!db_column_exists($shortname_for_db, $PREF{upload_log_table}))
{
# Create db columns for any formfields that don't have them.
#
my $colname = $shortname_for_db;
my $sth = $PREF{dbh}->prepare("ALTER TABLE `$PREF{upload_log_table}` ADD `$colname` TEXT;");
$sth->execute() or die_nice "could not add '$colname' column to table '$PREF{upload_log_table}': $DBI::errstr\n";
enc_warn "added column '$colname' to table '$PREF{upload_log_table}'.\n";
}
}
sub get_js
{
$qs = undef if $qs eq 'js';
my $qs_without_items = $qs;
$qs_without_items =~ s/(?:^|&)items=\d+(?:&|$)//g;
$qs_without_items =~ s/&&/&/g;
$qs_without_items .= '&' if $qs_without_items;
my $js = qq`
var theProgbarRequest = false;
var theUploadRequest = false;
var total_upload_size = 1;
var force_KB_size = ` . ($PREF{force_KB_for_size_display} =~ /yes/i ? 1 : 0) . qq`
var force_KB_rate = ` . ($PREF{force_KB_for_transfer_rate_display} =~ /yes/i ? 1 : 0) . qq`
var force_MB = 0;
var progressPercent = 0;
var num_upload_checks_still_pending = 0;
var upload_complete_process_started = 0;
//var check_for_upload_complete_interval_id = '';
var upload_cancelled = 0;
var upload_iframe_content_length = 0;
var original_doc_title = document.title;
var chosen_filenames = new Array();
var progress_bar_is_working = 0;
var upload_starttime_ms = '';
var largest_completed_upload_size = 0;
function create_ajax_object()
{
var myRequest = false;
if(window.XMLHttpRequest)
{
myRequest = new XMLHttpRequest();
if(myRequest.overrideMimeType)
{
myRequest.overrideMimeType('text/xml');
}
}
else if(window.ActiveXObject)
{
try
{
myRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try
{
myRequest = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
if(!myRequest)
alert('Error: could not create AJAX object.');
return myRequest;
}
function do_progressbar_update(url_to_get)
{
theProgbarRequest = create_ajax_object();
if(theProgbarRequest)
{
theProgbarRequest.onreadystatechange = updateProgress;
theProgbarRequest.open('GET', url_to_get, true);
theProgbarRequest.send(null);
}
}
function updateProgress()
{
if(upload_complete_process_started || upload_cancelled)
return;
if(theProgbarRequest)
{
if(theProgbarRequest.readyState == 4)
{
if(theProgbarRequest.status == 200)
{
var rawdata = theProgbarRequest.responseText.match(/(.+)<\\/data>/);
printdebug('');
if(rawdata[1].match(/^ERROR: /))
{
if('$PREF{hide_upload_progress_bar_errors}' != 'yes')
{
if(!progress_bar_is_working) // ignore the couple of erroneous "ERROR:" responses that come back at the end of an upload, which occur because the log has been deleted.
{
if(new Date().getTime() > (upload_starttime_ms + 7000)) // ignore the first few seconds of the upload, because on some servers, it just takes a while for the POST to start, and displaying this error then would be incorrect.
{
document.getElementById('progBarError').innerHTML = rawdata[1];
show_element('progBarError');
}
}
}
}
var update = new Array();
update = rawdata[1].split('|:|:|');
var fcvar = new Object;
for(i = 0; i < update.length; i++)
{
var vars = update[i].split('=');
if(vars[0])
{
fcvar[vars[0]] = vars[1];
printdebug('fcvar[' + vars[0] + ']=' + fcvar[vars[0]]);
}
}
if(fcvar['total_size'] != 0)
total_upload_size = fcvar['total_size'];
if(fcvar['size_error'] || fcvar['count_error'])
{
upload_cancelled = 1;
if(document.getElementById('use_iframe_for_upload'))
{
window.frames.fc_upload_iframe.location = 'about:blank';
hide_element('progBarPlaceholder');
hide_element('progBarContainer');
var error_msg = '';
if(fcvar['size_error'])
{
var upload_size = format_filesize_with_unit(total_upload_size, ' ', force_MB, force_KB_size);
var upload_limit = format_filesize_with_unit(fcvar['size_limit'], ' ', force_MB, force_KB_size);
error_msg = '$TEXT{upload_too_big_error}';
error_msg = error_msg.replace(/%%upload_size%%/, upload_size);
error_msg = error_msg.replace(/%%limit%%/, upload_limit);
}
else // count_error.
{
error_msg = '$TEXT{upload_too_many_files_error}';
error_msg = error_msg.replace(/%%upload_count%%/, fcvar['total_file_count']);
error_msg = error_msg.replace(/%%limit%%/, fcvar['count_limit']);
}
document.getElementById('uploadDoneContainer').innerHTML = error_msg;
return;
}
else
{
var go = "";
if(fcvar['size_error'])
go = "$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_error}?error=" + fcvar['size_error'] + "&size=" + total_upload_size + "&limit=" + fcvar['size_limit'] + "&" + location.search.replace(/^\\?/, '');
else // count_error.
go = "$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_error}?error=" + fcvar['count_error'] + "&count=" + fcvar['total_file_count'] + "&limit=" + fcvar['count_limit'] + "&" + location.search.replace(/^\\?/, '');
return enc_js_redirect(go);
}
}
var completed_upload_size = fcvar['progress'];
var elapsedtime = fcvar['elapsed_time'];
var numfinishedfiles = fcvar['finished_file_count'];
var numtotalfiles = fcvar['total_file_count'];
var postprocessingdone = fcvar['ppd_status'];
if((postprocessingdone == 1) && document.getElementById('popup_status_window_enabled'))
window.close();
if(isNum(total_upload_size) && isNum(completed_upload_size) && isNum(elapsedtime) && isNum(numfinishedfiles) && isNum(numtotalfiles) && isNum(postprocessingdone) && (total_upload_size > 1))
{
hide_element('progBarPlaceholder');
hide_element('progBarError');
show_element('progBarContainer');
progress_bar_is_working = 1;
document.getElementById('progStatus').innerHTML = '$TEXT{Uploading_please_wait_}';
var newProgressPercent = Math.ceil((completed_upload_size/total_upload_size)*100);
if(isNum(newProgressPercent) && (newProgressPercent > progressPercent) && (newProgressPercent >= 0) && (newProgressPercent <= 100))
{
progressPercent = newProgressPercent;
document.getElementById('progPercent').innerHTML = progressPercent + '%';
document.title = progressPercent + '% Complete [Uploading]';
var newbarwidth = parseInt(progressPercent*$PREF{progress_bar_width}/100);
if(isNum(newbarwidth)) { increment_pb_width(newbarwidth); }
}
var totaltime = parseInt((elapsedtime * 100) / progressPercent);
var totaltime_forprint = format_timespan_with_unit(totaltime, ' ');
var remainingtime_forprint = format_timespan_with_unit(eval(totaltime - elapsedtime), ' ');
var elapsedtime_forprint = format_timespan_with_unit(elapsedtime, ' ');
var force_MB = total_upload_size > 999999 ? 1 : 0;
var total_upload_size_forprint = format_filesize_with_unit(total_upload_size, ' ', force_MB, force_KB_size);
var remaining_upload_size_forprint = format_filesize_with_unit(total_upload_size - completed_upload_size, ' ', force_MB, force_KB_size);
var completed_upload_size_forprint = format_filesize_with_unit(completed_upload_size, ' ', force_MB, force_KB_size);
var transfer_rate = format_filesize_with_unit(completed_upload_size/elapsedtime, ' ', force_MB, force_KB_rate);
if((completed_upload_size != "") && (completed_upload_size != 0) && (parseInt(completed_upload_size) >= parseInt(largest_completed_upload_size)))
{
// The largest_completed_upload_size check is necessary because sometimes weird stuff happens
// where the completed_upload_size actually *decreases* during an upload (notably at the end
// of uploads where disable_upload_hook is set to 'yes'), which results in screwed-up
// calculations here for the time values, etc.
if(document.getElementById('showprogtable'))
{
document.getElementById('donet').innerHTML = elapsedtime_forprint;
document.getElementById('dones').innerHTML = completed_upload_size_forprint;
document.getElementById('donef').innerHTML = numfinishedfiles;
document.getElementById('leftt').innerHTML = remainingtime_forprint;
document.getElementById('lefts').innerHTML = remaining_upload_size_forprint;
document.getElementById('leftf').innerHTML = numtotalfiles - numfinishedfiles;
document.getElementById('totalt').innerHTML = totaltime_forprint;
document.getElementById('totals').innerHTML = total_upload_size_forprint;
document.getElementById('totalf').innerHTML = numtotalfiles;
}
document.getElementById('progRate').innerHTML = transfer_rate + '/s';
}
if(progressPercent == 100)
{
hide_element('theMeter');
show_element('uploadCompleteMsg');
document.getElementById('uploadCompleteMsg').innerHTML = '$PREF{server_processing_upload_message}';
if(document.getElementById('showprogtable'))
{
document.getElementById('donet').innerHTML = totaltime_forprint;
document.getElementById('dones').innerHTML = total_upload_size_forprint;
document.getElementById('donef').innerHTML = numtotalfiles;
document.getElementById('leftt').innerHTML = '00:00:00';
document.getElementById('lefts').innerHTML = '0.0 $PREF{MB}';
document.getElementById('leftf').innerHTML = '0';
}
$PREF{custom_js_code__onuploaddone}
}
}
//check_for_upload_complete_message();
if(!upload_complete_process_started)
schedule_progressbar_update($PREF{progressbar_update_delay});
if(parseInt(completed_upload_size) > parseInt(largest_completed_upload_size))
largest_completed_upload_size = completed_upload_size;
}
else
{
if(document.getElementById('fcdebug'))
alert('Error: got a not-OK status code...');
// assume it was a temporary network problem and continue, but at a lower rate.
schedule_progressbar_update(5000);
}
}
}
}
function startupload(custvar)
{
// Note: we don't currently use custvar by default, but it's supported in case a client wants
// to use custom code in PREF{custom_js_code__onsubmit} that can then branch and hook back
// into itself, for example using enc_confirm() to present some kind of yes/no prompt, where
// a "no" would simply return false, but a "yes" would call startupload() as its callback and
// pass a value to bypass that enc_confirm() the second time.
if(custvar == undefined)
custvar = "";
if(check_if_onload_happened() && check_for_required_fields() && filenames_are_legal() && verify_that_new_passwords_match())
{
$PREF{custom_js_code__onsubmit}
if(document.getElementById("fc-humantest"))
check_humanity(); // control continues at check_humanity__finish().
// This probably needs to be the last thing we do before do_upload(), because Safari is delicate.
if(navigator.userAgent.indexOf("Safari") != -1)
kill_keepalive_to_work_around_safari_bug();
do_upload(); // called unconditionally; all checks within this block must either return false or use num_upload_checks_still_pending if they want to halt the upload.
}
else { return false; }
}
function check_if_onload_happened()
{
if(document.getElementById("onload_happened"))
{
if(document.getElementById("onload_happened").value == 1)
{
return true;
}
else
{
alert("Our onload actions did not run. You must remove any 'onload' attribute from your page's tag. See encodable.com/multiple_onload_events for details.");
return false;
}
}
}
function update_onload_status()
{
if(document.getElementById("onload_happened"))
document.getElementById("onload_happened").value = 1;
}
function generate_new_serial_number()
{
var theform = document.getElementById('theuploadform');
var juststatus = document.getElementById('fcjuststatus');
if(theform && !juststatus)
{
var new_serial = hex_sha1(get_random_text());
theform.action = theform.action.replace(/serial=\\w+/, 'serial=' + new_serial);
var juststatuslink = document.getElementById('juststatuslink');
if(juststatuslink)
juststatuslink.href = juststatuslink.href.replace(/serial=\\w+/, 'serial=' + new_serial);
}
}
function do_upload()
{
if(num_upload_checks_still_pending > 0)
return;
var file_present = document.getElementById('$PREF{filefield_namebase}1') && document.getElementById('$PREF{filefield_namebase}1').type == 'file' ? 1 : 0;
var uploadform = document.getElementById('theuploadform');
if(!document.getElementById('upload_progress_bar_disabled'))
{
if(file_present && document.getElementById('popup_status_window_enabled'))
{
$PREF{popup_status_window_javascript_code}
}
}
update_numitems();
uploadform.submit();
var upload_starttime_object = new Date();
upload_starttime_ms = upload_starttime_object.getTime();
document.getElementById('tca4').innerHTML = '$TEXT{Time} ';
if(file_present)
{
document.getElementById('$PREF{uploadbutton_id}').disabled = true;
show_element('progBarPlaceholder');
var names_div = document.getElementById('chosen_filenames');
if(names_div)
names_div.innerHTML = "$PREF{chosen_filenames_pretext}" + chosen_filenames.join("$PREF{chosen_filenames_separator}") + "$PREF{chosen_filenames_posttext}";
if(document.getElementById('popup_status_window_enabled'))
document.getElementById('progBarPlaceholder').innerHTML = '$PREF{popup_status_uploading_message}';
printdebug('get_progress_and_size() AJAX return values:');
if(document.getElementById('fcclearpage'))
{
hide_element('fcintro');
hide_element('theuploadform');
}
if(!document.getElementById('upload_progress_bar_disabled'))
{
if(!document.getElementById('popup_status_window_enabled'))
{
// this is in the parent window, not the popup.
var timeout = 1200;
var now = new Date();
window.setTimeout("do_progressbar_update('" + uploadform.action + "&action=ajax_get_progress&foo=" + now.getTime() + "')", timeout);
}
}
}
// 20111023: replaced this with show_upload_iframe_conents().
//check_for_upload_complete_interval_id = setInterval("check_for_upload_complete_message()", 2000);
}
function schedule_progressbar_update(timeout)
{
var now = new Date();
window.setTimeout("do_progressbar_update('" + document.getElementById('theuploadform').action + "&action=ajax_get_progress&foo=" + now.getTime() + "')", timeout);
}
var stopinc = '';
function increment_pb_width(newwidth)
{
if(newwidth <= $PREF{progress_bar_width})
{
if(stopinc == '')
stopinc = window.setInterval("inc_pb_width(" + newwidth + ")", 10);
else
window.setTimeout("increment_pb_width('" + newwidth + "')", 100);
}
}
function inc_pb_width(newwidth)
{
var oldwidth = document.getElementById('progBarDone').style.width;
oldwidth = oldwidth.replace(/px/,'');
if((oldwidth++) <= newwidth)
{
document.getElementById('progBarDone').style.width = (oldwidth++) + 'px';
}
else
{
window.clearInterval(stopinc);
stopinc = '';
document.getElementById('progBarDone').style.width = newwidth + 'px';
}
}
// 20111023: replaced this with show_upload_iframe_conents().
//function check_for_upload_complete_message()
//{
// if(document.getElementById('use_iframe_for_upload'))
// {
// var upload_complete_redirect_content = window.frames.fc_upload_iframe.document.getElementById('fc_afterupload_redirect');
// if(upload_complete_redirect_content && (upload_complete_redirect_content.length != upload_iframe_content_length))
// {
// upload_complete_process_started = 1;
// upload_iframe_content_length = upload_complete_redirect_content.length;
// clearInterval(check_for_upload_complete_interval_id);
// enc_js_redirect(upload_complete_redirect_content.value);
// }
//
// var upload_complete_page_content = window.frames.fc_upload_iframe.document.getElementById('fc_content');
// if(upload_complete_page_content && (upload_complete_page_content.length != upload_iframe_content_length))
// {
// upload_complete_process_started = 1;
// upload_iframe_content_length = upload_complete_page_content.length;
// clearInterval(check_for_upload_complete_interval_id);
//
// document.title = original_doc_title;
// hide_element('progBarPlaceholder');
// hide_element('progBarContainer');
// hide_element('progBarError');
// var newContent = upload_complete_page_content.cloneNode(true);
//
// // In case the iframe's content was slow-loading, causing this function to get called more than once:
// remove_all_children(document.getElementById("uploadDoneContainer"));
//
// if(navigator.userAgent.match(/MSIE (6|7)/))
// document.getElementById("uploadDoneContainer").innerHTML += newContent.innerHTML;
// else
// document.getElementById("uploadDoneContainer").appendChild(newContent);
//
// $PREF{custom_js_code__uploadcomplete_page}
// }
// }
//}
function show_upload_iframe_contents()
{
if(document.getElementById('use_iframe_for_upload'))
{
if(window.frames.fc_upload_iframe.location != 'about:blank') // skip the initial iframe load, when the upload form first loads.
{
var upload_complete_redirect_content = window.frames.fc_upload_iframe.document.getElementById('fc_afterupload_redirect');
if(upload_complete_redirect_content)
{
upload_complete_process_started = 1;
enc_js_redirect(upload_complete_redirect_content.value);
}
var fc_content_element = window.frames.fc_upload_iframe.document.getElementById('fc_content');
var upload_complete_page_content = fc_content_element || window.frames.fc_upload_iframe.document.body;
if(upload_complete_page_content)
{
upload_complete_process_started = 1;
document.title = original_doc_title;
hide_element('progBarPlaceholder');
hide_element('progBarContainer');
hide_element('progBarError');
var newContent = upload_complete_page_content.cloneNode(true);
// In case the iframe's content was slow-loading, causing this function to get called more than once:
// Update 20111023: this shouldn't be necessary anymore? But probably doesn't hurt in any case.
remove_all_children(document.getElementById("uploadDoneContainer"));
if(navigator.userAgent.match(/MSIE (6|7)/))
document.getElementById("uploadDoneContainer").innerHTML += newContent.innerHTML;
else
document.getElementById("uploadDoneContainer").appendChild(newContent);
$PREF{custom_js_code__uploadcomplete_page}
}
}
}
}
function reset_iframe_location()
{
if(document.getElementById('use_iframe_for_upload'))
{
//window.frames.fc_upload_iframe.document.getElementById('fc_content').innerHTML = "";
window.frames.fc_upload_iframe.location = 'about:blank';
}
}
function reset_upload_form_after_size_or_count_error()
{
var inputs = document.getElementById('theuploadform').getElementsByTagName('input');
for(i = 0; i < inputs.length; i++)
{
var re = new RegExp("^file\$", "i");
if(inputs[i].type.match(re))
inputs[i].value = '';
}
upload_cancelled = 0;
document.getElementById('$PREF{uploadbutton_id}').disabled = false;
remove_all_children(document.getElementById("uploadDoneContainer"));
show_element('fcintro');
show_element('theuploadform');
}
function remove_all_children(element)
{
while (element.firstChild)
{
element.removeChild(element.firstChild);
}
}
function hide_element(elname)
{
var theel = document.getElementById(elname);
if(theel)
{
theel.style.position = 'absolute';
theel.style.left = '-8000px';
theel.style.overflow = 'hidden';
theel.style.height = '0px'; // 20110506: changed from '0' to '0px'; shouldn't break anything, but keep an eye on it.
//theel.style.display = 'none'; // display:none on the upload form will cause Safari to fail to upload the file(s).
if(theel.getElementsByClassName)
{
// In case there are any required inputs that are currently hidden, they shouldn't block submission.
var required_inputs = theel.getElementsByClassName('required');
for(var i=0; i ' + msg + ' ';
}
function enc_js_redirect(gotoURL)
{
if(document.getElementById('popup_status_window_enabled'))
{
window.opener.location.href = gotoURL;
window.close();
return null;
}
else
{
location.href = gotoURL;
}
}
function startorder()
{
var inputs = document.getElementById('theorderform').getElementsByTagName('input');
var missing = 0;
var i = 0;
for(i = 0; i < inputs.length; i++)
{
if(inputs[i].className.indexOf('required') != -1 && (inputs[i].value == '' || inputs[i].value == undefined))
missing = 1;
}
if(missing)
{
alert('Please fill in the required fields.');
}
else
{
document.getElementById('theorderform').submit();
}
}
function itemactions_verify()
{
var action = document.getElementById("actiontodo").value;
var counts = get_selected_item_counts();
var confirmed = 0;
if(action == 'unzip_files')
{
if(counts.files_selected) { confirmed = window.confirm("$TEXT{Selected_} " + counts.files_selected + " $TEXT{files}. $TEXT{Unzip_now_}"); }
else { alert("No files selected."); }
}
else if(action.indexOf('rotate_images') != -1)
{
if(counts.files_selected) { confirmed = window.confirm("$TEXT{Selected_} " + counts.files_selected + " $TEXT{images}. $TEXT{Rotate_now_}"); }
else { alert("No files selected."); }
}
else if(action == 'delete_items')
{
if(counts.files_selected || counts.dirs_selected) { confirmed = window.confirm("$TEXT{Selected_} " + counts.files_selected + " $TEXT{files} $TEXT{and} " + counts.dirs_selected + " $TEXT{folders}. $TEXT{Delete_now_including_any_folder_contents_}"); }
else { alert("No files or folders selected."); }
}
else if(action == 'multidownload')
{
if(counts.single_file_id) { enc_js_redirect(document.getElementById(counts.single_file_id).href); return false; }
if(counts.files_selected || counts.dirs_selected) { confirmed = window.confirm("$TEXT{multidownload_warning}"); }
else { alert("No files or folders selected."); }
}
else if(action == 'reprocess_items')
{
reprocess_items();
}
else if(action == 'copy_items' || action == 'move_items')
{
if(!(counts.files_selected || counts.dirs_selected)) { alert("No files or folders selected."); }
else if(!document.getElementById('copymovedest').value) { alert("No destination selected."); }
else { confirmed = 1; }
}
if(confirmed)
{
var action_attribute = document.getElementById("itemactions").action;
action_attribute = action_attribute.replace(/action=\\w+/, 'action='+action);
document.getElementById("itemactions").action = action_attribute;
document.getElementById('itemactions').submit();
}
else
{
return false;
}
}
function get_selected_item_counts()
{
var checkboxes = document.getElementById("itemactions").getElementsByTagName("input");
var dirs_selected = 0;
var files_selected = 0;
var total_selected = 0;
var single_file_name = '';
for(i = 0; i < checkboxes.length; i++)
{
if(checkboxes[i].checked)
{
total_selected++;
if(checkboxes[i].name.match(/^dir-/))
{
dirs_selected++;
}
else if(checkboxes[i].name.match(/^file-/))
{
files_selected++;
var matches = checkboxes[i].name.match(/^file-(.+)/);
single_file_name = matches[1];
}
}
}
var single_file_id = '';
if(files_selected == 1 && dirs_selected == 0)
{
single_file_id = 'fclink-' + single_file_name.replace(/\\W/g, '');
}
return { dirs_selected : dirs_selected, files_selected : files_selected, total_selected : total_selected, single_file_id : single_file_id };
}
function check_for_required_fields()
{
var onlyinputs = document.getElementById('theuploadform').getElementsByTagName('input');
var selects = document.getElementById('theuploadform').getElementsByTagName('select');
var textareas = document.getElementById('theuploadform').getElementsByTagName('textarea');
var inputs = new Array;
for(var i = 0; i < onlyinputs.length; i++)
inputs[inputs.length] = onlyinputs[i];
for(var i = 0; i < selects.length; i++)
inputs[inputs.length] = selects[i];
for(var i = 0; i < textareas.length; i++)
inputs[inputs.length] = textareas[i];
var items_missing = 0;
var email_format_incorrect = 0;
var alpha_format_incorrect = 0;
var numeric_format_incorrect = 0;
var alphanum_format_incorrect = 0;
for(var i = 0; i < inputs.length; i++)
{
if(inputs[i].className.indexOf('required') != -1)
{
var formfield_group___array = inputs[i].className.match(/(formfield_\\d+)/);
var formfield_group = formfield_group___array ? formfield_group___array[1] : '';
if(inputs[i].type == 'radio' && document.getElementsByClassName && radio_group_is_unchecked(document.getElementsByClassName(formfield_group)))
{
mark_input_error(inputs[i].parentNode, 'input_error_reqd');
items_missing = 1;
}
else if(inputs[i].type == 'checkbox' && !inputs[i].checked)
{
mark_input_error(inputs[i], 'input_error_reqd');
items_missing = 1;
}
else if(inputs[i].value == '' || inputs[i].value == undefined)
{
mark_input_error(inputs[i], 'input_error_reqd');
items_missing = 1;
}
else
{
if(inputs[i].type == 'radio')
unmark_input_error(inputs[i].parentNode, 'input_error_reqd');
else
unmark_input_error(inputs[i], 'input_error_reqd');
}
}
if(inputs[i].className.indexOf('emailformat') != -1)
{
if(inputs[i].value.length > 0 && !inputs[i].value.match( /.+\@.+\\..+/ ))
{
mark_input_error(inputs[i], 'input_error_email');
email_format_incorrect = 1;
}
else
unmark_input_error(inputs[i], 'input_error_email');
}
if(inputs[i].className.indexOf('numeric') != -1)
{
if(!inputs[i].value.match( /^\\d+\$/ ))
{
mark_input_error(inputs[i], 'input_error_num');
numeric_format_incorrect = 1;
}
else
unmark_input_error(inputs[i], 'input_error_num');
}
if(inputs[i].className.indexOf('alphabetic') != -1)
{
if(!inputs[i].value.match( /^[a-z]*\$/i ))
{
mark_input_error(inputs[i], 'input_error_alpha');
alpha_format_incorrect = 1;
}
else
unmark_input_error(inputs[i], 'input_error_alpha');
}
if(inputs[i].className.indexOf('alphanum') != -1)
{
if(!inputs[i].value.match( /^[a-z0-9]*\$/i ))
{
mark_input_error(inputs[i], 'input_error_alphanum');
alphanum_format_incorrect = 1;
}
else
unmark_input_error(inputs[i], 'input_error_alphanum');
}
}
if(items_missing)
alert("$TEXT{Please_fill_in_the_required_items_}");
else if(email_format_incorrect)
alert("$TEXT{Please_enter_a_valid_email_address_}");
else if(alpha_format_incorrect)
alert("$TEXT{Please_enter_only_letters_}");
else if(numeric_format_incorrect)
alert("$TEXT{Please_enter_a_number_}");
else if(alphanum_format_incorrect)
alert("$TEXT{Please_enter_only_letters_and_numbers_}");
else
return 1;
return 0;
}
function mark_input_error(the_el, the_err)
{
if(the_el.className.indexOf(the_err) == -1)
the_el.className += ' ' + the_err;
}
function unmark_input_error(the_el, the_err)
{
the_el.className = the_el.className.replace(new RegExp(the_err,'g'), '');
}
function radio_group_is_unchecked(radio_group_list)
{
var checked = 0;
for(var i = 0; i < radio_group_list.length; i++)
if(radio_group_list[i].checked)
checked = 1;
return !checked;
}
function filenames_are_legal()
{
var inputs = document.getElementById('theuploadform').getElementsByTagName('input');
for(i = 0; i < inputs.length; i++)
{
if(inputs[i].type == 'file' && !(inputs[i].value == '' || inputs[i].value == undefined))
{
var filename__array = inputs[i].value.match(/([^\\/\\\\]+)\$/);
var filename = filename__array[1];
var this_files_extension__array = filename.match(/.*(\\..+)\$/);
var this_files_extension = this_files_extension__array ? this_files_extension__array[1] : '';
var illegal = 0;
var only_allow_these_file_extensions = "$PREF{only_allow_these_file_extensions}";
if(only_allow_these_file_extensions)
{
if(!this_files_extension)
illegal = 1;
var extension_is_in_allowed_list = 0;
var allowed_extensions = only_allow_these_file_extensions.split(" ");
for(j = 0; j < allowed_extensions.length; j++)
{
if(this_files_extension.toLowerCase() == allowed_extensions[j].toLowerCase())
extension_is_in_allowed_list = 1;
}
if(!extension_is_in_allowed_list)
illegal = 1;
}
var disallow_these_file_extensions = "$PREF{disallow_these_file_extensions}";
if(disallow_these_file_extensions)
{
var extension_is_in_disallowed_list = 0;
var disallowed_extensions = disallow_these_file_extensions.split(" ");
for(j = 0; j < disallowed_extensions.length; j++)
{
if(this_files_extension.toLowerCase() == disallowed_extensions[j].toLowerCase())
extension_is_in_disallowed_list = 1;
}
if(extension_is_in_disallowed_list)
illegal = 1;
}
var disallow_these_strings_within_filenames = "$PREF{disallow_these_strings_within_filenames___for_js}";
if(disallow_these_strings_within_filenames)
{
var name_contains_disallowed_string = 0;
var disallowed_strings = disallow_these_strings_within_filenames.split(" ");
for(j = 0; j < disallowed_strings.length; j++)
{
var re = new RegExp(disallowed_strings[j], "i");
if(filename.match(re))
name_contains_disallowed_string = 1;
}
if(name_contains_disallowed_string)
illegal = 1;
}
if(("$PREF{allow_files_without_extensions}" == "no") && !this_files_extension)
{
illegal = 1;
}
if(!filename.match(/[0-9A-Za-z]/))
illegal = 1;
if(illegal)
{
var message = "$TEXT{illegal_filename_message}";
message = message.replace(/%%filename%%/, filename);
alert(message);
return false;
}
}
}
return true;
}
function format_filesize_with_unit(num,space,forceMB,forceKB)
{
if(!isNum(num,1)) { return "?" + space + "$PREF{KB}"; }
var unit;
if( ((num > 999999) || forceMB) && !forceKB)
{
num = num/(1024*1024);
num = num.toString();
var testnum = num.replace( /^(\\d+\\.\\d).*/, '\$1' ); // show 1 decimal place. // extra escaping b/c printing JS from Perl.
if(testnum == '0.0')
{
testnum = num.replace( /^(\\d+\\.\\d\\d).*/, '\$1' ); // show 2 decimal places.
}
if(testnum == '0.00')
{
testnum = num.replace( /^(\\d+\\.\\d\\d\\d).*/, '\$1' ); // show 3 decimal places.
}
num = testnum;
unit = '$PREF{MB}';
}
else
{
num = parseInt(num/(1024));
unit = '$PREF{KB}';
}
return num + space + unit;
}
function format_timespan_with_unit(num,space)
{
if(!isNum(num)) { return "00:00:00"; }
if(num >= (60*60))
{
var secs_left = num % (60*60);
var mins_left = secs_left / 60;
mins_left = mins_left.toString();
mins_left = mins_left.replace( /^(\\d+)\\..*/, '\$1' ); // show no decimal places. // extra escaping b/c printing JS from Perl.
mins_left = mins_left.replace( /^(\\d)\$/, '0\$1' ); // for single-digits, prepend a zero.
num = num/(60*60);
num = num.toString();
num = num.replace( /^(\\d+)\\..*/, '\$1' ); // show no decimal places.
num = num + ':' + mins_left + ':00';
}
else if(num >= 60)
{
var secs_left = num % 60;
secs_left = secs_left.toString().replace( /^(\\d)\$/, '0\$1' ); // for single-digits, prepend a zero.
num = num/60;
num = num.toString();
num = num.replace( /^(\\d+)\\..*/, '\$1' ); // show no decimal places. // extra escaping b/c printing JS from Perl.
num = num.replace( /^(\\d)\$/, '0\$1' ); // for single-digits, prepend a zero.
num = '00:' + num + ':' + secs_left;
}
else
{
num = num.toString();
num = num.replace( /^(\\d+)\\..*/, '\$1' ); // show no decimal places. // extra escaping b/c printing JS from Perl.
num = num.replace( /^(\\d)\$/, '0\$1' ); // for single-digits, prepend a zero.
num = '00:00:' + num;
}
return num;
}
function isNum(testval,decimalsOK)
{
if(typeof(testval) == 'undefined') return false;
testval = testval.toString();
if (!testval.length) return false;
var numbers = decimalsOK ? '.0123456789' : '0123456789';
for (i=0; i