package Admin::Filemanager;
use strict;
#################################################################################
# Ikonboard v3 by Jarvis Entertainment Group, Inc.
#
# No part of this script can be used outside Ikonboard without prior consent.
#
# More information available from <ib-license@jarvisgroup.net>
# (c)2001-2002 Jarvis Entertainment Group, Inc.
# 
# http://www.ikonboard.com | http://www.jarvisgroup.net
#
# Please read the license for more information
#
# 
#
#################################################################################

BEGIN {
    require 'Lib/FUNC.pm';
    require 'Lib/ADMIN.pm';
    require 'Admin/SKIN.pm';
    require 'Boardinfo.pm' or die "Cannot load Module: $!";
}

my $SKIN  = Admin::SKIN->new();
my $std   = FUNC::STD->new();
my $ADMIN = FUNC::ADMIN->new();
my $INFO  = Boardinfo->new();

use File::Path;

# Initialise our file extensions hash
my $EXT = {
            'gif'       => ['image.gif','GIF File'   ],
            'jpg'       => ['image.gif','JPEG File'  ],
            'jpeg'      => ['image.gif','JPEG File'  ],
            'bmp'       => ['image.gif','BMP File'   ],
            'txt'       => ['text.gif' ,'Text File'  ],
            'cgi'       => ['script.gif' ,'GCI Script' ],
            'pl'        => ['script.gif' ,'Perl Script'],
            'pm'        => ['script.gif' ,'Perl Module'],
            'js'        => ['script.gif' ,'JS Source'  ],
            'css'       => ['text.gif' ,'CSS Source' ],
            'zip'       => ['zip.gif'  ,'ZIP File'   ],
            'gz'        => ['zip.gif'  ,'Compressed File'],
            'tar'       => ['zip.gif'  ,'TAR File'],
            'htm'       => ['html.gif' ,'HTML File'],
            'html'      => ['html.gif' ,'HTML File'],
            'shtm'      => ['html.gif' ,'HTML File'],
            'shtml'     => ['html.gif' ,'HTML File'],
            'wav'       => ['sound.gif','Sound File'],
            'au'        => ['sound.gif','Sound File'],
            'mid'       => ['sound.gif','Sound File'],
            'mod'       => ['sound.gif','Sound File'],
            'exe'       => ['binary.gif','Binary File'],
            'unknown'   => ['unknown.gif',''],
            'db'        => ['quill.gif','DBM DB File'],
            'pag'       => ['quill.gif','DBM DB File'],
         };  

sub new {
    my $pkg = shift;
    my $obj = {};
    bless $obj, $pkg;
    return $obj;
}





##########################################################################################
#
# Print out the frames.
#
##########################################################################################
sub splash {
    my ($obj, $db) = @_;

    my $html = qq~ <html>
                  <head>
                      <title>Ikonboard Control Panel</title>
                  </head>
                 <frameset rows="*,85" framespacing=0>
                   <frame name="MAIN" src="$INFO->{'BOARD_URL'}/ikonboard.$INFO->{'CGI_EXT'}?AD=1&act=file&CODE=main&s=$iB::SESSION" frameborder="1" bordercolor='EEEEEE'>
                   <frame name="BAR" src="$INFO->{'BOARD_URL'}/ikonboard.$INFO->{'CGI_EXT'}?AD=1&act=file&CODE=bar&s=$iB::SESSION" scrolling="no" noresize frameborder="0" target="MAIN">
                   <noframes>
                   <body bgcolor="#FFFFFF">
                   <p>The Ikonboard AdminCP requires you to use a frames enabled browser..</p>
                   </body>
                   </noframes>
                 </frameset>
                 </html>
                ~;

    $ADMIN->Print( DB => $db, STD => $std, OUTPUT => $html );
}


sub bar {
    my ($obj, $db) = @_;
    # Insert a blank page until javascript catches up..
    my $html = "<html><body bgcolor='#EEEEEE'></body></html>";
    $ADMIN->Print( DB => $db, STD => $std, OUTPUT => $html );
}




sub main {
    my ($obj, $db) = @_;
    $obj->show_dir($db);
}



