#!/usr/bin/perl # MimerDesk # Web based groupware and eLearning environment # www.mimerdesk.org # # Copyright (C) 2001 Ionstream Ltd. # www.ionstream.fi # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your option) # any later version. # # This program is distributed with a hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # $Id: files.html,v 1.292 2002/07/18 11:44:49 inf Exp $ #"""""""""""""""""""""""""""""""""""""""""# # # # MimerDesk: Resources - Files # # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # (c) Ionstream Oy 1999 - 2001 # # # # Main programming by: Jyrki Muukkonen # # MimerDesk integration and additional # # programming by: Teemu Arina # # Modifications by: Hannes Muurinen # # # #_________________________________________# use Fcntl ':flock'; # import LOCK_* constants use File::Copy; use File::Find; use File::Path qw(rmtree); use strict; # gotta luv da strict use vars qw ($ACTIVEGRP $APPLICATION $USER $IP $REVISIONLOG $ADMIN_RIGHTS $LAST_ACT $FORWARDED $GROUPACTIVOR $ROOTDIR $GRPNAME $ENABLE_STREAMING $TIME_USED $IDLE $FILETYPE_CHECK $form $ref $sth $htmlcolors $USED_QUOTA $QUOTA @mp3_genres $trans $CRLF $FILEDESCS $FILERIGHTS); use lib::MimerDesk; # File actions # Directory actions sub view_file; sub stream_all_mp3; sub download_file; sub create_dir; sub delete_file; sub rename_directory; sub stream_selected_mp3; sub show_category; sub upload_file; sub send_zip_archive; sub rename_file; sub send_gz_archive; sub edit_file; sub edit_tag; sub save_new_version; sub lock_file; sub unlock_file; sub check_lock; # Misc # Descriptions sub do_output; sub del_description; sub human_readable; sub get_description; sub do_output_files; sub add_description; sub do_output_filesedit; sub do_output_fileseditor; sub do_output_editdir; sub do_output_renamedir; sub do_output_mp3tagedit; sub do_output_newrevision; sub do_output_renamefile; ######################### # Settings # ######################### read_config('../config/mimerdesk.cfg'); $APPLICATION = 'Personal - Files'; my %filepics = ( default => 'rf-default.gif', # Images # Sounds jpg => 'rf-image.gif', wav => 'rf-audio.gif', gif => 'rf-image.gif', au => 'rf-audio.gif', png => 'rf-image.gif', aiff => 'rf-audio.gif', pcx => 'rf-image.gif', aif => 'rf-audio.gif', bmp => 'rf-image.gif', snd => 'rf-audio.gif', tiff => 'rf-image.gif', raw => 'rf-audio.gif', tif => 'rf-image.gif', xm => 'rf-audio.gif', tga => 'rf-image.gif', s3m => 'rf-audio.gif', xpm => 'rf-image.gif', it => 'rf-audio.gif', psd => 'rf-ps.gif', midi => 'rf-midi.gif', cdr => 'rf-corel.gif', mid => 'rf-midi.gif', cfl => 'rf-corel.gif', mp3 => 'rf-mp3.gif', bpt => 'rf-corel.gif', pls => 'rf-mp3.gif', cmv => 'rf-corel.gif', rd3 => 'rf-corel.gif', shw => 'rf-corel.gif', # Documents # Sourcecode html => 'rf-webdoc.gif', c => 'rf-source.gif', htm => 'rf-webdoc.gif', pl => 'rf-source.gif', xml => 'rf-webdoc.gif', py => 'rf-source.gif', css => 'rf-webdoc.gif', java => 'rf-source.gif', pdf => 'rf-acrobat.gif', sh => 'rf-source.gif', sgml => 'rf-text.gif', jar => 'rf-source.gif', latex => 'rf-text.gif', hxx => 'rf-source.gif', tex => 'rf-text.gif', h => 'rf-source.gif', lyx => 'rf-text.gif', hpp => 'rf-source.gif', txt => 'rf-text.gif', cpp => 'rf-source.gif', faq => 'rf-text.gif', cxx => 'rf-source.gif', nfo => 'rf-text.gif', js => 'rf-source.gif', ps => 'rf-acrobat.gif', awk => 'rf-source.gif', doc => 'rf-doc.gif', cfm => 'rf-source.gif', rtf => 'rf-rtf.gif', asm => 'rf-source.gif', xls => 'rf-xls.gif', pm => 'rf-source.gif', ppt => 'rf-ppt.gif', pps => 'rf-ppt.gif', ksp => 'rf-xls.gif', swf => 'rf-flash.gif', # Packages # Video zip => 'rf-zip.gif', ram => 'rf-real.gif', rar => 'rf-zip.gif', ra => 'rf-real.gif', arj => 'rf-zip.gif', avi => 'rf-video.gif', gz => 'rf-zip.gif', mpg => 'rf-video.gif', tar => 'rf-zip.gif', mpeg => 'rf-video.gif', bz2 => 'rf-zip.gif', mov => 'rf-video.gif', ace => 'rf-zip.gif', vfw => 'rf-video.gif', tgz => 'rf-zip.gif', # Other exe => 'rf-app.gif', class => 'rf-app.gif', com => 'rf-app.gif', bat => 'rf-app.gif', ini => 'rf-ini.gif', cfg => 'rf-ini.gif', mmp => 'rf-visio.gif', vss => 'rf-visio.gif', vsd => 'rf-visio.gif', vsw => 'rf-visio.gif', plt => 'rf-autocad.gif', ); my %fmconfig = ( resourceroot => $config{'file_dir'}, # directory for files mimetypes => $config{'misc'}."/rf-mime.types", # mime types imagedir => $config{'loc_pictures'} ); $fmconfig{'imagedir'} =~ s/([^\/]*)$//; $fmconfig{'imagedir'} .= 'files'; my ($category); my ($detection) = split / /, $config{'file_detect'}; my $FILETYPE_CHECK = (-e $detection); $ENABLE_STREAMING = 1 if eval 'require MP3::Info'; ######################### # Initialize # ######################### # # 1. initialize # 2. read parameters # $htmlcolors = initialize('colors'); $form = decode_multipart(); $form->{'ID'} =~ tr/0-9//cd; $form->{'auth'} =~ tr/0-9a-z//cd; ($USER, $IP, $LAST_ACT, $FORWARDED, $TIME_USED, $IDLE, $ACTIVEGRP) = authenticate($form->{'ID'}, $form->{'auth'}, $form->{'changeGroup'}); if ($form->{'quit'}) {redirect("$config{'loc_server'}$config{'bin_dir'}/index.html?ID=$form->{'ID'}&auth=$form->{'auth'}&quit=quit");} $trans = lib::MimerDesk->new_gettext(program => 'files',language => $config{'language'}); $APPLICATION = $trans->gettext('Personal - Files'); $FILEDESCS = 'filedescs'; $FILERIGHTS = 'filerights'; $REVISIONLOG = 'revisionlog'; if ($form->{'grouptool'} =~ /^\d+$/) { my ($test); lock_tables('READ', 'groupusers','groups'); db_list("SELECT groupusers.RIGHTS,groups.QUOTA,groupusers.USER,groups.GRPNAME FROM groupusers,groups where groupusers.USER = '$USER' and groupusers.GID = '$form->{'grouptool'}' and groupusers.GID = groups.GID"); while (my $ref = $sth->fetchrow_hashref()) { $ADMIN_RIGHTS = $ref->{'RIGHTS'}; $GROUPACTIVOR = $ref->{'USER'}; $GRPNAME = $ref->{'GRPNAME'}; $QUOTA = $ref->{'QUOTA'}; } db_end(); unlock_tables(); if ($GROUPACTIVOR) { $fmconfig{'resourceroot'} .= '/groups/'.$form->{'grouptool'}; $ROOTDIR = 'groups/'.$GRPNAME; $FILERIGHTS = $form->{'grouptool'}.'_'.$FILERIGHTS; $FILEDESCS = $form->{'grouptool'}.'_'.$FILEDESCS; $REVISIONLOG = $form->{'grouptool'}.'_'.$REVISIONLOG; } else { $fmconfig{'resourceroot'} .= '/users/'.$USER; $ROOTDIR = 'users/ '.$USER; lock_tables('READ','users'); db_list("select quota from users where nimi = '$USER'"); ($QUOTA) = $sth->fetchrow_array(); db_end(); unlock_tables(); } } else { $fmconfig{'resourceroot'} .= '/users/'.$USER; $ROOTDIR = 'users/'.$USER; lock_tables('READ','users'); db_list("select quota from users where nimi = '$USER'"); ($QUOTA) = $sth->fetchrow_array(); db_end(); unlock_tables(); } ######################### # Main program # ######################### # # 1. If users directory doesn't exist create it # 2. Calculate used quota # 3. Security check category # 4. Security check file # 5. If cancel pressed Return to filelist # 6. If upload pressed upload file # 7. If make directory pressed create category # 8. If delete pressed delete file or directory # 9. If edit pressed check if show or update mode activated and process # 10. If file chosen but above failed view or download file # 11. If everything else failed show category if ($form->{'filename'} && !$form->{'upload2'} && !$form->{'save_newrevision'} ) { unlink $form->{'filename'}; } unless (-d $fmconfig{'resourceroot'}) { mkdir $fmconfig{'resourceroot'}, 0700 or write_log("Cannot create directory $fmconfig{'resourceroot'}. $!"); } find(sub {if (-f) {$USED_QUOTA += -s if $_ !~ /^\./;}}, "$fmconfig{'resourceroot'}"); if ($form->{'cat'}) { $category = $form->{'cat'}; while ($category =~ s/\.\.//gm) {} $category =~ s/^\.//; $category =~ s/\n//gm; $category =~ s{/+}{/}gm; $category .= '/' unless $category =~ m{/$}; $category = '/'.$category unless $category =~ m{^/}; unless (-d "$fmconfig{'resourceroot'}$category") { my $nodir = $category; $category = '/'; do_output("$config{'theme'}_files",show_category($category), sprintf($trans->gettext('Directory /%s%s does not exist!'),$ROOTDIR,$nodir), 'error'); } } else {$category = '/';} if ($form->{'dl'}) { $form->{'dl'} =~ s/(<|>|\||\*|\/|\\|\?|\:|\"|\')//g; $form->{'dl'} =~ s/^\.//; $form->{'dl'} =~ s/\n//gm; $form->{'dl'} =~ s/\.\.//gm; unless (-e "$fmconfig{'resourceroot'}$category$form->{'dl'}") { my $nofile = $form->{'dl'}; delete $form->{'dl'}; do_output("$config{'theme'}_files",show_category($category), sprintf($trans->gettext('File /%s%s%s does not exist!'),$ROOTDIR,$category,$nofile), 'error'); } } if ($form->{'cancel'}) {do_output("$config{'theme'}_files", show_category($category));} elsif ($form->{'doaction'}) { my (@items); for (my $n = 1;$n <= $form->{'numofcheckboxes'};$n++) { $form->{'checkb'.$n} =~ s/(<|>|\||\*|\/|\\|\?|\:|\"|\')//g; $form->{'checkb'.$n} =~ s/^\.//; $form->{'checkb'.$n} =~ s/\.\.//gm; push @items, $form->{'checkb'.$n} if $form->{'checkb'.$n}; } unless (@items) { do_output("$config{'theme'}_files", show_category($category), $trans->gettext('No files or folders selected!'),'error'); } if ($form->{'fileaction'} eq 'delete') { my $lock; foreach (@items) { if ($lock = check_lock($category, $_) ) { do_output("$config{'theme'}_files", show_category($category), sprintf($trans->gettext('File %s has been locked. You cannot perform an action on the file until the lock has been released.'),$_),'error'); } delete_file($category, $_); } do_output("$config{'theme'}_files", show_category($category), $trans->gettext('Selected files and folders deleted successfully.'),'success'); } elsif ($form->{'fileaction'} eq 'copy') {} elsif ($form->{'fileaction'} eq 'move') {} elsif ($form->{'fileaction'} eq 'downloadgz') { unless (eval 'require Compress::Zlib') { do_output("$config{'theme'}_files", show_category($category), sprintf($trans->gettext('Perl module %s not installed!'), 'Compress::Zlib'),'error'); } unless (eval 'require Archive::Tar') { do_output("$config{'theme'}_files", show_category($category), sprintf($trans->gettext('Perl module %s not installed!'), 'Archive::Tar'),'error'); } send_gz_archive($category, \@items); } elsif ($form->{'fileaction'} eq 'downloadzip') { unless (eval 'require Compress::Zlib') { do_output("$config{'theme'}_files", show_category($category), sprintf($trans->gettext('Perl module %s not installed!'), 'Compress::Zlib'),'error'); } unless (eval 'require Archive::Zip') { do_output("$config{'theme'}_files", show_category($category), sprintf($trans->gettext('Perl module %s not installed!'), 'Archive::Zip'),'error'); } send_zip_archive($category, \@items); } elsif ($form->{'fileaction'} eq 'stream_selected_mp3') { stream_selected_mp3($category, \@items); } } elsif ($form->{'upload2'}) { upload_file(); do_output("$config{'theme'}_files",show_category($category), sprintf($trans->gettext('%s uploaded.'),$form->{'filename','tiedostonimi'}), 'success'); } elsif ($form->{'makedir'}) { $form->{'dirname'} =~ s/([\&;\`'\\\|"*?~<>^\(\)\[\]\{\}\$\n\r])//g; $form->{'dirname'} =~ s/\0//g; # Remove poison NULL bytes create_dir($category, $form->{'dirname'}); do_output("$config{'theme'}_files",show_category($category), sprintf($trans->gettext('Directory /%s%s created.'),$ROOTDIR,"$category$form->{'dirname'}"), 'success'); } elsif ($form->{'newfile'}) { do_output("$config{'theme'}_uploadfile",show_category($category)); } elsif ($form->{'newdir'}) { do_output("$config{'theme'}_createfolder",show_category($category)); } elsif ($form->{'download'}) { download_file($category, $form->{'dl'}); } elsif ($form->{'view'}) { view_file($category, $form->{'dl'}); } elsif ($form->{'stream'}) { stream_selected_mp3($category, [$form->{'dl'}]); } elsif ($form->{'stream_all'}) { stream_all_mp3($category); } elsif ($form->{'edit_file'}) { do_output("$config{'theme'}_fileseditor",show_category($category)); } elsif ($form->{'edit_tag'}) { do_output("$config{'theme'}_mp3tagedit",show_category($category)); } elsif ($form->{'edit_desc'}) { do_output("$config{'theme'}_editdesc",show_category($category)); } elsif ($form->{'edit_dirdesc'}) { do_output("$config{'theme'}_editdir",show_category($category)); } elsif ($form->{'rename_dir'}) { do_output("$config{'theme'}_renamedir",show_category($category)); } elsif ($form->{'rename_file'}) { do_output("$config{'theme'}_renamefile",show_category($category)); } elsif ($form->{'new_revision'}) { do_output("$config{'theme'}_newrevision",show_category($category)); } elsif ($form->{'lock_file'}) { my $ref = get_description($category, $form->{'dl'}); lock_tables('READ', $FILEDESCS); my ($locked) = db_select('LOCKED',$FILEDESCS,"FID = '$ref->{'FID'}'"); unlock_tables(); do_output("$config{'theme'}_filesedit", show_category($category), sprintf($trans->gettext('File %s has been locked. You cannot perform an action on the file until the lock has been released.'),$form->{'dl'}),'error') if $locked->{'LOCKED'}; lock_file($category, $form->{'dl'}), do_output("$config{'theme'}_filesedit", show_category($category), $trans->gettext("You have locked the file. Other users are not permitted to make modifications to the file until the file lock has been released."),'success'); } elsif ($form->{'unlock_file'}) { my $ref = get_description($category, $form->{'dl'}); lock_tables('READ','users', $FILEDESCS); my ($user) = db_select('UID','users',"nimi = '$USER'"); my ($locked) = db_select('LOCKED',$FILEDESCS,"FID = '$ref->{'FID'}'"); unlock_tables(); do_output("$config{'theme'}_filesedit", show_category($category), sprintf($trans->gettext('File %s has been locked. You cannot perform an action on the file until the lock has been released.'),$form->{'dl'}),'error') if ($user->{'UID'} ne $locked->{'LOCKED'} && $ADMIN_RIGHTS !~ /F0/); unlock_file($category, $form->{'dl'}), do_output("$config{'theme'}_filesedit", show_category($category), $trans->gettext('You have unlocked the file. Users are now permitted to make modifications to the file.'),'success'); } elsif ($form->{'save_newrevision'}) { do_output("$config{'theme'}_filesedit", show_category($category), sprintf($trans->gettext('File %s has been locked. You cannot perform an action on the file until the lock has been released.'),$form->{'dl'}),'error') if check_lock($category, $form->{'dl'}); my $version = save_new_version($category, $form->{'dl'}); do_output("$config{'theme'}_filesedit", show_category($category), sprintf($trans->gettext('Uploaded new revision of file %s. New version number is %s.'),$form->{'dl'}, $version),'success'); } elsif ($form->{'save_edit'}) { do_output("$config{'theme'}_filesedit", show_category($category), sprintf($trans->gettext('File %s has been locked. You cannot perform an action on the file until the lock has been released.'),$form->{'dl'}),'error') if check_lock($category, $form->{'dl'}); edit_file($category, $form->{'dl'}, $form->{'file_content'}); do_output("$config{'theme'}_filesedit", show_category($category), sprintf($trans->gettext('/%s%s%s edited.'),$ROOTDIR,$category,$form->{'dl'}),'success'); } elsif ($form->{'save_tag'}) { do_output("$config{'theme'}_filesedit", show_category($category), sprintf($trans->gettext('File %s has been locked. You cannot perform an action on the file until the lock has been released.'),$form->{'dl'}),'error') if check_lock($category, $form->{'dl'}); edit_tag($category, $form->{'dl'}); do_output("$config{'theme'}_filesedit", show_category($category), sprintf($trans->gettext('/%s%s%s edited.'),$ROOTDIR,$category,$form->{'dl'}),'success'); } elsif ($form->{'save_desc'}) { do_output("$config{'theme'}_filesedit", show_category($category), sprintf($trans->gettext('File %s has been locked. You cannot perform an action on the file until the lock has been released.'),$form->{'dl'}),'error') if check_lock($category, $form->{'dl'}); my $ref = get_description($category, $form->{'dl'}); add_description($category, $form->{'dl'}, { FID => $ref->{'FID'}, DESCRIPTION => prepare_fordb($form->{'file_desc'}) } ); do_output("$config{'theme'}_filesedit", show_category($category), sprintf($trans->gettext('/%s%s%s edited.'),$ROOTDIR,$category,$form->{'dl'}),'success'); } elsif ($form->{'save_dirdesc'}) { my $ref = get_description($category, $form->{'catdir'}); add_description($category, $form->{'dl'}, { FID => $ref->{'FID'}, DESCRIPTION => prepare_fordb($form->{'dirdesc'}) } ); do_output("$config{'theme'}_files", show_category($category), sprintf($trans->gettext('/%s%s%s edited.'),$ROOTDIR,$category,$form->{'catdir'}),'success'); } elsif ($form->{'save_renamedir'}) { unless ($form->{'rename_field'}) { do_output("$config{'theme'}_renamedir", show_category($category), $trans->gettext('You must enter a directory name!'), 'error'); } my $renamed = rename_directory($category, $form->{'catdir'}, $form->{'rename_field'}); unless ($renamed) { do_output("$config{'theme'}_files", show_category($category), sprintf($trans->gettext('Error renaming directory %s as %s!'),$form->{'catdir'},$form->{'rename_field'}), 'error'); } my $olddir = $form->{'catdir'}; $form->{'catdir'} = $renamed; do_output("$config{'theme'}_files", show_category($category), sprintf($trans->gettext('Directory %s renamed as %s.'),$olddir,$renamed), 'success'); } elsif ($form->{'rename'}) { do_output("$config{'theme'}_filesedit", show_category($category), sprintf($trans->gettext('File %s has been locked. You cannot perform an action on the file until the lock has been released.'),$form->{'dl'}),'error') if check_lock($category, $form->{'dl'}); unless ($form->{'rename_field'}) { do_output("$config{'theme'}_filesedit", show_category($category), $trans->gettext('You must enter a filename!'), 'error'); } my $renamed = rename_file($category, $form->{'dl'}, $form->{'rename_field'}); unless ($renamed) { do_output("$config{'theme'}_filesedit", show_category($category), sprintf($trans->gettext('Error renaming file %s as %s!'),$form->{'dl'},$form->{'rename_field'}), 'error'); } my $oldfile = $form->{'dl'}; $form->{'dl'} = $renamed; do_output("$config{'theme'}_filesedit", show_category($category), sprintf($trans->gettext('File %s renamed as %s.'),$oldfile,$renamed), 'success'); } elsif ($form->{'edit'}) { if ($form->{'cd'}) {do_output("$config{'theme'}_files", show_category($category));} else {do_output("$config{'theme'}_filesedit", show_category($category));} } else {do_output("$config{'theme'}_files", show_category($category));} ######################### # Upload file # ######################### # # 1. Security check filename # 2. If file not chosen return error # 3. If file already exists return error # 4. If quota exceeded return error # 5. If copy doesn't succeed return error # 6. Get file size and date # 7. Insert record into filedescs database # 8. Update used quota # 9. Remove temporary file and return sub upload_file { my ($mode,$value); $form->{'filename','tiedostonimi'} =~ s{/}{}gm; $form->{'filename','tiedostonimi'} =~ s/(<|>|\||\*|\/|\\|\?|\:|\"|\')//g; while ($form->{'filename','tiedostonimi'} =~ s/\.\./\./gm) {} $form->{'filename','tiedostonimi'} =~ s/^\.+//; if (!$form->{'filename','tiedostonimi'}) { unlink($form->{'filename'}) or write_log("$USER: Cannot remove file $form->{'filename'}. $!", 'error'); do_output("$config{'theme'}_files", show_category($category), $trans->gettext('You must select a file to upload.'), 'error'); } if (-e "$fmconfig{'resourceroot'}$category$form->{'filename','tiedostonimi'}") { unlink($form->{'filename'}) or write_log("$USER: Cannot remove file $form->{'filename'}. $!", 'error'); do_output("$config{'theme'}_files", show_category($category), sprintf($trans->gettext('File %s already exists!'),$form->{'filename','tiedostonimi'}), 'error'); } if ($QUOTA < ((stat($form->{'filename'}))[7] + $USED_QUOTA)) { unlink($form->{'filename'}) or write_log("$USER: Cannot remove file $form->{'filename'}. $!", 'error'); do_output("$config{'theme'}_files", show_category($category), $trans->gettext('Your quota has exceeded! Remove some files before trying to upload anything.'), 'error'); } unless (copy($form->{'filename'}, "$fmconfig{'resourceroot'}$category$form->{'filename','tiedostonimi'}")) { unlink($form->{'filename'}) or write_log("$USER: Cannot remove file $form->{'filename'}. $!", 'error'); write_log("$USER: Cannot copy file from $form->{'filename'} to $fmconfig{'resourceroot'}$category$form->{'filename','tiedostonimi'}! $!", 'error'); do_output("$config{'theme'}_files", show_category($category), sprintf($trans->gettext('Error handling file %s. Contact administrator!'),$form->{'filename','tiedostonimi'}), 'error'); } chmod 0600, "$fmconfig{'resourceroot'}$category$form->{'filename','tiedostonimi'}"; my $size = "$fmconfig{'resourceroot'}$category$form->{'filename','tiedostonimi'}"; lock_tables('READ','users'); my ($ref) = db_select('UID','users',"nimi = '$USER'"); unlock_tables(); add_description($category, $form->{'filename','tiedostonimi'}, { FILENAME => prepare_fordb($form->{'filename','tiedostonimi'}), MODIFIED => time(), PATH => $category, UPLOADER => $ref->{'UID'}, DESCRIPTION => prepare_fordb($form->{'filedesc'}) } ); $USED_QUOTA += $size; unlink($form->{'filename'}) or write_log("$USER: Cannot remove file $form->{'filename'}. $!", 'error'); } ########################### # Upload new file version # ########################### sub save_new_version { my ($ref, $fileref, $oldversion, $newversion, @version); my ($category, $file) = @_; unless ( get_extension($file) eq get_extension($form->{'filename','tiedostonimi'}) ) { unlink($form->{'filename'}) or write_log("$USER: Cannot remove file $form->{'filename'}. $!", 'error'); do_output("$config{'theme'}_newrevision", show_category($category), sprintf($trans->gettext('Uploaded file doesn\'t have the same file type as file %s!'), $file), 'error'); } if (!$form->{'filename','tiedostonimi'}) { unlink($form->{'filename'}) or write_log("$USER: Cannot remove file $form->{'filename'}. $!", 'error'); do_output("$config{'theme'}_newrevision", show_category($category), $trans->gettext('You must select a file to upload.'), 'error'); } if ($QUOTA < ((stat($form->{'filename'}))[7] + $USED_QUOTA)) { unlink($form->{'filename'}) or write_log("$USER: Cannot remove file $form->{'filename'}. $!", 'error'); do_output("$config{'theme'}_newrevision", show_category($category), $trans->gettext('Your quota has exceeded! Remove some files before trying to upload anything.'), 'error'); } $fileref = get_description($category, $file); @version = split /\./, $fileref->{'REVISION'}; $oldversion = ".$version[0].$version[1].$file"; if ($version[0] == 9) { $version[0] += 1; $version[1] = 0; } else {$version[1]++;} $newversion = "$version[0].$version[1]"; unless (copy("$fmconfig{'resourceroot'}$category$file", "$fmconfig{'resourceroot'}$category$oldversion")) { unlink($form->{'filename'}) or write_log("$USER: Cannot remove file $form->{'filename'}. $!", 'error'); write_log("$USER: Cannot copy file from $fmconfig{'resourceroot'}$category$file to $fmconfig{'resourceroot'}$category$oldversion! $!", 'error'); do_output("$config{'theme'}_newrevision", show_category($category), sprintf($trans->gettext('Error handling file %s. Contact administrator!'),$file), 'error'); } unless (copy($form->{'filename'}, "$fmconfig{'resourceroot'}$category$file")) { unlink($form->{'filename'}) or write_log("$USER: Cannot remove file $form->{'filename'}. $!", 'error'); write_log("$USER: Cannot copy file from $form->{'filename'} to $fmconfig{'resourceroot'}$category$file! $!", 'error'); do_output("$config{'theme'}_newrevision", show_category($category), sprintf($trans->gettext('Error handling file %s. Contact administrator!'),$file), 'error'); } chmod 0600, "$fmconfig{'resourceroot'}$category$file"; my $size = "$fmconfig{'resourceroot'}$category$file"; lock_tables('READ','users'); ($ref) = db_select('UID','users',"nimi = '$USER'"); unlock_tables(); add_description($category, $file, { FID => $fileref->{'FID'}, MODIFIED => time(), UPLOADER => $ref->{'UID'}, REVISION => $newversion } ); lock_tables('WRITE',$REVISIONLOG); db_insert( $REVISIONLOG, { FID => $fileref->{'FID'}, REVISION => $newversion, DESCRIPTION => prepare_fordb($form->{'filedesc'}) } ); unlock_tables(); $USED_QUOTA += $size; unlink($form->{'filename'}) or write_log("$USER: Cannot remove file $form->{'filename'}. $!", 'error'); unlock_file($category, $file); return $newversion; } ######################### # Show category # ######################### # # 1. Create file path with and without links # 2. Open directory and read it's contents # 3. Sort files case-insensitevily # 4. Skip hidden files # 5. Get file or category description # 6. Read file or category attributes # 7. Calculate date # 8. If record is a directory # - Calculate directory size # - Add a directory record to array # 9. If record is a file # - Choose icon # - Add a file record to array # 10. Combine directory and file arrays and return contents and path sub show_category { my ($category) = @_; my ($path, $file, $description, $size, $aika, $last, $myext, $filepic,$nolinks_path,$view_action); my (@files, @directories, @filelist, @fileinfo, @date, @path, $new_window); @path = split(m{/}, $category); my @rootpath = split(m{/}, $ROOTDIR); $path = qq{/ $rootpath[0] / $rootpath[1]}; for(my $i = 0; $i < @path; $i++) { if ($path[$i]) { $path .= qq{ / {'auth'}&ID=$form->{'ID'}&grouptool=$form->{'grouptool'}">$path[$i]}; $nolinks_path .= "/$path[$i]"; } $last .= "$path[$i]/"; } if (@path) { my ($child_folder) = get_child_folder($nolinks_path); push @directories, { pic => 'rf-up.gif', size => ' - ', alt => $trans->gettext('Up one level'), name => $trans->gettext('Previous folder'), params => {cat => $child_folder}, }; } undef $last; opendir(DIR, "$fmconfig{'resourceroot'}$category") or write_log("$USER: Error opening dir $fmconfig{'resourceroot'}$category. $!", 'error'); @files = readdir DIR; closedir DIR; @files = sort {uc($a) cmp uc($b)} @files; foreach $file (@files) { if ($file =~ /^\./) {next;} $description = get_description($category, $file); lock_tables('READ','users'); my ($ref) = db_select('info','users',"UID = '$description->{'UPLOADER'}'"); $description->{'UPLOADER'} = $ref->{'info'}; unlock_tables(); $description->{'DESCRIPTION'} = $trans->gettext('No description.') unless $description->{'DESCRIPTION'}; @fileinfo = stat("$fmconfig{'resourceroot'}$category$file"); @date = utc_epoch2date($fileinfo[9]); $aika = "$date[5]/$date[4]/$date[3] $date[2]:$date[1]"; if (-d _) { undef $size; find(sub {if (-f) {$size += -s if $_ !~ /^\./;}}, "$fmconfig{'resourceroot'}$category$file"); push @directories, { pic => 'rf-folder.gif', alt => $description->{'DESCRIPTION'}, name => $file, params => {cat => "$category$file"}, size => $size, date => $aika, revision => ' - ', uploader => $description->{'UPLOADER'}, actions => ['edit_dirdesc', 'rename_dir'], action_map => {edit_dirdesc => $trans->gettext('Description'), rename_dir => $trans->gettext('Rename')} }; } else { $new_window = undef; $myext = get_extension($file); if ($filepics{$myext}) {$filepic = $filepics{$myext};} else {$filepic = $filepics{'default'};} $new_window = 1 if $myext =~ /^(png|gif|jpeg|jpg|swf|html|txt|doc|xls|css|pdf|xml)$/; $view_action = 'view'; if ($myext eq 'mp3' && $ENABLE_STREAMING) { $description->{'DESCRIPTION'} = undef; MP3::Info->import(qw(get_mp3tag)); my $tag = get_mp3tag("$fmconfig{'resourceroot'}$category$file", 1); foreach (qw(TITLE ARTIST ALBUM YEAR GENRE COMMENT)) { $description->{'DESCRIPTION'} .= '[B]'.$trans->gettext(ucfirst(lc $_))."[/B]: $tag->{$_}\n" if $tag->{$_}; } chomp($description->{'DESCRIPTION'}); $description->{'DESCRIPTION'} = $trans->gettext('No description.') unless $description->{'DESCRIPTION'}; $view_action = 'stream'; } push @filelist, { new_window => $new_window, pic => $filepic, alt => $description->{'DESCRIPTION'}, name => $file, params => {cat => $category,dl => $file}, size => $fileinfo[7], date => $aika, revision => $description->{'REVISION'}, uploader => $description->{'UPLOADER'}, actions => ['edit','download',$view_action], action_map => {download => $trans->gettext('Download'), stream => $trans->gettext('Stream'), view => $trans->gettext('View'), edit => $trans->gettext('Properties')} }; } } return ([@directories,@filelist],$path); } #################################### # Return human readable byte sizes # #################################### # # 1. If file is over a gigabyte round it # 2. If file is over a megabyte round it # 3. If file is over a kilobyte round it # 4. Return rounded value sub human_readable { my $size = shift; if ($size >= (1024*1024*1024)) { $size = sprintf("%.1f", $size/(1024*1024*1024)); $size .= 'G'; } elsif ($size >= (1024*1024)) { $size = sprintf("%.1f", $size/(1024*1024)); $size .= 'M'; } elsif ($size >= 1024) { $size = sprintf("%.1f", $size/1024); $size .= 'k'; } $size = "0" if !$size; return $size; } ######################################## # Check if file has been locked or not # ######################################## sub check_lock { my ($category, $file) = @_; my $ref = get_description($category, $file); lock_tables('READ','users', $FILEDESCS); my ($user) = db_select('UID','users',"nimi = '$USER'"); my ($locked) = db_select('LOCKED',$FILEDESCS,"FID = '$ref->{'FID'}'"); unlock_tables(); return undef unless $locked->{'LOCKED'}; return 0 if $user->{'UID'} eq $locked->{'LOCKED'}; return $user->{'UID'}; } ######################### # Lock file for editing # ######################### sub lock_file { my ($category, $file) = @_; my $ref = get_description($category, $file); lock_tables('READ','users'); my ($user) = db_select('UID','users',"nimi = '$USER'"); unlock_tables(); lock_tables('WRITE', $FILEDESCS); db_update($FILEDESCS, { DATELOCKED => time(), LOCKED => $user->{'UID'} }, "FID = $ref->{'FID'}"); unlock_tables(); } ################################### # Unlock file (stop editing mode) # ################################### sub unlock_file { my ($category, $file) = @_; my $ref = get_description($category, $file); lock_tables('WRITE', $FILEDESCS); db_update($FILEDESCS, { DATELOCKED => '0', LOCKED => '0' }, "FID = $ref->{'FID'}"); unlock_tables(); } ######################### # Get description # ######################### # # 1. If requested entry is a file # - Get description from database # - Return description # 2. If requested entry is a directory # - Open .descriptions file # - Return description from file if record found sub get_description { my ($category, $file) = @_; my ($temp, $description, $line); my (@lines); unless (-f "$fmconfig{'resourceroot'}$category.descriptions") { open FILE, "> $fmconfig{'resourceroot'}$category.descriptions" or die "Can't open file $fmconfig{'resourceroot'}$category.descriptions: $!"; lock(*FILE); unlock(*FILE); close FILE; } open FILE, "< $fmconfig{'resourceroot'}$category.descriptions" or die "Can't open file $fmconfig{'resourceroot'}$category.descriptions: $!"; lock(*FILE, 1); @lines = ; unlock(*FILE); close FILE; foreach $line (@lines) { chomp($line); ($temp, $description) = split(/:::/, $line); if ($temp eq $file) { $description =~ s/\\n/\n/gm; lock_tables('READ', $FILEDESCS); my ($return) = db_select("*", $FILEDESCS, "FID = $description"); unlock_tables(); return $return; } } if (-e "$fmconfig{'resourceroot'}$category$file") { lock_tables('READ','users'); my ($ref) = db_select('UID','users',"nimi = '$USER'"); unlock_tables(); my $id = add_description( $category, $file, { MODIFIED => time(), FILENAME => prepare_fordb($file), PATH => prepare_fordb($category), UPLOADER => $ref->{'UID'} } ); return {FILENAME => $file, PATH => $category, MODIFIED => time(), FID => $id, REVISION => '1.0', DOWNCOUNT => '0', UPLOADER => $ref->{'UID'}, DESCRIPTION => ''}; } } ######################### # Add description # ######################### sub add_description { my ($category, $file, $description) = @_; my ($temp, $line, $descfile); my (@lines); $file =~ s/://g; $descfile = "$fmconfig{'resourceroot'}$category.descriptions"; unless (-f $descfile) { open FILE, "> $descfile" or die "Can't open file $descfile: $!"; lock(*FILE); unlock(*FILE); close FILE; } unless ( $description->{'FID'} ) { lock_tables('WRITE', $FILEDESCS, $REVISIONLOG); db_insert( $FILEDESCS, $description ); $description->{'FID'} = get_lastid(); db_insert( $REVISIONLOG, { FID => $description->{'FID'}, REVISION => '1.0', DESCRIPTION => 'Initial version.' } ); unlock_tables(); open FILE, "+< $descfile" or die "Can't open file $descfile: $!"; lock(*FILE); @lines = ; seek(FILE, 0, 0) or die "Can't seek to start of file $descfile: $!"; push @lines, "$file\:\:\:$description->{'FID'}\n"; print FILE @lines or die "Can't print to file $descfile: $!"; truncate (FILE, tell(FILE)) or die "Can't truncate file $descfile: $!"; unlock(*FILE); close FILE or die "Can't close file $descfile: $!"; } else { lock_tables('WRITE', $FILEDESCS); foreach (keys %$description) { $description->{$_} = prepare_fordb($description->{$_}); } db_update( $FILEDESCS, $description, "FID = '$description->{'FID'}'" ); unlock_tables(); open FILE, "+< $descfile" or die "Can't open file $descfile: $!"; lock(*FILE); @lines = ; seek(FILE, 0, 0) or die "Can't seek to start of file $descfile: $!"; foreach $line (@lines) { ($temp) = split(/:::/, $line); if ($temp eq $file) { if ($description->{'FILENAME'}) { print FILE "$description->{'FILENAME'}\:\:\:$description->{'FID'}\n" or die "Can't print to file $descfile: $!"; } else { print FILE "$file\:\:\:$description->{'FID'}\n" or die "Can't print to file $descfile: $!"; } } else { print FILE "$line" or die "Can't print to file $descfile: $!"; } } truncate (FILE, tell(FILE)) or die "Can't truncate file $descfile: $!"; unlock(*FILE); close FILE or die "Can't close file $descfile: $!"; } return $description->{'FID'}; } ######################### # Delete description # ######################### sub del_description { my ($category, $file) = @_; my ($temp, $descfile, $line, $id); my (@lines); $descfile = "$fmconfig{'resourceroot'}$category.descriptions"; open FILE, "+< $descfile" or die "Can't open file $descfile: $!"; lock(*FILE); @lines = ; seek(FILE, 0, 0) or die "Can't seek to start of file $descfile: $!"; foreach $line (@lines) { ($temp, $id) = split(/:::/, $line); if ($temp eq $file) { lock_tables('WRITE', $FILEDESCS, $REVISIONLOG); db_delete($FILEDESCS, "FID = '$id'"); db_delete($REVISIONLOG, "FID = '$id'"); unlock_tables(); next; } else { print FILE "$line" or die "Can't print to file $descfile: $!"; } } truncate (FILE, tell(FILE)) or die "Can't truncate file $descfile: $!"; unlock(*FILE); close FILE or die "Can't close file $descfile: $!"; } ################ # Edit file # ################ sub edit_file { my ($category, $file, $content) = @_; my ($line, $path, $binary, $temp_file); $path = "$fmconfig{'resourceroot'}$category$file"; $binary = 1 if -B $path; do {$temp_file = (int rand 1000000)} while (-e "$config{'uploads'}/$temp_file"); $temp_file = "$config{'uploads'}/".$temp_file; open FILE, "> $temp_file" or write_log("Error opening file $temp_file", 'error'); lock(*FILE); binmode(FILE) if $binary; print FILE $content; unlock(*FILE); close FILE; $form->{'filename' , 'tiedostonimi'} = $file; $form->{'filename'} = $temp_file; save_new_version($category, $file); } ################ # Edit MP3 tag # ################ sub edit_tag { my ($category, $file) = @_; my ($line, $path, $binary, %tag); $path = "$fmconfig{'resourceroot'}$category$file"; MP3::Info->import(qw(remove_mp3tag set_mp3tag use_winamp_genres @mp3_genres)); MP3::Info::use_winamp_genres(); $form->{'year'} =~ tr/0-9//cd; %tag = ( TITLE => $form->{'title'}, ARTIST => $form->{'artist'}, ALBUM => $form->{'album'}, YEAR => $form->{'year'}, COMMENT => $form->{'comment'}, GENRE => $form->{'genre'} ); set_mp3tag($path, \%tag); # Set ID3v1 tag } ################## # Rename file # ################## sub rename_file { my ($category, $file, $rename) = @_; $rename =~ s/(<|>|\||\*|\/|\\|\?|\:|\"|\')//g; $rename =~ s{/}{}gm; $rename =~ s/^\.//gm; $rename =~ s/\n//gm; $rename =~ s/\.\.//gm; unless (rename "$fmconfig{'resourceroot'}$category$file", "$fmconfig{'resourceroot'}$category$rename") { write_log("$USER: Cannot rename file $fmconfig{'resourceroot'}$category$file as $fmconfig{'resourceroot'}$category$rename!", 'error'); return undef; } my $ref = get_description($category, $file); if ($ref->{'REVISION'} ne '1.0') { lock_tables('READ', $REVISIONLOG); db_list("select REVISION from $REVISIONLOG where FID = '$ref->{'FID'}'"); while (my $revisionref = $sth->fetchrow_hashref()) { unless (rename "$fmconfig{'resourceroot'}$category.$revisionref->{'REVISION'}.$file", "$fmconfig{'resourceroot'}$category.$revisionref->{'REVISION'}.$rename") { write_log("$USER: Cannot rename file $fmconfig{'resourceroot'}$category.$revisionref->{'REVISION'}.$file as $fmconfig{'resourceroot'}$category.$revisionref->{'REVISION'}.$rename!", 'error'); } } db_end(); unlock_tables(); } add_description( $category, $file, {FID => $ref->{'FID'}, FILENAME => $rename} ); return $rename; } #################### # Rename directory # #################### sub rename_directory { my ($category, $catdir, $rename) = @_; my (%ren_table); $rename =~ s/(<|>|\||\*|\/|\\|\?|\:|\"|\')//g; $rename =~ s{/}{}gm; $rename =~ s/\.\.//gm; $rename =~ s/^\.//; unless (rename "$fmconfig{'resourceroot'}$category$catdir", "$fmconfig{'resourceroot'}$category$rename") { write_log("$USER: Cannot move directory from $fmconfig{'resourceroot'}$category$catdir to $fmconfig{'resourceroot'}$category$rename: $!", 'error'); return undef; } my $ref = get_description( $category, $catdir ); add_description( $category, $catdir, {FID => $ref->{'FID'}, FILENAME => $rename} ); lock_tables('WRITE', $FILEDESCS); db_list("select FID,PATH from $FILEDESCS where PATH like '$category$catdir/%'"); while (my $ref = $sth->fetchrow_hashref()) { if ($ref->{'PATH'} =~ /^$category$catdir\//o) { $ref->{'PATH'} =~ s/^$category$catdir\//$category$rename/; $ren_table{$ref->{'FID'}} = $ref->{'PATH'}; } } db_end(); foreach my $fid (keys %ren_table) { db_update( $FILEDESCS, { PATH => $ren_table{$fid} }, "FID = '$fid'" ); } unlock_tables(); return $rename; } ######################### # View document # ######################### # # 1. Open mime types file # 2. Search for mime type based on extension # 3. Return file to the viewer sub view_file { my ($category, $file) = @_; my $path = "$fmconfig{'resourceroot'}$category$file"; my ( @extensions, $length, $binary); my ($mimetype, $extension, $myext); $myext = get_extension($file); open FILE, "< $fmconfig{'mimetypes'}" or write_log("Error opening file $fmconfig{'mimetypes'}", 'error'); lock(*FILE, 1); while () { @extensions = split /\s+/, $_; foreach $extension (@extensions) { if ($myext eq $extension) {$mimetype = $extensions[0];} } last if $mimetype; } unlock(*FILE); close FILE; $length = -s $path; $binary = 1 if -B $path; if ($ENABLE_STREAMING && $mimetype eq 'audio/mpeg') { MP3::Info->import(qw(get_mp3tag get_mp3info)); my $tag = get_mp3tag($path, 1); my $info = get_mp3info($path); print "Content-Type: $mimetype".$CRLF; print "Content-Transfer-Encoding: binary$CRLF"; print "Server: MimerDesk".$CRLF; print "icy-notice1:
This stream requires a shoutcast/icecast compatible player.
".$CRLF; print "icy-notice2:MimerDesk MP3 stream
".$CRLF; print "icy-name:(MimerDesk) $tag->{'ARTIST'}-$tag->{'TITLE'}".$CRLF; print "icy-genre:$tag->{'GENRE'}".$CRLF; print "icy-url:$config{'loc_server'}".$CRLF; print "icy-metaint:0".$CRLF; print "icy-pub:0".$CRLF; print "icy-br:$info->{'BITRATE'}".$CRLF; print "x-audiocast-name:(MimerDesk) $tag->{'ARTIST'}-$tag->{'TITLE'}".$CRLF; print "x-audiocast-genre:$tag->{'GENRE'}".$CRLF; print "x-audiocast-pub:0".$CRLF; print "x-audiocast-br:$info->{'BITRATE'}".$CRLF; } elsif ($binary) { $mimetype = "application/octet-stream" unless $mimetype; print "Content-Type: $mimetype".$CRLF; print "Content-Transfer-Encoding: binary$CRLF"; } elsif (!$binary) { $mimetype = "text/plain" unless $mimetype; print "Content-Type: $mimetype".$CRLF; } print "Accept-Ranges: bytes".$CRLF; print "Content-Disposition: attachment; filename=$file".$CRLF unless $ENV{'HTTP_USER_AGENT'} =~ /MSIE/; print "Content-Length: $length".$CRLF.$CRLF; open FILE, "< $path" or write_log("Error opening file $path", 'error'); lock(*FILE, 1); binmode(FILE) if $binary; while () {print $_;} unlock(*FILE); close FILE; my $ref = get_description($category, $file); lock_tables('WRITE', $FILEDESCS); db_list("update $FILEDESCS set DOWNCOUNT = (DOWNCOUNT+1) where FID = '$ref->{'FID'}'"); db_end(); unlock_tables(); exit; } ######################## # Stream all MP3 files # ######################## sub stream_all_mp3 { my ($category) = @_; my (@files); opendir(DIR, "$fmconfig{'resourceroot'}$category") or write_log("$USER: Error opening dir $fmconfig{'resourceroot'}$category. $!", 'error'); @files = readdir DIR; closedir DIR; stream_selected_mp3($category, \@files); exit; } ######################## # Stream selected mp3s # ######################## sub stream_selected_mp3 { my ($category, $items) = @_; my ($m3u_filename, $content); MP3::Info->import(qw(get_mp3tag)); $m3u_filename = int rand 1000000; $content = "#EXTM3U".$CRLF; foreach my $file (sort {uc($a) cmp uc($b)} @$items) { my $myext = get_extension($file); next if -d "$fmconfig{'resourceroot'}$category$file"; next if $myext ne 'mp3'; my $tag = get_mp3tag("$fmconfig{'resourceroot'}$category$file", 1); $tag->{'ARTIST'} = $file unless $tag->{'ARTIST'}; $content .= "#EXTINF:-1,(MimerDesk) $tag->{'ARTIST'}-$tag->{'TITLE'}".$CRLF; $content .= "$config{'loc_server'}$ENV{'SCRIPT_NAME'}?auth=$form->{'auth'}&ID=$form->{'ID'}&cat=".encodeurl($form->{'cat'})."&dl=".encodeurl($file)."&view=1&grouptool=$form->{'grouptool'}".$CRLF; } print "Content-Length: ".length($content).$CRLF; print "Content-Type: audio/mpegurl".$CRLF; print "Accept-Ranges: bytes".$CRLF; print "Content-Disposition: attachment; filename=dir$m3u_filename.m3u".$CRLF.$CRLF; print $content; exit; } ######################### # Send file # ######################### # # 1. print headers # 2. read file and send it sub download_file { my ($category, $file) = @_; my ($length, $binary, $mimetype); my $path = "$fmconfig{'resourceroot'}$category$file"; $length = -s $path; $binary = 1 if -B $path; $mimetype = "application/octet-stream"; print "Content-Type: $mimetype".$CRLF; print "Content-Length: $length".$CRLF; print "Accept-Ranges: bytes".$CRLF; print "Content-Transfer-Encoding: binary".$CRLF if $binary; print "Content-Disposition: attachment; filename=$file".$CRLF.$CRLF; open FILE, "<$path" or write_log("Error opening file $path", 'error'); lock(*FILE, 1); binmode(FILE) if $binary; while () {print;} unlock(*FILE); close FILE; my $ref = get_description($category, $file); lock_tables('WRITE', $FILEDESCS); db_list("update $FILEDESCS set DOWNCOUNT = (DOWNCOUNT+1) where FID = '$ref->{'FID'}'"); db_end(); unlock_tables(); exit; } ######################### # Create directory # ######################### # # 1. try to create dir # - if failed # - print error # - if succeed # - Add description sub create_dir { my ($category, $newdir) = @_; if (!$newdir) { do_output( "$config{'theme'}_files", show_category($category), $trans->gettext('You must specify a directory name!'), 'error' ); } if (!mkdir("$fmconfig{'resourceroot'}$category$newdir", 0700)) { write_log("$USER: Error creating directory $fmconfig{'resourceroot'}$category$newdir. $!", 'error'); do_output( "$config{'theme'}_files", show_category($category), sprintf($trans->gettext('Error creating directory %s%s!'), $category, $newdir), 'error' ); } lock_tables('READ','users'); my ($ref) = db_select('UID','users',"nimi = '$USER'"); unlock_tables(); add_description($category, $newdir, { FILENAME => prepare_fordb($newdir), MODIFIED => time(), PATH => $category, UPLOADER => $ref->{'UID'}, DESCRIPTION => prepare_fordb($form->{'dirdesc'}) } ); } ######################### # Send zip archive # ######################### sub send_zip_archive { my $zip = Archive::Zip->new(); my ($category, $items) = @_; my $fullname = "$fmconfig{'resourceroot'}$category"; chdir($fullname); foreach my $file (@$items) { if (-e $file) { if (-d _) { $zip->addDirectory($file); find({ wanted => sub { return if $_ =~ m{/\.}; $zip->addFile($_) if -f $_; $zip->addDirectory($_) if -d; }, no_chdir => 1, follow => 1 }, $file); } else {$zip->addFile($file) ;} } else { do_output("$config{'theme'}_files", show_category($category), sprintf($trans->gettext('File /%s%s%s does not exist!'),$ROOTDIR,$category,$file), 'error'); } } $zip->zipfileComment( 'Downloaded from MimerDesk' ); my $filename = $ROOTDIR.$category; chop($filename); $filename =~ s{/}{\-}g; $filename =~ s{ }{\_}g; print "Content-Type: application/x-zip-compressed".$CRLF; print "Content-Transfer-Encoding: binary".$CRLF; print "Content-Disposition: attachment; filename=MimerDesk_$filename.zip".$CRLF.$CRLF; $zip->writeToFileHandle( *STDOUT ); exit; } ######################### # Send gz archive # ######################### sub send_gz_archive { my $tar = Archive::Tar->new(); my ($category, $items) = @_; my ($file_temp,$length); my $fullname = "$fmconfig{'resourceroot'}$category"; chdir($fullname); foreach my $file (@$items) { if (-e $file) { if (-d _) { find({ wanted => sub { return if $_ =~ m{/\.}; $tar->add_files($_) if -f $_; }, no_chdir => 1, follow => 1 }, $file); } else {$tar->add_files($file);} } else { do_output("$config{'theme'}_files", show_category($category), sprintf($trans->gettext('File /%s%s%s does not exist!'),$ROOTDIR,$category,$file), 'error'); } } my $filename = $ROOTDIR.$category; chop($filename); $filename =~ s{/}{\-}g; $filename =~ s{ }{\_}g; do {$file_temp = (int rand 1000000)} while (-e $config{'uploads'}."/$file_temp"); $tar->write($config{'uploads'}."/$file_temp", 1); $length = -s $config{'uploads'}."/$file_temp"; print "Content-Type: application/x-compressed".$CRLF; print "Content-Transfer-Encoding: binary".$CRLF; print "Content-Length: $length".$CRLF; print "Content-Disposition: attachment; filename=MimerDesk_$filename.tar.gz".$CRLF.$CRLF; open FILE, "< $config{'uploads'}/$file_temp" or write_log("Error opening file $config{'uploads'}/$file_temp", 'error'); lock(*FILE, 1); binmode(FILE); while () {print;} unlock(*FILE); close FILE; unlink($config{'uploads'}."/$file_temp"); exit; } ######################### # Delete file/dir # ######################### # # 1. Check if file or dir exists # - if failed return error # 1. Delete dir description # 2. If directory try to rm -r it # - if failed return error # - Update quota # 3. If file try to unlink it # - Update quota # - Remove description from database sub delete_file { my ($category, $file) = @_; my (%remove_table); my $fullname = "$fmconfig{'resourceroot'}$category$file"; if (-e $fullname) { if (-d _) { chdir "$fmconfig{'resourceroot'}$category$file"; find(sub { my $filepath = $_; return unless $filepath eq '.descriptions'; open FILE, "< $filepath" or die "Can't open file $filepath: $!"; lock(*FILE, 1); my @lines = ; unlock(*FILE); close FILE; my $folder = $File::Find::dir; $folder =~ s/^\.//; $folder = '/' unless $folder; $folder .= '/' unless $folder =~ m{/$}; foreach my $line (@lines) { chomp($line); my ($filename) = split(/:::/, $line); if ( check_lock("$category$file$folder", $filename) ) { do_output("$config{'theme'}_files", show_category($category), sprintf($trans->gettext('Directory %s contains locked files! You cannot remove the directory until all the locks have been released.'),$file),'error'); } } }, "."); unless (rmtree($fullname)) { write_log("$USER: Error deleting directory $fullname. $!", 'error'); do_output( "$config{'theme'}_files", show_category($category), sprintf($trans->gettext('Error deleting directory %s%s!'),$category,$file), 'error' ); } $USED_QUOTA = undef; find(sub {if (-f) {$USED_QUOTA += -s if $_ !~ /^\./;}}, "$fmconfig{'resourceroot'}"); lock_tables('WRITE', $FILEDESCS, $REVISIONLOG); db_list("select FID,PATH from $FILEDESCS where PATH like '$category$file/%'"); while (my $ref = $sth->fetchrow_hashref()) { $remove_table{$ref->{'FID'}} = $ref->{'PATH'} if $ref->{'PATH'} =~ /^$category$file\//o; } db_end(); foreach my $fid (keys %remove_table) { db_delete($FILEDESCS, "FID = '$fid'"); db_delete($REVISIONLOG, "FID = '$fid'"); } unlock_tables(); del_description($category, $file); } else { $USED_QUOTA -= (stat($fullname))[7]; unless (unlink($fullname)) { write_log("$USER: Error deleting file $fullname. $!", 'error'); do_output( "$config{'theme'}_files", show_category($category), sprintf($trans->gettext('Error deleting file %s%s!'),$category,$file), 'error' ); } my $ref = get_description($category, $file); unlink <$fmconfig{'resourceroot'}$category.*.$file>; del_description($category, $file); } } else { write_log("Error deleting $fullname!", 'error'); do_output("$config{'theme'}_files", show_category($category), sprintf($trans->gettext('Error deleting %s!'),$fullname), 'error'); } } ######################### # Print HTML-page # ######################### sub do_output { my ($ref); my ($template,$output,$path,$message,$class) = @_; $message .= tag('br').tag('br') if $message; print_header('pragma'); $ref = get_template('maintemplate',$template,'js_doClock', 'js_help', 'js_gotosite'); $ref->{'maintemplate'} =~ s/<>/$ref->{$template}/m; my $stuff = join '', ($ref->{'js_doClock'},$ref->{'js_help'},$ref->{'js_gotosite'}); $ref->{'maintemplate'} =~ s/<>/$stuff/ms; if ($GROUPACTIVOR) {$ref->{'maintemplate'} = create_buttons($ref->{'maintemplate'}, 'Group', 'Files', $form);} else {$ref->{'maintemplate'} = create_buttons($ref->{'maintemplate'}, 'Personal', 'Files', $form);} $ref->{'maintemplate'} =~ s/<>/minea/gm; $ref->{'maintemplate'} =~ s/<>/MimerDesk\: $APPLICATION/ms; $ref->{'maintemplate'} = replace_tags($ref->{'maintemplate'}, $USER, $form->{'auth'}, $form->{'ID'}, $TIME_USED); $ref->{'maintemplate'} = add_popups($ref->{'maintemplate'}, $USER, $form->{'auth'}, $form->{'ID'}); if ($template eq "$config{'theme'}_files") { do_output_files($ref, $output); } elsif ($template eq "$config{'theme'}_filesedit") { do_output_filesedit($ref); } elsif ($template eq "$config{'theme'}_fileseditor") { do_output_fileseditor($ref); } elsif ($template eq "$config{'theme'}_editdesc") { do_output_editdesc($ref); } elsif ($template eq "$config{'theme'}_editdir") { do_output_editdir($ref); } elsif ($template eq "$config{'theme'}_renamedir") { do_output_renamedir($ref); } elsif ($template eq "$config{'theme'}_renamefile") { do_output_renamefile($ref); } elsif ($template eq "$config{'theme'}_mp3tagedit") { do_output_mp3tagedit($ref); } elsif ($template eq "$config{'theme'}_newrevision") { do_output_newrevision($ref); } $ref->{'maintemplate'} =~ s/<
>/$form->{'dl'}/m; $ref->{'maintemplate'} =~ s{<>}{/$ROOTDIR$category$form->{'dl'}}m; $ref->{'maintemplate'} =~ s/<>/$path/m; $ref->{'maintemplate'} =~ s/<>/$class/m; $ref->{'maintemplate'} =~ s/<>/$message/m; $ref->{'maintemplate'} =~ s/<>/$category/mg; $ref->{'maintemplate'} =~ s/<>/$form->{'grouptool'}/mg; if ($GROUPACTIVOR) { my $group_translated_text = sprintf($trans->gettext("Files of group %s"), $GRPNAME); $ref->{'maintemplate'} =~ s/<>/$group_translated_text/m; } else { my ($realname, $user_translated_text); lock_tables('READ', 'users'); db_list("select info from users where nimi = '$USER'"); while (my $ref = $sth->fetchrow_hashref()) { $realname = $ref->{'info'}; } db_end(); unlock_tables(); my $user_translated_text = sprintf($trans->gettext("Files of user %s"), $realname); $ref->{'maintemplate'} =~ s/<>/$user_translated_text/m; } print $ref->{'maintemplate'}; db_end('disconnect'); exit; } ######### sub do_output_fileseditor { my $ref = shift; my ($line, $path, $binary, $file); $path = "$fmconfig{'resourceroot'}$category$form->{'dl'}"; $binary = 1 if -B $path; open FILE, "<$path" or write_log("Error opening file $path", 'error'); lock(*FILE, 1); binmode(FILE) if $binary; while ($line = ) { $line = html_escape($line); $file .= $line; } unlock(*FILE); close FILE; $ref->{'maintemplate'} =~ s/<>/html_escape($form->{'dl'})/me; $ref->{'maintemplate'} =~ s/<>/$file/m; } ######### sub do_output_newrevision { my $ref = shift; $ref->{'maintemplate'} =~ s/<>/sprintf($trans->gettext("Upload a new revision of file %s"), $form->{'dl'})/meg; $ref->{'maintemplate'} =~ s/<>/html_escape($form->{'filedesc'})/me; } ######### sub do_output_editdesc { my $ref = shift; my $desc = get_description($category, $form->{'dl'}); $ref->{'maintemplate'} =~ s/<>/html_escape($form->{'dl'})/me; $ref->{'maintemplate'} =~ s/<>/html_escape($desc->{'DESCRIPTION'})/me; } ######### sub do_output_editdir { my $ref = shift; my ($child, $parent) = get_child_folder($category); my $desc = get_description($child, $parent); $ref->{'maintemplate'} =~ s/<>/$child/mg; $ref->{'maintemplate'} =~ s/<>/$parent/mg; $ref->{'maintemplate'} =~ s/<>/html_escape($desc->{'DESCRIPTION'})/me; } ######### sub do_output_renamedir { my $ref = shift; my ($child, $parent) = get_child_folder($category); $ref->{'maintemplate'} =~ s/<>/$child/mg; $ref->{'maintemplate'} =~ s/<>/$parent/mg; $ref->{'maintemplate'} =~ s/<>/html_escape($parent)/me; } ######### sub do_output_renamefile { my $ref = shift; $ref->{'maintemplate'} =~ s/<>/html_escape($form->{'dl'})/gme; } ######### sub do_output_mp3tagedit { my $ref = shift; my (@mp3_genres, $genre, $path); $path = "$fmconfig{'resourceroot'}$category$form->{'dl'}"; MP3::Info->import(qw(get_mp3tag use_winamp_genres @mp3_genres)); use_winamp_genres(); my $tag = get_mp3tag($path, 1); @mp3_genres = sort @MP3::Info::mp3_genres; $tag->{'YEAR'} =~ tr/0-9//cd; $genre = dropdownmenu(name => 'genre',default => $tag->{'GENRE'},order => \@mp3_genres); $ref->{'maintemplate'} =~ s/<>/html_escape($form->{'dl'})/me; $ref->{'maintemplate'} =~ s/<>/html_escape($tag->{'ARTIST'})/me; $ref->{'maintemplate'} =~ s/<>/html_escape($tag->{'TITLE'})/me; $ref->{'maintemplate'} =~ s/<<album>>/html_escape($tag->{'ALBUM'})/me; $ref->{'maintemplate'} =~ s/<<year>>/html_escape($tag->{'YEAR'})/me; $ref->{'maintemplate'} =~ s/<<comment>>/html_escape($tag->{'COMMENT'})/me; $ref->{'maintemplate'} =~ s/<<genre>>/$genre/m; } ######### sub do_output_files { my ($ref, $output) = @_; my ($stream_button,$checkbox_count); my $columnspan = 7; my $count_files = "0"; my $count_bytes = "0"; my $count_dirs = "0"; my $filelist = starttable(width => '95%',align => 'center',cellspacing => 1,cellpadding => 1,gridcolor => 'black'). startrow(bgcolor => "$htmlcolors->{'title'}"); my @columns = ( '', $trans->gettext('Name'), $trans->gettext('Size'), $trans->gettext('Date & time'), $trans->gettext('Revision'), $trans->gettext('Uploaded by'), $trans->gettext('Actions') ); foreach (@columns) { $filelist .= column(class => 'blackTitle',content => $_.' '); } endrow(); foreach (@$output) { my($parameters,$actions, $checkbox); $stream_button = undef; if (defined $_->{'params'}) # Build link parameters { my (@parameters); my %parameters = %{$_->{'params'}}; foreach my $key (keys %parameters) { push @parameters, "$key=".encodeurl($parameters{$key}); } if (@parameters) { $parameters = '&'; $parameters .= join '&', @parameters; } } if (defined $_->{'actions'}) # Create action links { my %action_map = %{$_->{'action_map'}}; foreach my $action (@{$_->{'actions'}}) { my %parameters = ( href => "$ENV{'SCRIPT_NAME'}?auth=$form->{'auth'}&ID=$form->{'ID'}$parameters&$action=1&grouptool=$form->{'grouptool'}", content => $action_map{$action}, ); if ($action eq 'view' && $_->{'new_window'}) { $parameters{'target'} = '_blank'; } elsif ($action eq 'stream') { $stream_button = '1'; } $actions .= tagged('a',\%parameters).' '; } } unless ($_->{'pic'} eq 'rf-up.gif') { $checkbox_count++; $checkbox = checkbox(name => 'checkb'.$checkbox_count, value => html_escape($_->{'name'})); } $_->{'size'} = 0 unless $_->{'size'}; if ($_->{'pic'} eq 'rf-up.gif') {} # Calculate total byte size elsif ($_->{'pic'} ne 'rf-folder.gif') { $count_bytes += $_->{'size'}; $count_files++; } else {$count_dirs++;} $_->{'size'} = human_readable($_->{'size'}); ($_->{'alt'}) = html_escape($_->{'alt'}); ($_->{'alt'}) = itag_replacer($_->{'alt'}); $_->{'alt'} =~ s/\r?\n/<br>/gm; my $view_mode = 'view'; $view_mode = 'stream' if $stream_button; my %param; $param{'target'} = '_blank' if $view_mode eq 'view' && $_->{'new_window'}; $view_mode = 'cd' if $_->{'pic'} eq 'rf-folder.gif' || $_->{'pic'} eq 'rf-up.gif'; $filelist .= startrow(). column(width => '10', bgcolor => '#FFFFFF', valign => 'top', align => 'CENTER',content => $checkbox). column(class => 'contentLink', valign => 'top', bgcolor => '#FFFFFF', content => ' '. image(src => "$fmconfig{'imagedir'}/$_->{'pic'}", align => 'absmiddle').' '. tagged('a',{onMouseOut => "removeBox()", %param, onMouseOver => "popup('$_->{'alt'}')", href => "$ENV{'SCRIPT_NAME'}?auth=$form->{'auth'}&ID=$form->{'ID'}$parameters&$view_mode=1&grouptool=$form->{'grouptool'}",content => $_->{'name'}}).' '). column(class => 'small', valign => 'top', bgcolor => '#FFFFFF', content => $_->{'size'}.' '). column(class => 'small', valign => 'top', bgcolor => '#FFFFFF', content => $_->{'date'}.' '). column(class => 'content', valign => 'top', bgcolor => '#FFFFFF', content => $_->{'revision'}.' '). column(class => 'content', valign => 'top', bgcolor => '#FFFFFF', content => $_->{'uploader'}.' '). column(class => 'content', valign => 'top', bgcolor => '#FFFFFF', content => ' '.$actions.' '). endrow(); } if (@$output == 0) { $filelist .= startrow(). column(class => 'content', colspan => $columnspan, bgcolor => '#FFFFFF', align => 'center', content => tag('br').$trans->gettext('No files or directories.').tag('br').tag('br')). endrow(); } $filelist .= endtable('hasgrid'); if ($stream_button) { $stream_button = tagged('a', {href => "$ENV{'SCRIPT_NAME'}?auth=$form->{'auth'}&ID=$form->{'ID'}&cat=".encodeurl($form->{'cat'})."&stream_all=1&grouptool=$form->{'grouptool'}", content => image(src => "$config{'loc_pictures'}/streamallmp3files.gif")}); } $ref->{'maintemplate'} =~ s/<<stream_button>>/$stream_button/m; $ref->{'maintemplate'} =~ s/<<numofcheckboxes>>/$checkbox_count/m; $ref->{'maintemplate'} =~ s/<<filelist>>/$filelist/m; my $procents = sprintf("%.1f", ($USED_QUOTA / $QUOTA) * 100) if $QUOTA != 0; $count_bytes = human_readable($count_bytes); $USED_QUOTA = human_readable($USED_QUOTA); $QUOTA = human_readable($QUOTA); $count_bytes = sprintf($trans->gettext('%s bytes'), $count_bytes) if $count_bytes =~ /^\d+$/; $USED_QUOTA = sprintf($trans->gettext('%s bytes'), $USED_QUOTA) if $USED_QUOTA =~ /^\d+$/; $QUOTA = sprintf($trans->gettext('%s bytes'), $QUOTA) if $QUOTA =~ /^\d+$/; $ref->{'maintemplate'} =~ s/<<used_quota>>/$USED_QUOTA ($procents\%)/m; $ref->{'maintemplate'} =~ s/<<quota>>/$QUOTA/m; $ref->{'maintemplate'} =~ s/<<count_dirs>>/$count_dirs/m; $ref->{'maintemplate'} =~ s/<<count_files>>/$count_files/m; $ref->{'maintemplate'} =~ s/<<count_bytes>>/$count_bytes/m; } ######### sub do_output_filesedit { my $ref = shift; my ($editbuttons, $description_box, $file_status); my $description = get_description($category, $form->{'dl'}); my $lock = check_lock($category, $form->{'dl'}); my $extension = get_extension($form->{'dl'}); if ($extension eq 'mp3' && $ENABLE_STREAMING) { MP3::Info->import(qw(get_mp3tag)); my $tag = get_mp3tag("$fmconfig{'resourceroot'}$category$form->{'dl'}", 1); my %tagtranslations = ( 'Artist' => $trans->gettext('Artist'), 'Title' => $trans->gettext('Title'), 'Album' => $trans->gettext('Album'), 'Comment' => $trans->gettext('Comment')); foreach ('Artist','Title','Album','Comment') { $description_box .= startrow(). column(bgcolor => $htmlcolors->{'sectitle'},class => 'content', content => "$tagtranslations{$_}"). column(bgcolor => 'white', class => 'content', content => html_escape($tag->{(uc $_)}).' '). endrow() if $tag->{(uc $_)}; } $description_box .= startrow(). column(bgcolor => $htmlcolors->{'sectitle'},class => 'content', content => $trans->gettext('Year')). column(bgcolor => 'white', class => 'content', content => html_escape($tag->{'YEAR'}).' '). endrow() if $tag->{'YEAR'}; $description_box .= startrow(). column(bgcolor => $htmlcolors->{'sectitle'},class => 'content', content => $trans->gettext('Genre')). column(bgcolor => 'white', class => 'content', content => html_escape($tag->{'GENRE'}).' '). endrow() if $tag->{'GENRE'}; $editbuttons .= picbutton(form => 'form', name => 'stream', image => "stream.gif"). ' '; unless ( $lock ) { $editbuttons .= picbutton(form => 'form', name => 'edit_tag', image => "editmp3tag.gif"). ' '; } } else { $description->{'DESCRIPTION'} = html_escape($description->{'DESCRIPTION'}); ($description->{'DESCRIPTION'}) = itag_replacer($description->{'DESCRIPTION'}); $description->{'DESCRIPTION'} =~ s/\n/<br>/gm; my %param; $param{'target'} = '_blank' if $extension =~ /^(png|gif|jpeg|jpg|swf|html|txt|doc|xls|css|pdf|xml)$/; $description_box = startrow(). column(bgcolor => $htmlcolors->{'sectitle'},valign => 'top',class => 'content', content => $trans->gettext('Description')). column(bgcolor => 'white', class => 'content', content => ($description->{'DESCRIPTION'} || '-')). endrow(); $editbuttons .= tagged('a', {href => "$ENV{'SCRIPT_NAME'}?auth=$form->{'auth'}&ID=$form->{'ID'}&view=1&dl=".encodeurl($form->{'dl'})."&cat=".encodeurl($form->{'cat'})."&grouptool=$form->{'grouptool'}", %param, content => image(align => 'absmiddle', src => "$config{'loc_pictures'}/view.gif")}). ' '; unless ( $lock ) { $editbuttons .= picbutton(form => 'form', name => 'edit_desc', image => "editdescription.gif"). ' '; } } $editbuttons .= picbutton(form => 'form', name => 'download', image => "download.gif"). ' '; if (-T "$fmconfig{'resourceroot'}$category$form->{'dl'}") # If file is not a binary file { unless ( $lock ) { $editbuttons .= picbutton(form => 'form', name => 'edit_file', image => "editfile.gif"). ' '; } } unless ( $lock ) { $editbuttons .= picbutton(form => 'form', name => 'rename_file', image => "rename.gif"). ' '; } my $size = -s "$fmconfig{'resourceroot'}$category$form->{'dl'}"; my $size_human = human_readable($size); $size = sprintf($trans->gettext('%s bytes'), $size); $ref->{'maintemplate'} =~ s/<<file_size>>/$size_human \($size\)/m; lock_tables('READ','users'); my ($tmp) = db_select('info','users',"UID = '$description->{'UPLOADER'}'"); $description->{'UPLOADER'} = $tmp->{'info'}; unlock_tables(); my $uploader = $description->{'UPLOADER'} || '-'; $ref->{'maintemplate'} =~ s/<<uploader>>/$uploader/m; if ( !$lock && $lock ne '0' ) { $file_status = $trans->gettext('Not locked.'). tag('br').tag('br').' '. picbutton(form => 'form', name => 'lock_file', image => "lockfileforediting.gif"). tag('br').tag('br'); } elsif ( $lock eq '0' ) { my (undef, $min,$hour,$day,$month,$year) = utc_epoch2date($description->{'DATELOCKED'}); $file_status = sprintf($trans->gettext('You have locked the file for editing on %s. Other users are not permitted to make modifications to the file until the file lock has been released.'), "$year/$month/$day $hour:$min"). tag('br').tag('br').' '. picbutton(form => 'form', name => 'unlock_file', image => "unlockfile.gif"). tag('br').tag('br'); } else { lock_tables('READ','users'); my ($user) = db_select('info','users',"UID = '$description->{'LOCKED'}'"); unlock_tables(); my (undef, $min,$hour,$day,$month,$year) = utc_epoch2date($description->{'DATELOCKED'}); $file_status = sprintf($trans->gettext('This file has been locked by %s on %s. You cannot edit this file until the file lock has been released.'), $user->{'info'}, "$year/$month/$day $hour:$min"); if ($ADMIN_RIGHTS =~ /F0/) { $file_status .= tag('br').tag('br').' '. picbutton(form => 'form', name => 'unlock_file', image => "forceunlockfile.gif"). tag('br').tag('br'); } } $ref->{'maintemplate'} =~ s/<<file_status>>/$file_status/m; my $revision = $description->{'REVISION'} || '-'; unless ( $lock ) { $revision .= ' '.picbutton(form => 'form', name => 'new_revision', image => "uploadnewversion.gif"); } $ref->{'maintemplate'} =~ s/<<revision>>/$revision/m; my $downloads = $description->{'DOWNCOUNT'} || '0'; $ref->{'maintemplate'} =~ s/<<count_downloads>>/$downloads/m; my $filetype; if ($FILETYPE_CHECK) { $filetype = ucfirst `$config{'file_detect'} -b "$fmconfig{'resourceroot'}$category$form->{'dl'}" 2>&1`; } else {$filetype = $trans->gettext('Not available.');} $ref->{'maintemplate'} =~ s/<<file_type>>/$filetype/m; my @filestat = stat("$fmconfig{'resourceroot'}$category$form->{'dl'}"); my @date = utc_epoch2date($filestat[9]); $ref->{'maintemplate'} =~ s/<<last_mod>>/$date[5]\/$date[4]\/$date[3]\ \;$date[2]\:$date[1]/m; $ref->{'maintemplate'} =~ s/<<editbuttons>>/$editbuttons/m; $ref->{'maintemplate'} =~ s/<<rename>>/html_escape($form->{'dl'})/me; $ref->{'maintemplate'} =~ s/<<description>>/$description_box/m; }