sub show_dir {
    my ($obj, $db, $msg) = @_;

    $msg ||= '';

    # Build up our links list....
    
    my $links = "<a href='$obj->{base_url}"."&CODE=display' target='MAIN'>Root</a>";
    my $rl_pth;
    my $rl_parent;
    my $p_cnt;
    my $r_cnt = $obj->{path_parts} ? scalar @{$obj->{path_parts}} : 0;
    for my $p (@{$obj->{path_parts}}) {
        ++$p_cnt;
        $rl_pth    .= ($rl_pth    ? '/' : '') . $p;
        $rl_parent .= ($rl_parent ? '/' : '') . $p if $p_cnt < $r_cnt;
        $links  .= "&nbsp;/&nbsp;<a href='$obj->{base_url}"."&CODE=display&pth=$rl_pth' target='MAIN'>$p</a>";
    }

    my $html = qq~ <html>
                   <head>
                      <title>Functions Bar</title>
                     <style type="text/css">
                     TABLE, TD, TR, BODY    { font-family: Verdana, Arial; font-size: 11px; color: #000000 }
                     a:link, a:active, a:visited { text-decoration:underline; color:#000033; }
                     a:hover { text-decoration:underline; color:#000099; }
                     </style>
                     <script language='JavaScript'>
                     <!--
                     var introMessage = "$msg";

                     function CheckAll(cb) {
                         var fmobj = document.MAIN_FORM;
                         for (var i=0;i<fmobj.elements.length;i++) {
                             var e = fmobj.elements[i];
                             if ((e.name != 'allbox') && (e.type=='checkbox') && (!e.disabled)) {
                                 e.checked = fmobj.allbox.checked;
                             }
                         }
                     }
                     function CheckCheckAll(cb) {	
                         var fmobj = document.MAIN_FORM;
                         var TotalBoxes = 0;
                         var TotalOn = 0;
                         for (var i=0;i<fmobj.elements.length;i++) {
                             var e = fmobj.elements[i];
                             if ((e.name != 'allbox') && (e.type=='checkbox')) {
                                 TotalBoxes++;
                                 if (e.checked) {
                                     TotalOn++;
                                 }
                             }
                         }
                         if (TotalBoxes==TotalOn) {fmobj.allbox.checked=true;}
                         else {fmobj.allbox.checked=false;}
                     }
                     function check_selected(multi) {
                         var fmobj = document.MAIN_FORM;
                         var count = 0;
                         var _checked;
                         for (var i=0;i<fmobj.elements.length;i++)
                             {
                             var e = fmobj.elements[i];
                             if ((e.name != 'allbox') && (e.type=='checkbox')&& (e.checked)) {
                                 _checked = true;
                                 count++;
                             }
                             if (count>1) {break}
                         }
                         if (! _checked) {
                             if (multi) {return 'Please select files or directories.';}
                             else {return 'Please select a file.';}
                         }
                         if (count > 1 && multi == false) {
                             return 'Can not execute this command on multiple files.'
                         }
                         return;
                     }
                     function PopUp(url, name, width,height,center,resize,scroll,posleft,postop) {
                         if (posleft != 0) { x = posleft }
                         if (postop  != 0) { y = postop  }
                     
                         if (!scroll) { scroll = 1 }
                         if (!resize) { resize = 1 }
                     
                         if ((parseInt (navigator.appVersion) >= 4 ) && (center)) {
                           X = (screen.width  - width ) / 2;
                           Y = (screen.height - height) / 2;
                         }
                         if (scroll != 0) { scroll = 1 }
                     
                         var Win = window.open( url, name, 'width='+width+',height='+height+',top='+Y+',left='+X+',resizable='+resize+',scrollbars='+scroll+',location=no,directories=no,status=no,menubar=no,toolbar=no');
                     }
                      function draw_footer(action) {
                         var doc = parent.BAR.document;
                         doc.clear();
                         doc.write("<html>");
                         doc.write("<head>");
                         doc.write("   <title>Functions Bar</title>");
                         doc.write("  <style type='text/css'>");
                         doc.write("  TABLE, TD, TR, BODY    { font-family: Verdana, Arial; font-size: 11px; color: #000000 }");
                         doc.write("  a:link, a:active, a:visited { text-decoration:underline; color:#000033; }");
                         doc.write("  a:hover { text-decoration:underline; color:#000099; }");
                         doc.write("  </style>");
                         doc.write("</head>");
                         doc.write("<body bgcolor='#EEEEEE' tomargin='0' leftmargin='0' marginheight='0' marginwidth='0'>");
                         doc.write("<table cellspacing='1' cellpadding='0' bgcolor='#333366' border='0' width='95%' align='center'>");
                         doc.write("<tr>");
                         doc.write("  <td>");
                         doc.write("     <table cellspacing='1' cellpadding='4' bgcolor='#333366' border='0' width='100%' align='center'>");
                         doc.write("      <tr>");
                         doc.write("       <td bgcolor='#FFFFFF'>Commands: <a href='javascript:parent.MAIN.do_chmod()'>Chmod Selected Files</a> :: <a href='javascript:parent.MAIN.do_rename()'>Rename Selected File</a> :: <a href='javascript:parent.MAIN.do_delete()'>Delete Selected Files</a> :: <a href='javascript:parent.MAIN.do_upload()'>Upload a file</a></td>");
                         doc.write("     </tr>");
                         doc.write("     <tr>");
                         doc.write("     </table>");

                         if (action == 'chmod') {
                            write_chmod(doc);
                         }
                         if (action == 'delete') {
                            write_delete(doc);
                         }
                         if (action == 'rename') {
                            write_rename(doc);
                         }
                         if (action == 'upload') {
                            write_upload(doc);
                         }

                         doc.write("</td></tr></table></body></html>");
                         doc.close();

                         //-------------------------------------------
                         // Have we a message in a bottle?
                         //-------------------------------------------
                         if (introMessage != '') {
                             var tempMessage = introMessage;
                             introMessage = '';
                             alert(tempMessage);
                         }


                      }
                      function write_chmod(doc) {
                         doc.write("<table cellspacing='1' cellpadding='4' bgcolor='#333366' border='0' width='100%' align='center'><tr><td bgcolor='#FFFFFF'><form target='MAIN' name='bottomForm'>Enter the numeric CHMOD value: &nbsp;<input type='text' name='the_value' value='' size='4' onFocus='this.select()'>&nbsp;&nbsp;&nbsp;<input type='button' value=' CHMOD ' onClick='parent.MAIN.process_chmod()'></form></td></tr></table>");
                      }
                      function write_rename(doc) {
                         doc.write("<table cellspacing='1' cellpadding='4' bgcolor='#333366' border='0' width='100%' align='center'><tr><td bgcolor='#FFFFFF'><form target='MAIN' name='bottomForm'>Enter the new name for this file: &nbsp;<input type='text' name='the_value' value='' onFocus='this.select()'>&nbsp;&nbsp;&nbsp;<input type='button' value=' RENAME ' onClick='parent.MAIN.process_rename()'></form></td></tr></table>");
                      }
                      function write_delete(doc) {
                         doc.write("<table cellspacing='1' cellpadding='4' bgcolor='#333366' border='0' width='100%' align='center'><tr><td bgcolor='#FFFFFF'><form target='MAIN' name='bottomForm'>Delete empty directories (if chosen)?: &nbsp;<input type='checkbox' name='empty' value='1' checked>&nbsp;&nbsp;&nbsp;Delete full directories (if chosen)?&nbsp;<input type='checkbox' name='full' value='1'>&nbsp;&nbsp;&nbsp;<input type='button' value=' DELETE FILES ' onClick='parent.MAIN.process_delete()'></form></td></tr></table>");
                      }
                      function write_upload(doc) {
                         doc.write("<table cellspacing='1' cellpadding='4' bgcolor='#333366' border='0' width='100%' align='center'><tr><td bgcolor='#FFFFFF'><form name='bottomForm' enctype='multipart/form-data' method='post' target='MAIN' action='$iB::INFO->{'BOARD_URL'}/ikonboard.$iB::INFO->{'CGI_EXT'}'><input type='hidden' name='pth' value='$rl_pth'><input type='hidden' name='AD' value='1'><input type='hidden' name='act' value='file'><input type='hidden' name='s' value='$iB::SESSION'><input type='hidden' name='CODE' value='upload'>Name of file to upload into the current directory: &nbsp;<input type='file' name='the_value' value=''>&nbsp;&nbsp;&nbsp;<input type='button' value=' UPLOAD ' onClick='parent.MAIN.process_upload()'></form></td></tr></table>");
                      }
                      function do_chmod() {
                         draw_footer('chmod');
                      }
                      function do_rename() {
                         draw_footer('rename');
                      }
                      function do_delete() {
                         draw_footer('delete');
                      }
                      function do_upload() {
                         draw_footer('upload');
                      }

                      function process_chmod() {

                         var msg = check_selected(1);
                         if (msg) { alert (msg); return false;}
                         var main_form   = document.MAIN_FORM;
                         var bottom_form = window.parent.BAR.document.bottomForm;

                         main_form.the_value.value = bottom_form.the_value.value;
                         
                         if (bottom_form.the_value.value.length != 4) {
                             alert("CHMOD value must contain 4 numerals in the following format\\n----------------\\n0XXX (Replace X with a number)\\n----------------\\nExamples:\\n0777 is world writable\\n0755 is script executable");
                             return false;
                         }


                         main_form.CODE.value = 'chmod';
                         main_form.submit();
                      }

                      function process_rename() {

                         var msg = check_selected(0);
                         if (msg) { alert (msg); return false;}
                         var main_form   = document.MAIN_FORM;
                         var bottom_form = window.parent.BAR.document.bottomForm;

                         main_form.the_value.value = bottom_form.the_value.value;
                         
                         if (bottom_form.the_value.value == '') {
                             alert("You must enter a new name for this file");
                             return false;
                         }


                         main_form.CODE.value = 'rename';
                         main_form.submit();
                      }

                      function process_delete() {

                         var msg = check_selected(1);
                         if (msg) { alert (msg); return false;}
                         var main_form   = document.MAIN_FORM;
                         var bottom_form = window.parent.BAR.document.bottomForm;

                         main_form.del_full.value  = bottom_form.full.checked  ? 1  : 0;
                         main_form.del_empty.value = bottom_form.empty.checked ? 1  : 0;
                         
                         main_form.CODE.value = 'delete';
                         main_form.submit();
                      }
                         
                      function process_upload() {

                         var main_form   = document.MAIN_FORM;
                         var bottom_form = window.parent.BAR.document.bottomForm;
                         
                         if (bottom_form.the_value.value == '') {
                             alert("You must enter a name for a file to upload");
                             return false;
                         }

                         bottom_form.submit();
                      }
                     //-->
                     </script>
                   </head>
                   <body bgcolor='#EEEEEE' tomargin='0' leftmargin='0' marginheight='0' marginwidth='0' onload='draw_footer()'>
                   <table cellspacing='1' cellpadding='0' bgcolor='#EEEEEE' border='0' width='95%' align='center'>
                   <tr>
                     <td>
                        <table cellspacing='1' cellpadding='4' bgcolor='#333366' border='0' width='100%' align='center'>
                        <tr>
                           <td bgcolor='#8888AA' style='color:white'>Ikonboard file manager</td>
                         </tr>
                         <tr>
                           <td bgcolor='#EEEEEE'>Directory Path: $links</td>
                         </tr>
                        </table>
                     </td>
                   </tr>
                   </table>
                   <br>
                   <form action='$iB::INFO->{'BOARD_URL'}/ikonboard.$iB::INFO->{'CGI_EXT'}' method='post' name='MAIN_FORM'>
                   <table cellspacing='1' cellpadding='0' bgcolor='#333366' border='0' width='95%' align='center'>
                   <tr>
                     <td>
                        <table cellspacing='1' cellpadding='4' bgcolor='#333366' border='0' width='100%' align='center'>
                         <tr>
                           <td bgcolor='#8888AA' style='color:white' width='1%'><input name="allbox" type="checkbox" value="Check All" onClick="CheckAll();"></td>
                           <td bgcolor='#8888AA' style='color:white' width='4%'>&nbsp;</td>
                           <td bgcolor='#8888AA' style='color:white' width='30%'><b>Name</b></td>
                           <td bgcolor='#8888AA' style='color:white' width='10%'><b>Size</b></td>
                           <td bgcolor='#8888AA' style='color:white' width='12%'><b>Type</b></td>
                           <td bgcolor='#8888AA' style='color:white' width='16%'><b>Modified</b></td>
                           <td bgcolor='#8888AA' style='color:white' width='13%'><b>Owner</b></td>
                           <td bgcolor='#8888AA' style='color:white' width='14%'><b>Permissions</b></td>
                         </tr>
                 ~;

    my $colour = { one => 'FFFFFF',
                   two => 'EEEEEE',
                 };

    # Get the directory contents...

    opendir DIR, $obj->{full_path} or die "Cannot open directory: $obj->{full_path}: $!";
    my @files = readdir DIR;
    closedir DIR;

    my $cnt    = 0;

    # Do we have a parent directory to print first?

    if ($obj->{work_path}) {

        $html .= qq~<tr>
                      <td bgcolor='#DDDDDD' width='1%' align='center'>&nbsp;</td>
                      <td bgcolor='#DDDDDD' width='4%'><img src='$INFO->{'IMAGES_URL'}/sys-img/icons/parent.gif' border='0' alt='parent'></td>
                      <td bgcolor='#DDDDDD' width='30%'><b><a href='$obj->{base_url}&CODE=display&pth=$rl_parent' target='MAIN'>Parent Directory</a></b></td>
                      <td bgcolor='#DDDDDD' width='10%'>&nbsp;</td>
                      <td bgcolor='#DDDDDD' width='12%'>&nbsp;</td>
                      <td bgcolor='#DDDDDD' width='16%'>&nbsp;</td>
                      <td bgcolor='#DDDDDD' width='13%'>&nbsp;</td>
                      <td bgcolor='#DDDDDD' width='14%'>&nbsp;</td>
                    </tr>
                   ~;
    }


    # Loop through and build our list..

    for my $f ( sort { $a cmp $b } @files) {
        next if $f =~ /^\.{1,}/;
        my $full_path = $obj->{full_path} . '/'. $f;
        my @stat = stat($full_path);
        my $details = { 
                         name =>  $f,
                         size =>  &_get_size($stat[7]),
                         date =>  &_get_date($stat[9]),
                         perm =>  &_get_permissions($stat[2]),
                      };
        {
            local $@, $SIG{__DIE__};
            unless ($^O eq 'MSWin32') {
                $details->{'user'} = eval { getpwuid($stat[4]); } || '';
            } else {
                 $details->{'user'} = "n/a";
            }
        }

        if (-d $full_path) {
            $details->{size} = '&nbsp;';
            my $tmp = $obj->{work_path}.'/'.$f;
            $tmp =~ s!^[/\\]!!;
            $tmp =~ s![/\\]$!!;
            $details->{name} = qq~<b><a href='$obj->{base_url}&CODE=display&pth=$tmp' target='MAIN'>$f</a></b>~;
            $details->{icon} = 'folder.gif';
            $details->{type} = 'Directory';
        } else {
            my $what_is_it = &_get_icon($f);
            $details->{icon} = $what_is_it->{icon};
            $details->{type} = $what_is_it->{type};
            $details->{name} = qq~<a href="javascript:PopUp('$iB::INFO->{'BOARD_URL'}/ikonboard.$iB::INFO->{'CGI_EXT'}?s=$iB::SESSION&AD=1&act=file&CODE=show&pth=$obj->{work_path}&file=$f','Show','400','400','0','1','1','1')">$f</a>~;
        }

        $details->{colour} = $cnt ? eval  { $cnt = 0;  $colour->{one}; }
                                  : eval  { $cnt = 1;  $colour->{two}; };


        $html .= qq~<tr>
                      <td bgcolor='#$details->{colour}' width='1%' align='center'><input type='checkbox' name='chosen' value='$f' onClick="CheckCheckAll(this);"></td>
                      <td bgcolor='#$details->{colour}' width='4%'><img src='$INFO->{'IMAGES_URL'}/sys-img/icons/$details->{icon}' border='0' alt='$details->{icon}'></td>
                      <td bgcolor='#$details->{colour}' width='30%'>$details->{name}</td>
                      <td bgcolor='#$details->{colour}' width='10%'>$details->{size}</td>
                      <td bgcolor='#$details->{colour}' width='12%'>$details->{type}</td>
                      <td bgcolor='#$details->{colour}' width='16%'>$details->{date}</td>
                      <td bgcolor='#$details->{colour}' width='13%'>$details->{user}</td>
                      <td bgcolor='#$details->{colour}' width='14%'>$details->{perm}</td>
                    </tr>
                   ~;
    }

    $html .= qq~   </table>
                  </td>
                 </tr>
                </table>
                <!-- FIELDS -->
                <input type='hidden' name='AD' value='1'>
                <input type='hidden' name='act' value='file'>
                <input type='hidden' name='CODE' value=''>
                <input type='hidden' name='the_value' value=''>
                <input type='hidden' name='pth' value='$rl_pth'>
                <input type='hidden' name='del_full'  value=''>
                <input type='hidden' name='del_empty' value=''>
                </form>
                </body>
               </html>
               ~;

    $ADMIN->Print( DB => $db, STD => $std, OUTPUT => $html );
}

##########################################################################################
#
# CHMOD a file(s)
#
##########################################################################################

sub chmod {
    my ($obj, $db) = @_;
    my @files = $iB::CGI->param('chosen');
    # Get the octal representation
    my $oct = oct($iB::IN{'the_value'});
    my $count = 0;
    my $failed = 0;
    for my $f (@files) {
        my $tmp = $obj->{full_path}."/$f";
        if (chmod ($oct, $tmp)) {
            $count++;
        } else {
            $failed++;
        }
    }
    $obj->show_dir($db, "CHMOD Permissions change result\\n\\n-$count- files changed successfully,\\n-$failed- files failed due to insufficient permission");
}

sub rename {
    my ($obj, $db) = @_;
    my $file = $iB::CGI->param('chosen');
    # Make sure we only have one file..
    if (ref $file eq 'ARRAY') {
         $ADMIN->Error( DB => $db, STD => $std, MSG => "Sorry, you can only rename one file at a time.");
    }
    my $count = 0;
    my $new_name = $obj->{full_path}."/$iB::IN{'the_value'}";
    my $old_name = $obj->{full_path}."/$file";
    if (rename($old_name, $new_name)) {
        $count++;
    }
    my $msg = $count ? "Renamed -$file- to -$iB::IN{'the_value'}-" : "Could not rename that file";
    $obj->show_dir($db, $msg);
}

sub upload {
    my ($obj, $db) = @_;

    my $data        = $iB::CGI->param('the_value');
    my $filename    = $data;
    $filename       =~ s/.*?([^\\\/:]+)$/$1/;

    my $save_as = $obj->{full_path}."/$filename";

    # Does the file already exist?
    if (-e $save_as) {
            $obj->show_dir($db, "Cannot upload, file already exists");
    } else { 

        my ($bytesread, $buffer, $size);
        open    (OUTFILE, ">$save_as");
        # Turn on binmode for Win servers, it won't affect
        # unix servers (we hope)
        binmode (OUTFILE); 
        while ($bytesread = read($data,$buffer,1024)) {
            $size += $bytesread;
            print OUTFILE $buffer;
        }
        close OUTFILE;

        $size = &_get_size($size);
    
        $obj->show_dir($db, "File uploaded ($size)");
    }
}

sub delete {
    my ($obj, $db) = @_;
    my @files = $iB::CGI->param('chosen');
    my $f_count = 0;
    my $f_failed = 0;
    my $d_count = 0;
    my $d_failed = 0;
    for my $f (@files) {
        my $tmp = $obj->{full_path}."/$f";
        if (-d $tmp) {
            # Is it empty?
            my $dir_files = $obj->_read_dir($tmp);
            if (scalar @$dir_files > 0) {
                # Are we removing full directories?
                if ($iB::IN{'del_full'}) {
                    rmtree $tmp;
                    ++$d_count;
                } else {
                    ++$d_failed;
                }
            } elsif ($iB::IN{'del_empty'}) {
                if ( rmdir ($tmp) ) {
                    ++$d_count;
                } else {
                    ++$d_failed;
                }
            } else {
                ++$d_failed;
            }
        } else {
            if ( unlink ($tmp) ) {
                ++$f_count;
            } else {
                ++$f_failed;
            }
        }
    }
    $obj->show_dir($db, "Delete Files Result\\n\\n-$f_count- files deleted,\\n-$f_failed- files could not be deleted\\n\\n-$d_count- directories deleted,\\n-$d_failed- directories could not be deleted");
}

##########################################################################################
#
# Show a file
#
##########################################################################################

sub show {
    my ($obj, $db) = @_;

    # Do some set up..

    my $file = $iB::CGI->param('file');
    my $path = $obj->{work_path};
    my $full = $obj->{full_path};

    my $gfx_ext = 'bmp gif jpg jpeg tif tiff';

    my $url  = "$iB::INFO->{'BOARD_URL'}/" . ($obj->{work_path} ? "$obj->{work_path}/" : '')
              ."$file";

    my ($ext) = $file =~ /\.([^.]+)$/;

    my $html = qq~ <html>
                   <head>
                      <title>File Viewer</title>
                     <style type="text/css">
                     TABLE, TD, TR, BODY    { font-family: Verdana, Arial; font-size: 11px; color: #000000 }
                     a:link, a:active, a:visited { text-decoration:underline; color:#000033; }
                     a:hover { text-decoration:underline; color:#000099; }
                     </style>
                   </head>
                   <body bgcolor='#EEEEEE' tomargin='0' leftmargin='0' marginheight='0' marginwidth='0'>
                   <table cellspacing='1' cellpadding='0' bgcolor='#333366' border='0' width='95%' align='center'>
                   <tr>
                     <td>
                        <table cellspacing='1' cellpadding='4' bgcolor='#333366' border='0' width='100%' align='center'>
                         <tr>
                           <td bgcolor='#8888AA' style='color:white'>Showing File: Root / $path / <b>$file<b></td>
                         </tr>
                        <tr>
                         <td bgcolor='#FFFFFF'>
                 ~;

    # if it's a text file...

    if ( $file =~ /^boardinfo\.pm$/i ) {
        # It's the boardinfo file, do not display
        $html .= qq~<b>You cannot view the Ikonboard configuration file in the filemanager for security reasons</b>~;
    } elsif (-T "$obj->{full_path}/$file") {
        open THEFILE, "$obj->{full_path}/$file" or die "Cannot open $file: $!";
        my @data = <THEFILE>;
        close THEFILE;
        my $string = join '', @data;

        # Swop hard returns
        $string =~ s!\r\n!\n!g;
        # Make HTML safe
        $string =~ s!<!&lt;!g;
        $string =~ s!>!&gt;!g;
        # Swop line returns into <BR>
        $string =~ s!\n!<br>!g;
        # Make 4 spaces into tabs..
        $string =~ s!\s{4}!\t!g;
        # Turn tabs into something HTML can understand
        $string =~ s!\t!&nbsp;&nbsp;&nbsp;&nbsp;!g;

        # Print it..
        $html .= $string;

    } elsif ( $gfx_ext =~ /$ext/i) {
        # Simply display the image..
        $html .= qq~<center><img src="$url" border='0' alt=''></center>~;
    } else {
        # It's unknown..
        $html .= qq~<b>Cannot display file: Unknown file type<br><br><br><a href='$url' target='_blank'>Download this file?</a></b>~;
    }

    $html .= qq~   </td>
                  </tr>
                 </table>
                </td>
                </tr>
                </table>
                </body>
                </html>
                ~;
    $ADMIN->Print( DB => $db, STD => $std, OUTPUT => $html );
}

##########################################################################################
#
# Process Sub
#
##########################################################################################


sub process {
    my ($obj, $db) = @_;

    # Set up or session
    $obj->_set_state($db);

    my $CodeNo = $iB::IN{'CODE'};

    my %Mode = ( 'main'        => \&main,
                 'bar'         => \&bar,
                 'display'     => \&show_dir,
                 'show'        => \&show,
                 'chmod'       => \&chmod,
                 'rename'      => \&rename,
                 'delete'      => \&delete,
                 'upload'      => \&upload,
               );
    $Mode{$CodeNo} ? $Mode{$CodeNo}->($obj,$db) : splash($obj,$db);
} 

sub _set_state {
    my ($obj, $db) = @_;

    # Only allow super admins access...

    unless ($iB::MEMBER->{'MEMBER_GROUP'} == $iB::INFO->{'SUPAD_GROUP'}) {
        $ADMIN->Error( DB => $db, STD => $std, MSG => "Sorry, only the board owners have access to this part");
    }



    $obj->{base_url} = "$INFO->{'BOARD_URL'}/ikonboard.$iB::INFO->{'CGI_EXT'}?AD=1&act=file";

    # Parse incoming data
    if ($iB::IN{'pth'}) {
        # Make sure we're not attempting to go above our root.
        # Otherwise people on shared hosting may be able to 'see'
        # other peoples accounts...
        if ($iB::IN{'pth'} =~ /\.{1,}/) {
            $ADMIN->Error( DB => $db, STD => $std, MSG => "Invalid path (cannot contain periods)");
        }
        $obj->{work_path} = $iB::CGI->param('pth');
        @{$obj->{path_parts}} = split(/\//,$obj->{work_path});
    }
    $obj->{full_path} = $iB::INFO->{'IKON_DIR'} .'/'. $obj->{work_path};
    # Remove any trailing slashes...
    $obj->{full_path} =~ s![/\\]$!!;

}

sub _get_permissions {

    my $chmod  = shift;
    return "---" unless $chmod;
    return if $^O eq 'MSWin32';
    my $str = sprintf "%lo", ($chmod & 07777);
    my $perm = '';
    foreach (split(//, $str)) {
        if    ($_ == 7) { $perm .= "rwx "; }
        elsif ($_ == 6) { $perm .= "rw- "; }
        elsif ($_ == 5) { $perm .= "r-x "; }
        elsif ($_ == 4) { $perm .= "r-- "; }
        elsif ($_ == 3) { $perm .= "-wx "; }
        elsif ($_ == 2) { $perm .= "-w- "; }
        elsif ($_ == 1) { $perm .= "--x "; }
        elsif ($_ == 0) { $perm .= "--- "; }
        else            { $perm .= "unkown '$_'!"; }
    }
    return $perm;
}

sub _get_date {
    my $time = shift;
    $time or ($time = time);
    my @months = qw!Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec!;

    my ($min, $hr, $day, $mon, $yr) = (localtime($time))[1,2,3,4,5];
    $yr = $yr + 1900;
    ($min < 10) and ($min = "0$min");
    ($hr  < 10) and ($hr  = "0$hr");
    ($day < 10) and ($day = "0$day");

    return "$day-$months[$mon]-$yr $hr:$min";
}

sub _get_size {
    my $size = shift;
    my $f_size = 0;
    $f_size = int($size / 1000) if ($size);
    return $f_size == 0 ? "$size bytes" : $f_size." kb";
}

sub _read_dir {
    my ($obj, $path) = @_;
    
    # open the dir and suck it in...
    opendir DIR, $path or die "Cannot open directory: $!";
    my @files = grep { !/^\./ } readdir DIR;
    closedir DIR;

    return \@files;
}

sub _get_icon {
    
    my $file = shift;
    my ($ext) = $file =~ /\.([^.]+)$/;

    return { icon => 'unknown.gif',
             type => 'unknown'
           } unless $ext;

    foreach ( keys %{$EXT} ) {
        next if (/folder/);
        next if (/unknown/);
        next if (/parent/);
        if (lc($_) eq $ext) {
            return { icon => $EXT->{$_}[0],
                     type => $EXT->{$_}[1]
                   };
        }
    }
    return { icon => 'unknown.gif',
             type => 'unknown'
           };
}

sub DESTROY { }


1;