#
# autopsyfunc.pm
# Autopsy Forensic Browser
#
# This file requires The Sleuth Kit
#    www.sleuthkit.org
#
# version 1.71+
# Brian Carrier [carrier@sleuthkit.org]
# Copyright (c) 2003 by Brian Carrier.  All rights reserved
#
# version 1.5, 1.6, 1.7
# Copyright (c) 2001-2003 by Brian Carrier, @stake Inc.  All rights reserved
#
# version 1.0
# Brian Carrier [carrier@cerias.purdue.edu]
# Copyright (c) 2001 by Brian Carrier.  All rights reserved
#
#
# This file is part of the Autopsy Forensic Browser (Autopsy)
#
# Autopsy 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.
#
# Autopsy is distributed in the 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 Autopsy; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#
# THIS SOFTWARE IS NOT AFFILIATED WITH PURDUE UNIVERSITY OR THE CENTER FOR
# EDUCATION IN INFORMATION ASSURANCE AND SECURITY (CERIAS) AND THEY BEAR
# NO RESPONSIBILITY FOR ITS USE OR MISUSE.
#
#
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
# IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, OR PROFITS OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#


#
# This file has become a huge mess!  The history behind this is that it
# was originally designed as a single CGI script.  The basic flow is that
# every HTML page or frameset has a different 'func' value in the URL.      
# There is an array of functions and the 'func' value is the index into
# that array.  Every request is first sent to 'autopsy_main' where basic
# arguments are checked and then the specific function is called.  It
# checks the specific arguments (using the check_*() functions) and the
# proper data is displayed to STDOUT, which is the socket.
#

use lib './';
use strict;
require 'conf.pl';
require 'fs.pl';
require 'define.pl';
require 'search.pl';

# Get rid of insecure settings
$ENV{PATH} = "";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

# import variables from conf.pl
use vars '$PROGNAME', '$TASKDIR', '$LOCKDIR';
use vars '$VER', '$GREP_EXE', '$STRINGS_EXE';
use vars '$SANITIZE_TAG';
use vars '$AUT_HOME_PAGE', '$MD5_FILE';
use vars '$USE_NOTES', '$USE_LOG';
use vars '$IMGDIR', '$DATADIR', '$LOGDIR', '$REPDIR';
use vars '$NSRLDB', '$HTTP_NL';
use vars '%first_inode', '%root_inode', '%addr_unit', '%first_addr';
use vars '%ctime_str', '%mtime_str', '%auto_srch', '%auto_srch_reg';
use vars '%auto_srch_csense', '%meta_str';


# Formats for regular expressions
# Year.Mon.Day Hr:Min:Sec (TZ)
my $REG_DAY = '\d\d\d\d.\d\d.\d\d';
my $REG_TIME = '\d\d:\d\d:\d\d';
my $REG_ZONE1 = '[\w\+\-]+';
my $REG_ZONE2 = '\([\w\+\-]+\)';
my $REG_DATE = "$REG_DAY".'\s+'."$REG_TIME".'\s+'."$REG_ZONE2";
my $REG_FTYPE = '[\w\-]+';
my $REG_SKEW = '[\+\-]?\d+';


my $REG_FILE = '[\w\-\_\.]+';
my $REG_IMG = "$REG_FILE".'/'."$REG_FILE";
my $REG_IMG_PATH = '/[\w\-\_\.\/]+';
my $REG_CASE = $REG_FILE;
my $REG_HOST = $REG_FILE;
my $REG_FNAME = $REG_FILE;
my $REG_MNT = '[\w\-\_\.\/\:\\\\]+';
my $REG_HASHDB = '[\w\-\_\.\,\/]+';
my $REG_BODY = $REG_FILE;
my $REG_TL = $REG_FILE;

my $REG_INODE = '[\d-]+';
my $REG_MD5 = '[0-9a-fA-F]{32,32}';

my $REG_INVESTIG = '[\w]+';

my $HELP_URL = "help/index.html";

# Give new directories user and group write permissions
my $MKDIR_MASK = 0775;

# constants for different functions (the func argument)
my $WELCOME = 0x00;
my $BLANK = 0x01;

my $MAIN_FR = 0x02;      
my $MAIN_LO = $MAIN_FR;
my $MAIN_TABS = 0x03;
my $MAIN_MSG = 0x04;
my $MAIN_HI = $MAIN_MSG;       


my $SORTER_MAIN = 0x06;
my $SORTER_LO = $SORTER_MAIN;
my $SORTER_LIST = 0x07;
my $SORTER_ENT = 0x08;
my $SORTER_DOIT = 0x09;       
my $SORTER_HI = $SORTER_DOIT;      


my $NOTES_READ = 0x0A;
my $NOTES_LO = $NOTES_READ;
my $NOTES_MAIN = $NOTES_READ;
my $NOTES_WRITE = 0x0B;
my $NOTES_ENT = 0x0C;
my $NOTES_SEQ_READ = 0x0D;
my $NOTES_SEQ_WRITE = 0x0E;
my $NOTES_HI = $NOTES_SEQ_WRITE;

#################################################
# File Mode
my $FIL_LO = 0x10;       
my $FIL_MAIN = $FIL_LO + 0;
my $FIL_DIR = $FIL_LO + 1;
my $FIL_LIST = $FIL_LO + 2;
my $FIL_CONT = $FIL_LO + 3;
my $FIL_REP = $FIL_LO + 4;
my $FIL_CMENU_FR = $FIL_LO + 5;
my $FIL_CMENU = $FIL_LO + 6;
my $FIL_DEL = $FIL_LO + 7;
my $FIL_SAVE = $FIL_LO + 8;
my $FIL_MD5 = $FIL_LO + 9;
my $FIL_NAME = $FIL_LO + 10;
my $FIL_HI = $FIL_LO + 10;

# Sorting and display types
my $FIL_SORT_ASC=0;
my $FIL_SORT_STR=1;

# Methods of sorting the file listings
my $SORT_DTYPE=0;	# type according to dentry
my $SORT_ITYPE=1;	# type according to inode
my $SORT_NAME=2;
my $SORT_MOD=3;
my $SORT_ACC=4;
my $SORT_CHG=5;
my $SORT_SIZE=6;
my $SORT_GID=7;
my $SORT_UID=8;
my $SORT_INODE=9;
my $SORT_DEL=10;

my $DMODE_SHOW = 1;
my $DMODE_NOSHOW = 2;

#################################################
# Data Mode
my $BLK_MAIN = 0x20;
my $BLK_LO=$BLK_MAIN;
my $BLK_ENT = 0x21;
my $BLK_CONT = 0x22;
my $BLK_REP = 0x23;
my $BLK_CMENU_FR = 0x24;
my $BLK_CMENU = 0x25;
my $BLK_DLS = 0x26;
my $BLK_SAVE = 0x27;
my $BLK_HI=$BLK_SAVE;


# Display types that use the sort variable 
my $BLK_SORT_ASC=0;
my $BLK_SORT_HEX=1;
my $BLK_SORT_STR=2;

# Types of block numbers 
my $BTYPE_DD=0;
my $BTYPE_DLS=1;


#################################################
# Hash Database 
my $HASH_LO = 0x2A;
my $HASH_LOOKUP = $HASH_LO + 0;
my $HASH_INDEX = $HASH_LO + 1;
my $HASH_MAIN = $HASH_LO + 2;
my $HASH_HI = $HASH_LO + 2;




#################################################
# Search Mode
my $SRCH_ENT = 0x30;
my $SRCH_MAIN = $SRCH_ENT;
my $SRCH_LO = $SRCH_ENT;
my $SRCH_RMAIN = 0x31;
my $SRCH_DOSRCH = 0x32;
my $SRCH_READSRCH = 0x33;
my $SRCH_MAKESTR = 0x34;
my $SRCH_MAKEDLS = 0x35;
my $SRCH_HI = $SRCH_MAKEDLS;

# Types of modes for fname (i.e. can we overwrite it if it exists)
my $FNAME_MODE_INIT=0;
my $FNAME_MODE_OVER=1;



#################################################
# Sanitized Environment for picts and HTML
my $CELL_LO = 0x38;
my $CELL_MAIN = $CELL_LO + 0;
my $CELL_MENU = $CELL_LO + 1;
my $CELL_CONT = $CELL_LO + 2;
my $CELL_HI = $CELL_LO + 2;


#################################################
# Inode / Meta Mode
my $INO_MAIN = 0x40;
my $INO_LO = $INO_MAIN;
my $INO_ENT = 0x41;
my $INO_CONT = 0x42;
my $INO_SAVE = 0x43;
my $INO_REP = 0x44;
my $INO_ILS = 0x45;
my $INO_FFIND = 0x46;
my $INO_HI = $INO_FFIND;


################################################
# File System
my $FS_STAT = 0x50;
my $FS_LO = $FS_STAT;
my $FS_MAIN = $FS_STAT;
my $FS_HI = $FS_STAT;

################################################
# Integrity
my $INT_CHECK = 0x56;
my $INT_MAIN = $INT_CHECK;
my $INT_LO = $INT_CHECK;
my $INT_CREATE = 0x57;
my $INT_LIST_FR = 0x58;
my $INT_LIST = 0x59;
my $INT_HI = $INT_LIST;

################################################
# Timeline
my $TL_LO = 0x60;
my $TL_MAIN = $TL_LO + 0;
my $TL_BODY_ENT = $TL_LO + 1;
my $TL_BODY_DOIT = $TL_LO + 2;
my $TL_TL_ENT = $TL_LO + 3;
my $TL_TL_DOIT = $TL_LO + 4;
my $TL_VIEW_MENU = $TL_LO + 5;
my $TL_VIEW_FR = $TL_LO + 6;
my $TL_VIEW_IDX = $TL_LO + 7;
my $TL_VIEW_SUM = $TL_LO + 8;
my $TL_VIEW = $TL_LO + 9;
my $TL_TABS = $TL_LO + 10;
my $TL_HI = $TL_LO + 10;


################################################
# Setup / Menu values
my $CASE_OPEN = 0x70;
my $CASE_LO = $CASE_OPEN;
my $CASE_OPEN_LOG = 0x71;
my $CASE_NEW = 0x72;
my $CASE_NEW_DOIT = 0x73;
my $CASE_DETAILS = 0x74;
my $CASE_DEL = 0x75;
my $CASE_HI = $CASE_DEL;

my $HOST_OPEN = 0x76;
my $HOST_LO = $HOST_OPEN;
my $HOST_OPEN_LOG = 0x77;
my $HOST_ADD = 0x78;
my $HOST_ADD_DOIT = 0x79;
my $HOST_DETAILS = 0x7A;
my $HOST_DEL = 0x7B;
my $HOST_HI = $HOST_DEL;

my $IMG_OPEN = 0x7C;
my $IMG_LO = $IMG_OPEN;
my $IMG_OPEN_LOG = 0x7D;
my $IMG_ADD = 0x7E;
my $IMG_ADD_DOIT = 0x7F;
my $IMG_DETAILS = 0x80;
my $IMG_DEL = 0x81;
my $IMG_HI = $IMG_DEL;

my $IMG_ADD_SYM = 0x1;
my $IMG_ADD_COPY = 0x2;
my $IMG_ADD_MOVE = 0x3;


my $BACK_COLOR="#CCCC99";
my $BACK_COLOR_TABLE="#CCCCCC";
my @DEL_COLOR;
$DEL_COLOR[0] = "red";
$DEL_COLOR[1] = "#800000";	 # used when inode has been reallocated 
my $NORM_COLOR = "";
my $LINK_COLOR = "blue";

my $YEL_PIX = "pict/back_pix.jpg";

my @funcs;		# Array for function references
my %args;		# Arguments that are decoded
my %enc_args;	# Arguments that are encoded
my $baseargs;	# Arguments that never change such as case,host,mnt and img
my $baseargs_noimg;	# baseargs w/out img info


my %img2mnt;	# Mapping for mount point, given the image name
my %img2ftype;	# Mapping for file system type, given the image name
my %mod2img;	# Mapping for image, given the strings or dls 
my %img2str;	# Mapping for strings file, given  the image name
my %img2dls;	# Mapping for dls file, given  the image name

# hash databases 
# NSRL is global
my $exclude_db = "";
my $alert_db = "";

my $tz = "";
my $ts = 0;	# time skew (in seconds)
my $host_desc = "";
my $host_dir = "";
my $case_dir = "";

my $is_html = 0;
my $is_body = 0;


# Main Menu
#
# Display the title page 
$funcs[$WELCOME] = sub {
	print_javascript_header("Autopsy Forensic Browser");

print <<EOF;


<CENTER>
<TABLE CELLSPACING=0 CELLPADDING=2 WIDTH=600 HEIGHT=350 BORDER=0>

<TR>
  <TD COLSPAN=\"3\" ALIGN=\"CENTER\" VALIGN=\"MIDDLE\">
	<A HREF=\"./about\">
      <IMG SRC=\"pict/logo.jpg\" BORDER=0>
	</A>
  </TD>
</TR>
<TR>
  <TD COLSPAN=\"3\" ALIGN=\"CENTER\" VALIGN=\"MIDDLE\">
    <A HREF=$AUT_HOME_PAGE>
      <TT>$AUT_HOME_PAGE</TT>
    </A>
  </TD>
</TR>
<TR><TD COLSPAN=3>&nbsp;</TD></TR>
<TR>
  <TD ALIGN=CENTER WIDTH=200 VALIGN=\"MIDDLE\">
    <A HREF=\"$PROGNAME?func=$CASE_OPEN\">
      <IMG SRC=\"pict/menu_b_copen.jpg\" ALT=\"Open Case\" WIDTH=176 BORDER=0>
    </A>
  </TD>
  <TD ALIGN=CENTER WIDTH=200 VALIGN=\"MIDDLE\">
    <A HREF=\"$PROGNAME?func=$CASE_NEW\">
      <IMG SRC=\"pict/menu_b_cnew.jpg\" ALT=\"New Case\" WIDTH=176 BORDER=0>
    </A>
  </TD>
  <TD ALIGN=CENTER WIDTH=200 VALIGN=\"MIDDLE\">
    <A HREF=\"$HELP_URL\" TARGET=\"_blank\">
      <IMG SRC=\"pict/menu_b_help.jpg\" ALT=\"Help\" WIDTH=167 BORDER=0>
    </A>
  </TD>
</TR>
</TABLE>

EOF

	return;
};


# create the frame for the tabs on top and the generic message on the bottom
$funcs[$MAIN_FR] = sub {
	print_html_header_frameset("$args{'case'}:$args{'host'}:$args{'img'}");

	my $mode = $MAIN_FR;
	$mode = get_mode() if (exists $args{'mode'});

	# Print the rest of the frames
	my $str = "";
	if ($mode == $MAIN_FR) {
		$mode = $MAIN_MSG;
	} 
	elsif ($mode == $FIL_MAIN) {
		$str .= "&inode=$args{'inode'}" if (exists $args{'inode'});
		$str .= "&dir=$args{'dir'}" if (exists $args{'dir'});
		$str .= "&sort=$args{'sort'}" if (exists $args{'sort'});
		$str .= "&dmode=$args{'dmode'}" if (exists $args{'dmode'});
	} 
	elsif ($mode == $BLK_MAIN) {
		$str .= "&block=$args{'block'}" if (exists $args{'block'});
		$str .= "&len=$args{'len'}" if (exists $args{'len'});
	} 
	elsif ($mode == $INO_MAIN) {
		$str .= "&inode=$args{'inode'}" if (exists $args{'inode'});
	} 
	# elsif ($mode == $FS_MAIN) 
	# elsif ($mode == $SRCH_MAIN) 
	# elsif ($mode == $INT_MAIN) 
	# elsif ($mode == $NOTES_MAIN) 


print <<EOF;

<FRAMESET ROWS=\"40,*\">
  <FRAME SRC=\"$PROGNAME?func=$MAIN_TABS&$baseargs&mode=$mode\">

  <FRAME SRC=\"$PROGNAME?func=$mode&$baseargs$str\">
</FRAMESET>

<NOFRAMES>
  <CENTER>
    Autopsy requires a browser that supports frames.
  </CENTER>
</NOFRAMES>

EOF
	return;
};


# Display a message when the image is opened (below the tabs)
$funcs[$MAIN_MSG] = sub {
	print_html_header("Main Message");

print <<EOF;

<CENTER>
  <BR><BR><BR><BR><BR><BR><BR>
  (select an analysis type)
</CENTER>

EOF
	return;
};


$funcs[$MAIN_TABS] = sub {
	check_mode();
	print_html_header_tabs("Mode Tabs");

	my $mode = get_mode();

	my $special = 0;
	$special = 1 if (($img2ftype{$args{'img'}} eq "strings") || 
	  ($img2ftype{$args{'img'}} eq "dls")) ;

	print "<CENTER><TABLE WIDTH=\"800\" BORDER=\"0\" CELLSPACING=\"0\" ".
	  "CELLPADDING=\"0\"><TR>\n";

	# Files
	print "<TD ALIGN=\"CENTER\" WIDTH=116>";
	if ($special == 0) {

		print "<A HREF=\"$PROGNAME?func=$MAIN_FR&mode=$FIL_MAIN&$baseargs\"".
		  "TARGET=\"_top\">";

		# Current 
		if ($mode == $FIL_MAIN) {
			print "<IMG BORDER=0 ".
			  "SRC=\"pict/main_t_fil_cur.jpg\" ".
			  "WIDTH=116 ".
			  "ALT=\"File Analysis (Current Mode)\"></A>";
		}
		# Link
		else {
			print "<IMG BORDER=0 ".
			  "SRC=\"pict/main_t_fil_link.jpg\" ".
			  "WIDTH=116 ".
			  "ALT=\"File Analysis\"></A>";
		}
	# non-link
	} else {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/main_t_fil_org.jpg\" ".
		  "WIDTH=116 ".
		  "ALT=\"File Analysis (not available)\">";
	}

	# Search
	print "</TD>\n".
	  "<TD ALIGN=\"CENTER\" WIDTH=116>";

	print "<A HREF=\"$PROGNAME?func=$MAIN_FR&mode=$SRCH_MAIN&$baseargs\"".
	  " TARGET=\"_top\">";

	if ($mode == $SRCH_MAIN) {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/main_t_srch_cur.jpg\" ".
		  "WIDTH=116 ".
		  "ALT=\"Keyword Search Mode (Current Mode)\"></A>";
	}
	else {
	  	print "<IMG BORDER=0 ".
		  "SRC=\"pict/main_t_srch_link.jpg\" ".
		  "WIDTH=116 ".
		  "ALT=\"Keyword Search Mode\"></A>";
	}

	# File Type
	print "</TD>\n".
	  "<TD ALIGN=\"CENTER\" WIDTH=116>";

	if ($special == 0) {

		print "<A HREF=\"$PROGNAME?func=$MAIN_FR&mode=$SORTER_MAIN&$baseargs\"".
		  " TARGET=\"_top\">";

		# Current
		if ($mode == $SORTER_MAIN) {
			print "<IMG BORDER=0 ".
			  "SRC=\"pict/main_t_ftype_cur.jpg\" ".
			  "WIDTH=116 ".
			  "ALT=\"File Type (Current Mode)\"></A>";
		}
		else {
			print "<IMG BORDER=0 ".
			  "SRC=\"pict/main_t_ftype_link.jpg\" ".
			  "WIDTH=116 ".
			  "ALT=\"File Type\"></A>";
		}
	} else {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/main_t_ftype_org.jpg\" ".
		  "WIDTH=116 ".
		  "ALT=\"File Type (not available)\">";
	}

	# File System
	print "</TD>\n".
	  "<TD ALIGN=\"CENTER\" WIDTH=116>";

	if ($special == 0) {

		print "<A HREF=\"$PROGNAME?func=$MAIN_FR&mode=$FS_MAIN&$baseargs\"".
		  " TARGET=\"_top\">";

		if ($mode == $FS_MAIN) {
			print "<IMG BORDER=0 ".
			  "SRC=\"pict/main_t_img_cur.jpg\" ".
			  "WIDTH=116 ".
			  "ALT=\"Image Details Mode (Current Mode)\"></A>";
		} else {
			print "<IMG BORDER=0 ".
			  "SRC=\"pict/main_t_img_link.jpg\" ".
			  "WIDTH=116 ".
			  "ALT=\"Image Details Mode\"></A>";
		}
	} else {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/main_t_img_org.jpg\" ".
		  "WIDTH=116 ".
		  "ALT=\"Image Details Mode (not available)\">";
	}

	# Meta Data
	print "</TD>\n".
	  "<TD ALIGN=\"CENTER\" WIDTH=116>";

	if ($special == 0) {
		print "<A HREF=\"$PROGNAME?func=$MAIN_FR&mode=$INO_MAIN&$baseargs\"".
		  " TARGET=\"_top\">";

		if ($mode == $INO_MAIN) {
			print "<IMG BORDER=0 ".
			  "SRC=\"pict/main_t_met_cur.jpg\" ".
			  "WIDTH=116 ".
			  "ALT=\"Meta Data Mode (Current Mode)\"></A>";
		} else {
			print "<IMG BORDER=0 ".
			  "SRC=\"pict/main_t_met_link.jpg\" ".
			  "WIDTH=116 ".
			  "ALT=\"Meta Data Mode\"></A>";
		}
	} else {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/main_t_met_org.jpg\" ".
		  "WIDTH=116 ".
		  "ALT=\"Meta Data Mode (not available)\">";
	}

	# Data Units
	print "</TD>\n".
	  "<TD ALIGN=\"CENTER\" WIDTH=116>";

	print "<A HREF=\"$PROGNAME?func=$MAIN_FR&mode=$BLK_MAIN&$baseargs\"".
	  " TARGET=\"_top\">";
	# Current
	if ($mode == $BLK_MAIN) {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/main_t_dat_cur.jpg\" ".
		  "WIDTH=116 ".
		  "ALT=\"Data Units Mode (Current Mode)\"></A>";
	}
	# Link
	else {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/main_t_dat_link.jpg\" ".
		  "WIDTH=116 ".
		  "ALT=\"Data Units Mode\"></A>";
	}



	# Help - set to current mode
	print "</TD>\n".
	  "<TD ALIGN=\"CENTER\" WIDTH=52>".
	  "<A HREF=\"$HELP_URL\"".
	  " TARGET=\"_blank\">".
	  "<IMG BORDER=0 ".
	  "SRC=\"pict/tab_help.jpg\" ".
	  "WIDTH=52 ".
	  "ALT=\"Help\">".
	  "</A></TD>\n";

	# Close
	print "<TD ALIGN=\"CENTER\" WIDTH=52>".
	  "<A HREF=\"$PROGNAME?func=$IMG_OPEN&$baseargs_noimg\"".
	  " TARGET=\"_top\">".
	  "<IMG BORDER=0 ".
	  "SRC=\"pict/tab_close.jpg\" ".
	  "WIDTH=52 ".
	  "ALT=\"Close Image\">".
	  "</A></TD>\n";

	print "</TR></TABLE>\n";

	return;
};



# The tabs / button images in timeline view
$funcs[$TL_TABS] = sub {
	check_mode();
	print_html_header_tabs("Timeline Mode Tabs");

	my $mode = get_mode();

	print "<CENTER><TABLE WIDTH=\"800\" BORDER=\"0\" ".
	  "CELLSPACING=\"0\" CELLPADDING=\"0\"><TR>\n";

	# Create Datafile
	print "<TD ALIGN=\"CENTER\" WIDTH=174>".
	  "<A HREF=\"$PROGNAME?func=$TL_MAIN&mode=$TL_BODY_ENT&$baseargs\" ".
	  "TARGET=\"_top\">";

	if ($mode == $TL_BODY_ENT) {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/tl_t_data_cur.jpg\" ".
		  "WIDTH=174 ".
		  "ALT=\"Create Data File (Current Mode)\"></A>\n";
	} else {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/tl_t_data_link.jpg\" ".
		  "WIDTH=174 ".
		  "ALT=\"Create Data File\"></A>\n";
	}

	print "</TD>\n".
	  "<TD ALIGN=\"CENTER\" WIDTH=174>".

	  "<A HREF=\"$PROGNAME?func=$TL_MAIN&mode=$TL_TL_ENT&$baseargs\" ".
	  "TARGET=\"_top\">";

	# Create Timeline
	if ($mode == $TL_TL_ENT) {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/tl_t_tl_cur.jpg\" ".
		  "WIDTH=174 ".
		  "ALT=\"Create Timeline (Current Mode)\"></A>\n";
	} else {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/tl_t_tl_link.jpg\" ".
		  "WIDTH=174 ".
		  "ALT=\"Create Timeline\"></A>\n";
	}
	print "</TD>\n".
	  "<TD ALIGN=\"CENTER\" WIDTH=174>".
	  "<A HREF=\"$PROGNAME?func=$TL_MAIN&mode=$TL_VIEW_MENU&$baseargs\" ".
	  "TARGET=\"_top\">";

	# View Timeline
	if (($mode == $TL_VIEW_FR) || ($mode == $TL_VIEW_MENU)) {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/tl_t_view_cur.jpg\" ".
		  "WIDTH=174 ".
		  "ALT=\"View Timeline (Current Mode)\"></A>\n";
	} else {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/tl_t_view_link.jpg\" ".
		  "WIDTH=174 ".
		  "ALT=\"View Timeline\"></A>\n";
	}

	# Notes
	print "</TD>\n".
	  "<TD ALIGN=\"CENTER\" WIDTH=174>";
	if ($USE_NOTES == 1) {
		print "<A HREF=\"$PROGNAME?func=$NOTES_MAIN&${baseargs_noimg}\" ".
		  "TARGET=\"_blank\">".
		  "<IMG BORDER=0 ".
		  "SRC=\"pict/tl_t_notes_link.jpg\" ".
		  "WIDTH=174 ".
		  "ALT=\"View Notes\"></A></TD>\n";
	} else {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/tl_t_notes_org.jpg\" ".
		  "WIDTH=174 ".
		  "ALT=\"View Notes\"></A></TD>\n";
	}

	# Help - set to current mode
	print "<TD ALIGN=\"CENTER\" WIDTH=52>".
	  "<A HREF=\"$HELP_URL\" ".
	  "TARGET=\"_blank\">".
	  "<IMG BORDER=0 ".
	  "SRC=\"pict/tab_help.jpg\" ".
	  "WIDTH=52 ".
	  "ALT=\"Help\"></A></TD>\n";

	# Close
	print "<TD ALIGN=\"CENTER\" WIDTH=52>".
	  "<A HREF=\"$PROGNAME?func=$IMG_OPEN&$baseargs\" ".
	  "TARGET=\"_top\">".
	  "<IMG BORDER=0 ".
	  "SRC=\"pict/tab_close.jpg\" ".
	  "WIDTH=52 ".
	  "ALT=\"Exit to Host Manager\"></A></TD>\n".
	  "</TR></TABLE>\n";

	return;
};



####################################################################
# General menu Functions

sub print_menu_tabs {

	print "<B>Case:</B> $args{'case'}" if (exists $args{'case'});
	print "<BR>\n";
	print "<B>Host:</B> $args{'host'}" if (exists $args{'host'});
	print "<BR>\n";

	print "<CENTER>\n";

	print "<TABLE WIDTH=\"600\" HEIGHT=\"60\" BACKGROUND=\"$YEL_PIX\" ".
	  "BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">\n<TR>\n".
	  "<TD ALIGN=\"CENTER\" WIDTH=\"200\">";

	# Case Gallery
	if ($args{'func'} == $CASE_OPEN) {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/menu_t_cg_cur.jpg\" ".
		  "WIDTH=200 ".
		  "ALT=\"Case Gallery (Current Mode)\">\n";
	}
	else {
		print "<A HREF=\"$PROGNAME?func=$CASE_OPEN\">".
		  "<IMG BORDER=0 ".
		  "SRC=\"pict/menu_t_cg_link.jpg\" ".
		  "WIDTH=200 ".
		  "ALT=\"Case Gallery\"></A>\n";
	}
	print "</TD>\n".
	  "<TD ALIGN=\"CENTER\" WIDTH=\"200\">";

	# Host Gallery
	# Current
	if ($args{'func'} == $HOST_OPEN) {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/menu_t_hg_cur.jpg\" ".
		  "WIDTH=200 ".
		  "ALT=\"Host Gallery (Current Mode)\">\n";
	}
	# Link
	elsif ($args{'func'} == $IMG_OPEN) {
		print "<A HREF=\"$PROGNAME?func=$HOST_OPEN&case=$args{'case'}\">".
		  "<IMG BORDER=0 ".
		  "SRC=\"pict/menu_t_hg_link.jpg\" ".
		  "WIDTH=200 ".
		  "ALT=\"Host Gallery\"></A>\n";
	}
	# non-link
	else {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/menu_t_hg_org.jpg\" ".
		  "WIDTH=200 ".
		  "ALT=\"Host Gallery (Not Available)\">\n";
	}

	print "</TD>\n".
	  "<TD ALIGN=\"CENTER\" WIDTH=\"200\">";

	# Host Manager
	# Current
	if ($args{'func'} == $IMG_OPEN) {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/menu_t_hm_cur.jpg\" ".
		  "WIDTH=200 ".
		  "ALT=\"Host Manager (Current Mode)\">\n";
	}
	# non-link
	else {
		print "<IMG BORDER=0 ".
		  "SRC=\"pict/menu_t_hm_org.jpg\" ".
		  "WIDTH=200 ".
		  "ALT=\"Host Manager (Not Available)\">\n";
	}

	print "</TD>\n".
	  "</TABLE>\n";
};

####################################################################
# Case Functions

$funcs[$CASE_NEW] = sub {
	print_html_header("Create A New Case");

print <<EOF;
<BR>
<BR>
<CENTER>
<IMG SRC=\"pict/menu_h_cnew.jpg\" ALT=\"New Case\">
<BR><BR><BR>

<TABLE WIDTH=\"600\" BACKGROUND=\"$YEL_PIX\" CELLSPACING=\"0\"
  CELLPADDING=\"2\" BORDER=0>
<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">
<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$CASE_NEW_DOIT\">
<TR>
  <TD COLSPAN=2 ALIGN=center>
    1.  Enter Case Name (directory name): 
    <INPUT TYPE=\"text\" NAME=\"case\">
  </TD>
</TR>
<TR><TD COLSPAN=2>&nbsp;</TD></TR>
<TR>
  <TD COLSPAN=2 ALIGN=center>
    2.  Enter Description (one line, optional): 
    <INPUT TYPE=\"text\" NAME=\"desc\">
  </TD>
</TR>
<TR><TD COLSPAN=2>&nbsp;</TD></TR>
<TR>
  <TD COLSPAN=2 ALIGN=center>
    3.  Enter Investigator Logins (no spaces):
  </TD>
</TR>
<TR>
  <TD ALIGN=CENTER>a. <INPUT TYPE=\"text\" NAME=\"inv1\"></TD>
  <TD ALIGN=CENTER>b. <INPUT TYPE=\"text\" NAME=\"inv2\"></TD>
</TR>
<TR>
  <TD ALIGN=CENTER>c. <INPUT TYPE=\"text\" NAME=\"inv3\"></TD>
  <TD ALIGN=CENTER>d. <INPUT TYPE=\"text\" NAME=\"inv4\"></TD>
</TR>
<TR>
  <TD ALIGN=CENTER>e. <INPUT TYPE=\"text\" NAME=\"inv5\"></TD>
  <TD ALIGN=CENTER>f. <INPUT TYPE=\"text\" NAME=\"inv6\"></TD>
</TR>
<TR>
  <TD ALIGN=CENTER>g. <INPUT TYPE=\"text\" NAME=\"inv7\"></TD>
  <TD ALIGN=CENTER>h. <INPUT TYPE=\"text\" NAME=\"inv8\"></TD>
</TR>
<TR>
  <TD ALIGN=CENTER>i. <INPUT TYPE=\"text\" NAME=\"inv9\"></TD>
  <TD ALIGN=CENTER>j. <INPUT TYPE=\"text\" NAME=\"inv10\"></TD>
</TR>
</TABLE>

<BR><BR>
<TABLE WIDTH=\"600\" CELLSPACING=\"0\" CELLPADDING=\"2\">
<TR>
  <TD ALIGN=CENTER>
    <INPUT TYPE=\"image\" SRC=\"pict/menu_b_cnew.jpg\" 
      ALT=\"Create Case\" WIDTH=\"176\" BORDER=0>
  </TD>
</FORM>
  <TD ALIGN=CENTER>
    <FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">
    <INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$CASE_OPEN\">
    <INPUT TYPE=\"image\" SRC=\"pict/menu_b_cancel.jpg\" 
    ALT=\"Cancel\" WIDTH=\"167\" BORDER=0>
    </FORM>
  </TD>
  <TD ALIGN=CENTER><A HREF=\"$HELP_URL\" 
    TARGET=\"_blank\">
    <IMG SRC=\"pict/menu_b_help.jpg\" ALT=\"Help\" 
    WIDTH=\"167\" BORDER=0></A>
  </TD>
</TR>
</TABLE>
EOF

	return;
};


# Create the directory and case configuration file
# Gets the input from CASE_NEW
$funcs[$CASE_NEW_DOIT] = sub {
	check_case();
	print_html_header("Creating Case: $args{'case'}");

	print "<H3>Creating Case: <TT>$args{'case'}</TT></H3>\n";
	# Make the directory
	if (-d "$case_dir") {
		print_err ("Error: $case_dir already exists<BR>Please remove the directory and its contents and try again");
	}

	unless (mkdir $case_dir, $MKDIR_MASK) {
	  print_err ("Error making directory $case_dir: $!");
	}

	print "Case directory (<TT>$case_dir</TT>) created<BR>\n";
	log_case_info ("Case $args{'case'} created");


	my $fname = case_config_fname();

	open CASE_CONFIG, ">$fname" or die "Can't open case config: $fname";

	print CASE_CONFIG "# Autopsy case config file\n".
	  "# Case: $args{'case'}\n\n".
	  "created ".localtime()."\n";

	if ((exists $args{'desc'}) && ($args{'desc'} ne "")){
		print_err ("Invalid Description") if ($args{'desc'} =~ /\n/);

		print CASE_CONFIG "desc $args{'desc'}\n";
	}
	print CASE_CONFIG "images	$IMGDIR\n";
	print CASE_CONFIG "data		$DATADIR\n";
	print CASE_CONFIG "log		$LOGDIR\n";
	print CASE_CONFIG "reports	$REPDIR\n";

	close CASE_CONFIG;
	print "Configuration file (<TT>$fname</TT>) created<BR>\n";

	write_invest ($args{'inv1'}) 
	  if ((exists $args{'inv1'}) && ($args{'inv1'} ne ""));
	write_invest ($args{'inv2'}) 
	  if ((exists $args{'inv2'}) && ($args{'inv2'} ne ""));
	write_invest ($args{'inv3'}) 
	  if ((exists $args{'inv3'}) && ($args{'inv3'} ne ""));
	write_invest ($args{'inv4'}) 
	  if ((exists $args{'inv4'}) && ($args{'inv4'} ne ""));
	write_invest ($args{'inv5'}) 
	  if ((exists $args{'inv5'}) && ($args{'inv5'} ne ""));
	write_invest ($args{'inv6'}) 
	  if ((exists $args{'inv6'}) && ($args{'inv6'} ne ""));
	write_invest ($args{'inv7'}) 
	  if ((exists $args{'inv7'}) && ($args{'inv7'} ne ""));
	write_invest ($args{'inv8'}) 
	  if ((exists $args{'inv8'}) && ($args{'inv8'} ne ""));
	write_invest ($args{'inv9'}) 
	  if ((exists $args{'inv9'}) && ($args{'inv9'} ne ""));
	write_invest ($args{'inv10'}) 
	  if ((exists $args{'inv10'}) && ($args{'inv10'} ne ""));

	print "Investigators added<BR>\n";

	log_session_info ("Case $args{'case'} created");

	print "<BR><BR><A HREF=\"$PROGNAME?func=$CASE_OPEN\">".
	  "<IMG SRC=\"pict/but_ok.jpg\" ALT=\"Ok\" ".
	  "WIDTH=\"43\" BORDER=\"0\"></A>\n";

	return;
};


# Open a Case
# This provides a form with a list of options
$funcs[$CASE_OPEN] = sub {
	print_html_header("Open A Case");

	print_menu_tabs();

	print "<TABLE WIDTH=\"600\" BACKGROUND=\"$YEL_PIX\" ".
	  " CELLSPACING=\"0\" CELLPADDING=\"2\" BORDER=0>\n";


	# Read the directories of the Evidence Locker into an array
	# Verify that there is a config file in the directory
	my @cases;
    opendir CASES, $LOCKDIR or die "Can't open $LOCKDIR directory: $!";
	foreach my $c (readdir CASES) {
        next if (($c eq '.') || ($c eq '..'));
		my $cfile = case_config_fname($c);

		push @cases, $c 
		  if ((-d "${LOCKDIR}$c") && (-e "$cfile"));
	}

	closedir CASES;

	# Were there any cases?  
	if (scalar @cases == 0) {
        print "<TR><TD ALIGN=\"CENTER\">".
		  "No cases exist in <TT>$LOCKDIR</TT>".
		  "</TD></TR>\n";
	}

	else {
		print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$CASE_OPEN_LOG\">\n".
		  make_hidden().
		  "<TR><TH>Name</TH>".
		  "<TH>Description</TH>".
		  "<TD>&nbsp;</TD></TR>\n";

		my $first = 0;
		foreach my $c (@cases) {

			print "<TR><TD ALIGN=\"left\">".
			  "<INPUT TYPE=\"radio\" NAME=\"case\" VALUE=$c";
			if ($first == 0) {
				print " CHECKED";
				$first = 1;
			}
            print ">$c</TD>";

			my %cvals = read_case_config($c);

			print "<TD>$cvals{'desc'}</TD>".
			  "<TD ALIGN=center>".
			  "<A HREF=\"$PROGNAME?func=$CASE_DETAILS&case=$c\">".
			  "details</A></TD>".
			  "</TR>\n";
        }
	}
	print "</TABLE>\n";

	print "<BR><BR>".
	  "<TABLE WIDTH=\"600\" CELLSPACING=\"0\" CELLPADDING=\"2\">\n".
	  "<TR>\n";

	# Print the OK button if there were cases
	if (scalar @cases != 0) {
		  print "<TD ALIGN=CENTER>".
			"<INPUT TYPE=\"image\" SRC=\"pict/menu_b_ok.jpg\" ".
			"ALT=\"Ok\" BORDER=0>".
			"</FORM></TD>\n\n";
	}

	# Print a 'New Case' Button
	print "<TD ALIGN=CENTER>".
	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n". 
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$CASE_NEW\">\n".
	  "<INPUT TYPE=\"image\" SRC=\"pict/menu_b_cnew.jpg\" ".
	  "ALT=\"New Case\" BORDER=0>\n".
	  "</FORM></TD>".

	# Print a Menu Button
	  "<TD ALIGN=CENTER>".
	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n". 
	  "<INPUT TYPE=\"image\" SRC=\"pict/menu_b_menu.jpg\" ".
	  "ALT=\"Main Menu\" BORDER=0></FORM></TD></TR></TABLE>\n";

	print 
	  "<TABLE WIDTH=600 CELLSPACING=\"0\" CELLPADDING=\"2\">\n<TR>".
	  "<TD>&nbsp;</TD>\n".
	  "<TD ALIGN=CENTER WIDTH=200><A HREF=\"$HELP_URL\" ".
	  " TARGET=\"_blank\">".
	  "<IMG SRC=\"pict/menu_b_help.jpg\" ALT=\"Help\" ".
	  "WIDTH=\"167\" BORDER=0>".
	  "</A></TD>".
	  "<TD>&nbsp;</TD>\n".
	  "</TR>\n".
	  "</TABLE>";

    return;
};

# Log that a given case was opened and then proceed to open a host
$funcs[$CASE_OPEN_LOG] = sub {
	log_session_info ("Case $args{'case'} opened");
	log_case_info ("Case $args{'case'} opened");
	$args{'func'} = $enc_args{'func'} = $HOST_OPEN;
	& {$funcs[$HOST_OPEN]};
};

# Display Case Details
$funcs[$CASE_DETAILS] = sub {
	check_case();

	print_html_header("Details of $args{'case'}");

	my %cvals = read_case_config();

	$cvals{'desc'} = "&nbsp;" unless (exists $cvals{'desc'});
	$cvals{'created'} = "&nbsp;" unless (exists $cvals{'created'});

	print "<BR><BR>".
	  "<CENTER>".
	  "<IMG SRC=\"pict/menu_h_cdet.jpg\" ALT=\"Case Details\">".
	  "<BR><BR><BR>\n".
	  "<TABLE WIDTH=\"600\" CELLSPACING=\"0\" BACKGROUND=\"$YEL_PIX\" ".
	  "CELLPADDING=\"2\" BORDER=0>\n".
	  "  <TR><TD ALIGN=\"RIGHT\" WIDTH=300><B>Name:</B></TD>".
	  "<TD ALIGN=\"LEFT\" WIDTH=300><TT>$args{'case'}</TT></TD></TR>\n".

	  # Description
	  "  <TR><TD ALIGN=\"RIGHT\"><B>Description:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>$cvals{'desc'}</TT></TD></TR>\n".
	  "  <TR><TD ALIGN=\"RIGHT\"><B>Created:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>$cvals{'created'}</TT></TD></TR>\n".

	  # Directories
	  "  <TR><TD ALIGN=\"RIGHT\"><B>Directory:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>$case_dir</TT></TD></TR>\n".
	  "  <TR><TD COLSPAN=\"2\">&nbsp;</TD></TR>\n".
	  "  <TR><TD ALIGN=\"RIGHT\"><B>Images Dir:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>$cvals{'images'}</TT></TD></TR>\n".
	  "  <TR><TD ALIGN=\"RIGHT\"><B>Output Dir:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>$cvals{'data'}</TT></TD></TR>\n".
	  "  <TR><TD ALIGN=\"RIGHT\"><B>Report Dir:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>$cvals{'reports'}</TT></TD></TR>\n".
	  "  <TR><TD ALIGN=\"RIGHT\"><B>Log Dir:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>$cvals{'log'}</TT></TD></TR>\n";

	# Display the valid investigators
	my @invs = read_invest();
	my $cnt = 0;
	print "  <TR><TD COLSPAN=\"2\">&nbsp;</TD></TR>\n"
	  if (scalar @invs > 0);

	foreach my $i (@invs) {
		if ($cnt == 0) {
			print "  <TR><TD ALIGN=\"RIGHT\"><B>Investigators:</B></TD>";
			$cnt++;
		} else {
			print "  <TR><TD>&nbsp;</TD>";
		}
		print "<TD ALIGN=\"LEFT\"><TT>$i</TT></TD></TR>\n";
	}

	print "</TABLE>\n".
	  "<P><A HREF=\"$PROGNAME?func=$CASE_OPEN\">".
	  "<IMG SRC=\"pict/menu_b_ok.jpg\" ALT=\"Ok\" ".
	  "WIDTH=\"167\" BORDER=\"0\"></A>";

	return;

};

####################################################################
# Host Functions

$funcs[$HOST_ADD] = sub {
	print_html_header("Add A New Host To $args{'case'}");

	print "<B>Case: </B> $args{'case'}<BR><BR>\n";

    print "<CENTER>".
	  "<IMG SRC=\"pict/menu_h_hnew.jpg\" ALT=\"Add Host\">".
	  "<BR><BR><BR>\n";

	print "<TABLE WIDTH=\"600\" CELLSPACING=\"0\" BACKGROUND=\"$YEL_PIX\" ".
	  "CELLPADDING=\"2\" BORDER=0>\n".
      "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$HOST_ADD_DOIT\">\n".
	  make_hidden().
	  "<TR><TD COLSPAN=\"2\">&nbsp;</TD></TR>".
	  "<TR><TD ALIGN=\"right\">1.  Host Name (directory name):</TD>".
	  "<TD ALIGN=\"left\"><INPUT TYPE=\"text\" NAME=\"host\"></TD></TR>\n".
	  "<TR><TD ALIGN=\"right\">2.  Description (one line, optional):</TD>".
	  "<TD ALIGN=\"left\">".
	  "<INPUT TYPE=\"text\" NAME=\"desc\" SIZE=32 MAXLENGTH=32></TD></TR>\n".
	  "<TR><TD COLSPAN=\"2\">&nbsp;</TD></TR>".
	  "<TR><TD ALIGN=\"right\">3.  Timezone:</TD>".
	  "<TD ALIGN=\"left\">".
	  "<INPUT TYPE=\"text\" NAME=\"tz\" SIZE=10 MAXLENGTH=16></TD></TR>\n".
	  "<TR><TD ALIGN=\"right\">4.  Timeskew (in +/- seconds):</TD>".
	  "<TD ALIGN=\"left\">".
	  "<INPUT TYPE=\"text\" NAME=\"ts\" SIZE=8 MAXLENGTH=16 VALUE=\"0\">".
	  "</TD></TR>\n".
	  "<TR><TD COLSPAN=\"2\">&nbsp;</TD></TR>".
	  "<TR><TD ALIGN=\"right\">5.  Path of Alert Hash Database (optional)<BR>i.e. known bad files:</TD>".
	  "<TD ALIGN=\"left\">".
	  "<INPUT TYPE=\"text\" NAME=\"alert_db\" SIZE=32 MAXLENGTH=512>".
	  "</TD></TR>\n".
	  "<TR><TD ALIGN=\"right\">6.  Path of Ignore Hash Database (optional)<BR>i.e. known good files:</TD>".
	  "<TD ALIGN=\"left\">".
	  "<INPUT TYPE=\"text\" NAME=\"exclude_db\" SIZE=32 MAXLENGTH=512>".
	  "</TD></TR>\n".
	  "<TR><TD COLSPAN=\"2\">&nbsp;</TD></TR>".
	  "</TABLE>\n";

	# Ok Button
	print "<BR><BR><TABLE WIDTH=\"600\" CELLSPACING=\"8\" CELLPADDING=\"2\">\n".
	  "<TR><TD ALIGN=CENTER>".
	  "<INPUT TYPE=\"image\" SRC=\"pict/menu_b_hnew.jpg\" ".
	  "ALT=\"Add Host\" BORDER=0>\n".
	  "</FORM></TD>\n".

	# Cancel Button
	  "<TD ALIGN=CENTER>".
	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n". 
      "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$HOST_OPEN\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"case\" VALUE=\"$args{'case'}\">\n".
	  "<INPUT TYPE=\"image\" SRC=\"pict/menu_b_cancel.jpg\" ".
	  "ALT=\"Cancel\" WIDTH=\"167\" BORDER=0>\n".
	  "</FORM></TD>\n".
	# Help Button
	  "<TD ALIGN=CENTER><A HREF=\"$HELP_URL\" ".
	  "TARGET=\"_blank\">".
	  "<IMG SRC=\"pict/menu_b_help.jpg\" ALT=\"Help\" ".
	  "WIDTH=\"167\" BORDER=0></A>".
	  "</TD></TR>\n".
	  "</TABLE>";

    return;

};


# Make the directories and config files for a host
$funcs[$HOST_ADD_DOIT] = sub {
	check_host(); check_tz(); check_ts();
	print_html_header("Adding Host $args{'host'} to $args{'case'}");

    print "<H3>Adding host: <TT>$args{'host'}</TT> to ".
	  "case <TT>$args{'case'}</TT></H3>\n";

	# Do some sanity checks before we start making the directories and such
	if ((exists $args{'alert_db'}) && ($args{'alert_db'} ne "")) {

		unless ($args{'alert_db'} =~ /^$REG_HASHDB$/o) {
			print "Invalid Alert Database path\n". 
			  "<P><A HREF=\"$PROGNAME?func=$HOST_ADD&case=$args{'case'}\">".
			  "<IMG SRC=\"pict/but_ok.jpg\" ALT=\"Ok\" ".
			  "WIDTH=\"43\" BORDER=\"0\"></A>\n";
			return 1;
		}

		unless (-e "$args{'alert_db'}") {
			print "Alert Database Not Found: $args{'alert_db'}".
			  "<P><A HREF=\"$PROGNAME?func=$HOST_ADD&case=$args{'case'}\">".
			  "<IMG SRC=\"pict/but_ok.jpg\" ALT=\"Ok\" ".
			  "WIDTH=\"43\" BORDER=\"0\"></A>\n";
			return 1;
		}
	}

	if ((exists $args{'exclude_db'}) && ($args{'exclude_db'} ne "")) {
		unless ($args{'exclude_db'} =~ /^$REG_HASHDB$/o) {
			print "Invalid Exclude Database path\n". 
			  "<P><A HREF=\"$PROGNAME?func=$HOST_ADD&case=$args{'case'}\">".
			  "<IMG SRC=\"pict/but_ok.jpg\" ALT=\"Ok\" ".
			  "WIDTH=\"43\" BORDER=\"0\"></A>\n";
			return 1;
		}

		unless (-e "$args{'exclude_db'}") {
			print "Exclude Database Not Found: $args{'exclude_db'}".
			  "<P><A HREF=\"$PROGNAME?func=$HOST_ADD&case=$args{'case'}\">".
			  "<IMG SRC=\"pict/but_ok.jpg\" ALT=\"Ok\" ".
			  "WIDTH=\"43\" BORDER=\"0\"></A>\n";
			return 1;
		}
	}

    # Make the directory
    if (-d "$host_dir") {
        print_err ("Error: $host_dir already exists<BR>Please remove the ".
		  "directory and its contents and try again");
    }
    unless (mkdir $host_dir, $MKDIR_MASK) {
        print_err ("Error making directory $host_dir: $!");
    }

    print "Host Directory (<TT>$host_dir</TT>) created<P>\n";
    log_case_info ("Host $args{'host'} added to case");

	# @@@ READ CASE CONFIG FOR DIR NAMES
	# Images directory
    unless (mkdir "${host_dir}$IMGDIR", $MKDIR_MASK) {
		rmdir "${host_dir}";
		print_err ("Error making ${host_dir}$IMGDIR");
	}
	# Output Directory
    unless (mkdir "${host_dir}$DATADIR", $MKDIR_MASK) {
		rmdir "${host_dir}$IMGDIR";
		rmdir "${host_dir}";
		print_err ("Error making ${host_dir}$DATADIR");
	}
	# Log Directory
    unless (mkdir "${host_dir}$LOGDIR", $MKDIR_MASK) {
		rmdir "${host_dir}$DATADIR";
		rmdir "${host_dir}$IMGDIR";
		rmdir "${host_dir}";
		print_err ("Error making ${host_dir}$LOGDIR");
	}
	# Reports directory
    unless (mkdir "${host_dir}$REPDIR", $MKDIR_MASK) {
		rmdir "${host_dir}$LOGDIR";
		rmdir "${host_dir}$DATADIR";
		rmdir "${host_dir}$IMGDIR";
		rmdir "${host_dir}";
		print_err ("Error making ${host_dir}$REPDIR");
	}
	# Make a directory for mounting the image in loopback
    unless (mkdir "${host_dir}mnt", $MKDIR_MASK) {
		rmdir "${host_dir}$REPDIR";
		rmdir "${host_dir}$LOGDIR";
		rmdir "${host_dir}$DATADIR";
		rmdir "${host_dir}$IMGDIR";
		rmdir "${host_dir}";
		print_err ("Error making ${host_dir}mnt");
	}

	log_host_info ("Host $args{'host'} added to case $args{'case'}");

	# Create config file
	my $fname = host_config_fname();
    open HOST_CONFIG, ">$fname" or die "Can't open host config: $fname";

	print HOST_CONFIG "# Autopsy host config file\n".
	  "# Case: $args{'case'}		Host: $args{'host'}\n".
	  "# Created: ".localtime()."\n\n";

    if ((exists $args{'desc'}) && ($args{'desc'} ne "")) {
        print_err ("Invalid Description") if ($args{'desc'} =~ /\n/);

        print HOST_CONFIG "desc $args{'desc'}\n";
    }

    print HOST_CONFIG "timezone  ".get_tz()."\n";
    print HOST_CONFIG "timeskew  ".get_ts()."\n";


	if ((exists $args{'alert_db'}) && ($args{'alert_db'} ne "")) {

		# Index it if it is not
		unless (-e "$args{'alert_db'}-md5.idx") {
			print "Alert Database has not been indexed - it will be as an md5sum file<BR>\n";

			print "<HR>\n";
			hash_index_md5sum ($args{'alert_db'});
			print "<HR>\n";
		}

		# only print it if it was successful
		print HOST_CONFIG "alert_db \'$args{'alert_db'}\'\n"
		  if (-e "$args{'alert_db'}-md5.idx");
	} 

	if ((exists $args{'exclude_db'}) && ($args{'exclude_db'} ne "")) {
		# Index it if it is not
		unless (-e "$args{'exclude_db'}-md5.idx") {
			print "Exclude Database has not been indexed - it will be as an md5sum file<BR>\n";

			print "<HR>\n";
			my @out = `\'${TASKDIR}hfind\' -i md5sum \'$args{'exclude_db'}\'`;
			foreach $_ (@out) {
				print "$_<BR>\n";
			}
			print "<HR>\n";
		}

		# only print it if it was successful
		print HOST_CONFIG "exclude_db \'$args{'exclude_db'}\'\n"
		  if (-e "$args{'exclude_db'}-md5.idx");
	}

    close HOST_CONFIG;

    print "Configuration file (<TT>$fname</TT>) created<BR><BR>\n";

	print "<A HREF=\"$PROGNAME?func=$HOST_OPEN&case=$args{'case'}\">".
	  "<IMG SRC=\"pict/but_ok.jpg\" ALT=\"Ok\" ".
	  "WIDTH=\"43\" BORDER=\"0\"></A>\n";

	return;
};

# Open a host in the given case
$funcs[$HOST_OPEN] = sub {
	print_html_header("Open Host In $args{'case'}");

	print_menu_tabs();

	print "<TABLE WIDTH=\"600\" CELLSPACING=\"0\" CELLPADDING=\"2\" ".
	  "BACKGROUND=\"$YEL_PIX\" BORDER=0>\n";

	# Create an array of directories in the case, verifying that there is
	# a config file
	my @hosts;
    opendir HOSTS, $case_dir or die "Can't open $case_dir directory: $!";
    foreach my $h (readdir HOSTS) {
        next if (($h eq '.') || ($h eq '..'));

		my $hfile = host_config_fname($h);
        push @hosts, $h
        	if ((-d "${case_dir}$h") && (-e "$hfile"));
	}
	closedir HOSTS;

	if (scalar @hosts == 0) {
        print "<TR><TD COLSPAN=\"4\" ALIGN=CENTER>".
		  "No hosts have been added to case yet".
		  "</TD></TR></TABLE>\n";
	}
	else {
		print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$HOST_OPEN_LOG\">\n".
		  make_hidden().
		  "<TR><TH>Name</TH>".
		  "<TH>Description</TH><TH>&nbsp;</TH></TR>\n";


		my $first = 0;
		foreach my $h (@hosts) {

			print "<TR><TD ALIGN=\"left\">".
			  "<INPUT TYPE=\"radio\" NAME=\"host\" VALUE=$h";
			if ($first == 0) {
				print " CHECKED";
				$first = 1;
			}
            print "> $h </TD>";

			my $fname = host_config_fname($h);
            open CONFIG, "<$fname" or die "Can't open host config file ($fname)";

            my $desc = "None Provided";
            while (<CONFIG>) {
				s/^\s+//;
				s/\s+$//;

                if (/^desc\s+(.*)$/) {
                    $desc = $1; 
                    last;
                }
            }
            close CONFIG;

            print "<TD ALIGN=left>$desc</TD>".
			  "<TD ALIGN=center>".
			  "<A HREF=\"$PROGNAME?func=$HOST_DETAILS&$baseargs&".
			  "host=$h\">details</A></TD></TR>\n";
        }
        print "</TABLE>\n";


		# Display pulldown of investigators
    	print "<BR>Investigator (for reports only): ";
		my @invs = read_invest();
		if (scalar @invs == 0) {
	  		print "None Provided<BR>\n".
			  "<INPUT TYPE=\"hidden\" NAME=\"inv\" VALUE=\"unknown\">\n";
		}
		else {
			my $cur_inv = "";
			$cur_inv = $args{'inv'} if (exists $args{'inv'});

		  	print "<SELECT NAME=\"inv\" SIZE=\"1\">\n";

			if (($cur_inv eq "") && (scalar @invs != 1)) {
				print "<OPTION VALUE=\"\" SELECTED>Select One".
				  "</OPTION>\n";
			}
			foreach my $i (@invs) {
				print "<OPTION VALUE=\"$i\"";
				print " SELECTED" if ($cur_inv eq $i);
				print ">$i</OPTION>\n";
			}
    		print "</SELECT>\n";
		}

	}
	print "<BR><BR><TABLE WIDTH=\"600\" CELLSPACING=\"0\" CELLPADDING=\"2\">\n".
	  "<TR>\n";

	# Make a table for the buttons.  The table will either be 3 or 2 
	# entries wide, depending on if there is an 'Ok' button or not

	unless (scalar @hosts == 0) {
		print "<TD ALIGN=CENTER>".
	  	  "<INPUT TYPE=\"image\" SRC=\"pict/menu_b_ok.jpg\" ".
	  	  "ALT=\"Ok\" WIDTH=\"167\" BORDER=0>\n".
		  "</FORM>\n</TD>\n";
	}

	# Add Host
	print "<TD ALIGN=CENTER>".
	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n". 
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$HOST_ADD\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"case\" VALUE=\"$args{'case'}\">\n".
	  "<INPUT TYPE=\"image\" SRC=\"pict/menu_b_hnew.jpg\" ".
  	  "ALT=\"Add Host\" WIDTH=\"176\" BORDER=0>\n".
	  "</FORM></TD>".

	# Close Button
	  "<TD ALIGN=CENTER>".
	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n". 
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$CASE_OPEN\">\n".
	  "<INPUT TYPE=\"image\" SRC=\"pict/menu_b_ccls.jpg\" ".
  	  "ALT=\"Close Case\" WIDTH=\"176\" BORDER=0>\n".
	  "</FORM></TD></TR></TABLE>\n";

	print 
	  "<TABLE WIDTH=\"600\"  CELLSPACING=\"0\" CELLPADDING=\"2\">\n".
	  "<TR><TD>&nbsp;</TD>".
	  "<TD ALIGN=CENTER><A HREF=\"$HELP_URL\" ".
	  " TARGET=\"_blank\">".
	  "<IMG SRC=\"pict/menu_b_help.jpg\" ALT=\"Help\" ".
	  "WIDTH=\"167\" BORDER=0>".
	  "</A></TD><TD>&nbsp;</TD></TR>\n".
	  "</TABLE>\n";

    return;
};

# Log that a given host was opened and then proceed to open an image
$funcs[$HOST_OPEN_LOG] = sub {
	unless ((exists $args{'inv'}) && ($args{'inv'} ne "")) {
		print_html_header("Missing Investigator");
		print "<BR>An investigator must be selected<P>\n".
          "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$HOST_OPEN_LOG\">\n".
		  make_hidden();

        print "Select one of the following:";       
        my @invs = read_invest();
        print "<SELECT NAME=\"inv\" SIZE=\"1\">\n";

		print "<OPTION VALUE=\"\" SELECTED>Select One".
		  "</OPTION>\n";

		foreach my $i (@invs) {
			print "<OPTION VALUE=\"$i\">$i</OPTION>\n";
		}
        print "</SELECT><P>\n".
		  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ALT=\"Ok\" ".
		  "BORDER=\"0\">\n".
		  "</FORM>\n";

		return;
	}

	check_inv();
	log_case_info ("Host $args{'host'} opened by $args{'inv'}");
	log_host_info ("Host $args{'host'} opened by $args{'inv'}");
	log_host_inv  ("Host $args{'host'} opened");
	$args{'func'} = $enc_args{'func'} = $IMG_OPEN;
	& {$funcs[$IMG_OPEN]};
};

# Provide details about the configuration of a host.  This window is
# a link from the HOST_OPEN window
$funcs[$HOST_DETAILS] = sub {
	print_html_header("Details of $args{'case'}:$args{'host'}");

	print "<B>Case: </B>$args{'case'}<BR><BR>".
	  "<CENTER>".
	  "<IMG SRC=\"pict/menu_h_hdet.jpg\" ALT=\"Host Details\">".
	  "<BR><BR><BR>\n".
	  "<TABLE WIDTH=\"600\" CELLSPACING=\"0\" CELLPADDING=\"2\" ".
	  "BACKGROUND=\"$YEL_PIX\" BORDER=0>\n".
	  # Name
	  "<TR><TD ALIGN=\"RIGHT\" WIDTH=300><B>Name:</B></TD>".
	  "<TD ALIGN=\"LEFT\" WIDTH=300><TT>$args{'host'}</TT></TD></TR>\n".
	  # Description
	  "<TR><TD ALIGN=\"RIGHT\"><B>Description:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>".
	  (($host_desc ne "") ? $host_desc : "&nbsp;").
	  "</TT></TD></TR>\n".
	  # Timezone
	  "<TR><TD ALIGN=\"RIGHT\"><B>Timezone: </B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>$tz</TT></TD></TR>\n".
	  # Timeskew
	  "<TR><TD ALIGN=\"RIGHT\"><B>Timeskew:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>$ts</TT></TD></TR>\n".
	  "<TR><TD COLSPAN=2>&nbsp;</TD></TR>\n".
	  # Actual Directory
	  "<TR><TD ALIGN=\"RIGHT\"><B>Directory:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>$host_dir</TT></TD></TR>\n".
	  "<TR><TD COLSPAN=2>&nbsp;</TD></TR>\n".
	  # Alert Database
	  "<TR><TD ALIGN=\"RIGHT\"><B>Alert Hash Database:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>".
	  (($alert_db ne "") ? $alert_db : "&nbsp;").
	  "</TT></TD></TR>\n".
	  # Exclude Database
	  "<TR><TD ALIGN=\"RIGHT\"><B>Exclude Hash Database:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>".
	  (($exclude_db ne "") ? $exclude_db : "&nbsp;").
	  "</TT></TD></TR>\n".
	  "</TABLE>\n";

	# Final Button
	print "<BR><BR><FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n". 
      "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$HOST_OPEN\">\n".
	  make_hidden().
	  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/menu_b_ok.jpg\" ".
	  "ALT=\"Ok\" WIDTH=\"167\" BORDER=\"0\">\n</FORM>";


	return;
};


####################################################################
# Image Functions

# Open an image that has been configured
$funcs[$IMG_OPEN] = sub {
	print_html_header("Open Image In $args{'case'}:$args{'host'}");

	print_menu_tabs();

	print "<TABLE WIDTH=\"600\" CELLSPACING=\"0\" CELLPADDING=\"2\" ".
	  "BACKGROUND=\"$YEL_PIX\" BORDER=0>\n";

	# the images have been loaded from reading the host config file in
	# autopsy_main
	if (scalar (keys %img2ftype) == 0) {
		print "</TABLE>No images have been added to this host yet<BR>\n";
		goto EGRESS;
	}

	# We want to sort by mounting point, so rearrange the hash
	my %mnt2img;

	# Cycle through each image we read from the host config
	foreach my $i (keys %img2mnt) {
		next if (($img2ftype{$i} eq "dls") || ($img2ftype{$i} eq "strings"));
		$mnt2img{"$img2mnt{$i}--AUTOPSY--$i"} = $i;
	}

	# sort via mount point (which includes the name)
	my @mnt = sort {
		lc($a) cmp lc($b)
	} keys %mnt2img;


	# It is possible to have only the dls image and not the original
	# We need to search for those now because they will not be in the
	# list that we just made (which are arranged via mount point)
	my @orphan_dls;

	# cycle through each image and check its type and original
	foreach my $k (keys %img2ftype) {
		if (($img2ftype{$k} eq "dls") && (!defined $mod2img{$k})) {
			push @orphan_dls, $k;
		} 
	}


	print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"_top\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$IMG_OPEN_LOG\">\n".
	  make_hidden().
	  "<TR><TH ALIGN=LEFT>mount</TH>".					# mnt
	  "<TH>&nbsp;</TH>".	# img button and unalloc
	  "<TH ALIGN=LEFT>name</TH><TH>&nbsp;</TH></TR>\n";		# img name

	for (my $i = 0; $i <= $#mnt; $i++) {
		print "<TR>";

		my $img = $mnt2img{$mnt[$i]};

		# Mount Point
		# If we have the dummy string at the end of the duplicate
		# entry, then take it off and print the original
		$mnt[$i] = $1 if ($mnt[$i] =~ /^(.*?)--AUTOPSY--$REG_IMG$/o);
		print "<TD><TT>$mnt[$i]</TT></TD>";

		# Image button
		print "<TD><INPUT TYPE=\"radio\" ".
		  "NAME=\"img\" VALUE=$img";
		print " CHECKED" if ($i == 0);	
		print ">";

		# if there is a corresponding dls entry, make an unalloc button
		if (defined $img2dls{$img}) {
			print " (<INPUT TYPE=\"radio\" NAME=\"img\" ".
			  "VALUE=$img2dls{$img}> unalloc)</TD>";
		} else {
			print "</TD>";
		}


		# image name and ftype
		print "<TD><TT>$img</TT></TD>".
		  "<TD ALIGN=center><A HREF=\"$PROGNAME?func=$IMG_DETAILS&$baseargs&".
		  "img=$img&mnt=$mnt[$i]\">details</A></TD>".
		  "</TR>\n";
	}
		
	# If we are done with the regular images and have some orphan
	# dls images, print them
	my @sort  = sort @orphan_dls;
	for (my $i = 0; $i <= $#sort; $i++) {
		print "<TR><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>(<INPUT TYPE=\"radio\" NAME=\"img\" ".
			  "VALUE=$sort[$i]";
		print " CHECKED" if ($#mnt == 0);	
		print "> unalloc)</TD><TD><TT>$sort[$i]</TT></TD></TR>\n";
	}

	# Begin Button
	print "</TABLE>\n";

EGRESS:

	print "<BR><BR>".
	  "<TABLE WIDTH=\"600\" CELLSPACING=\"0\" CELLPADDING=\"2\"><TR>\n";

	my $width = 300;
	unless (scalar (keys %img2ftype) == 0) {
		$width = 200;
		print "<TD ALIGN=CENTER WIDTH=$width>".
		  "<INPUT TYPE=\"image\" SRC=\"pict/menu_b_ok.jpg\" ".
		  "ALT=\"Ok\" WIDTH=\"167\" BORDER=0>\n".
		  "</FORM></TD>\n";
	}

	print "<TD ALIGN=CENTER WIDTH=$width>".
	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n". 
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$IMG_ADD\">\n".
	  make_hidden().
	  "<INPUT TYPE=\"image\" SRC=\"pict/menu_b_inew.jpg\" ".
  	  "ALT=\"Add Image\" BORDER=0></FORM></TD>\n".
	  "<TD ALIGN=CENTER WIDTH=$width>".
	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n". 
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$HOST_OPEN\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"case\" VALUE=\"$args{'case'}\">\n".
	  "<INPUT TYPE=\"image\" SRC=\"pict/menu_b_hcls.jpg\" ".
  	  "ALT=\"Close Host\" BORDER=0>\n".
	  "</FORM></TD></TR>\n</TABLE>\n";

	print 
	  "<TABLE WIDTH=\"600\" CELLSPACING=\"0\" CELLPADDING=\"2\">\n".
	  "<TR><TD>&nbsp;</TD>\n".
	  "<TD ALIGN=CENTER WIDTH=200><A HREF=\"$HELP_URL\" ".
	  " TARGET=\"_blank\">".
	  "<IMG SRC=\"pict/menu_b_help.jpg\" ALT=\"Help\" ".
	  "WIDTH=\"167\" BORDER=0>".
	  "</A></TD><TD>&nbsp;</TD></TR>\n".
	  "</TABLE>\n";

	# Other features that can be done on a host

	print "<HR><P>".
	  "<TABLE WIDTH=\"600\" CELLSPACING=\"0\" CELLPADDING=\"2\">\n".
	  "<TR>\n";


	# Timeline of file activity
	print "<TD ALIGN=\"CENTER\" WIDTH=200>".
	  "<A HREF=\"$PROGNAME?${baseargs_noimg}&func=$TL_MAIN\">".
	  "<IMG BORDER=0 ".
	  "SRC=\"pict/menu_b_tl.jpg\" ".
	  "WIDTH=\"167\" ".
	  "ALT=\"File Activity Timelines\"></A></TD>\n";

	# verify the integrity of the images
	print "<TD ALIGN=\"CENTER\" WIDTH=200>".
	  "<A HREF=\"$PROGNAME?${baseargs_noimg}&func=$INT_LIST_FR\">".
	  "<IMG BORDER=0 ".
	  "SRC=\"pict/menu_b_int.jpg\" ".
	  "WIDTH=\"167\" ".
	  "ALT=\"Image Integrity\"></A></TD>\n".

	  "<TD ALIGN=\"CENTER\" WIDTH=200>".
	  "<A HREF=\"$PROGNAME?${baseargs_noimg}&func=$HASH_MAIN\">".
	  "<IMG BORDER=0 ".
	  "SRC=\"pict/menu_b_hashdb.jpg\" ".
	  "WIDTH=\"167\" ".
	  "ALT=\"Hash Databases\"></A></TD>\n".
	  "</TR></TABLE>\n";

	# Notes 
	if ($USE_NOTES == 1) {
		print 
		  "<TABLE WIDTH=\"600\" CELLSPACING=\"0\" CELLPADDING=\"2\">\n".
		  "<TR>\n".
		  "<TD ALIGN=\"CENTER\" WIDTH=300>".
		  "<A HREF=\"$PROGNAME?${baseargs_noimg}&func=$NOTES_READ\">".
		  "<IMG BORDER=0 ".
		  "SRC=\"pict/menu_b_note.jpg\" ".
		  "WIDTH=\"167\" ".
		  "ALT=\"View Notes\"></A></TD>\n".

		  "<TD WIDTH=300 ALIGN=\"CENTER\">".
		  "<A HREF=\"$PROGNAME?${baseargs_noimg}&func=$NOTES_SEQ_READ\">".
		  "<IMG BORDER=0 ".
		  "SRC=\"pict/menu_b_seq.jpg\" ".
		  "WIDTH=\"167\" ".
		  "ALT=\"Event Sequencer\"></A></TD>\n".

		  "</TR>\n".
		  "</TABLE>\n";
	}


	# check if the permissions are ok
	# if (((stat("$host_dir/$IMGDIR"))[2]) & 0000222) {
	#	print "<BR><BR><BR>".
	#	  "<FONT COLOR=\"$DEL_COLOR[0]\">".
	#	  "NOTE: The images directory allows for writes.<BR> It is ".
	#	  "recommended that these permissions be turned off</FONT><BR>\n"; 
	#}


    return;
};

# Log in the host log that a given image was opened by what user
# then open the main window
$funcs[$IMG_OPEN_LOG] = sub {
	log_host_info ("Image $args{'img'} opened by $args{'inv'}");
	log_host_inv ("$args{'img'}: Image opened");
	$args{'func'} = $enc_args{'func'} = $MAIN_FR;
	& {$funcs[$MAIN_FR]};
};


my $MD5_NOTHING = 1;
my $MD5_CALC = 2;
my $MD5_ADD = 3;

# Menu to add a new image to the host
#
# The list of new images is determined by looking in the images directory
# and seeing which is not yet configured
#
$funcs[$IMG_ADD] = sub {
	print_html_header("Add Image To $args{'case'}:$args{'host'}");

	print "<B>Case:</B> $args{'case'}<BR>\n".
	  "<B>Host:</B> $args{'host'}<BR>\n";

	print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"_top\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$IMG_ADD_DOIT\">\n".
	  make_hidden();

print <<EOF1;
<CENTER>
<IMG SRC=\"pict/menu_h_inew.jpg\" ALT=\"Add Image\">
<BR><BR><BR>

<TABLE WIDTH=\"600\" CELLPADDING=\"2\" CELLSPACING=\"0\" BACKGROUND=\"$YEL_PIX\" BORDER=0>
<TR>
  <TD COLSPAN=2>&nbsp;</TD>
</TR>
<TR>
  <TD WIDTH=300 ALIGN=RIGHT>Image Location (starting with /): </TD>
  <TD WIDTH=300 ALIGN=LEFT>
    <INPUT TYPE=\"text\" NAME=\"img_path\" SIZE=36 MAXLENGTH=256>
  </TD>
</TR>
<TR>
  <TD WIDTH=300 ALIGN=RIGHT>Import Method:</TD>
  <TD WIDTH=300 ALIGN=LEFT>
    <INPUT TYPE=\"radio\" NAME=\"sort\" VALUE=$IMG_ADD_SYM CHECKED>
      Symlink to Evidence Locker
  </TD>
</TR>
<TR>
  <TD WIDTH=300 ALIGN=RIGHT>&nbsp;</TD>
  <TD WIDTH=300 ALIGN=LEFT>
    <INPUT TYPE=\"radio\" NAME=\"sort\" VALUE=$IMG_ADD_COPY>
      Copy to Evidence Locker
  </TD>
</TR>
<TR>
  <TD WIDTH=300 ALIGN=RIGHT>&nbsp;</TD>
  <TD WIDTH=300 ALIGN=LEFT>
    <INPUT TYPE=\"radio\" NAME=\"sort\" VALUE=$IMG_ADD_MOVE>
	  Move to Evidence Locker (<FONT COLOR="red">Warning</FONT>: image loss could occur during a system failure)
  </TD>
</TR>

EOF1

	# Show the file system types that we know of
	print "<TR><TD ALIGN=RIGHT>File System Type: </TD>".
	  "<TD ALIGN=LEFT><SELECT NAME=\"ftype\">\n";
	foreach my $fs (sort keys %root_inode) {
		print "<OPTION VALUE=\"$fs\">$fs</OPTION>\n";
	}
	print "</SELECT></TD></TR>\n";


	# Enter the mounting point and MD5

print <<EOF2;

<TR>
  <TD ALIGN=RIGHT>Mounting point: </TD>
  <TD ALIGN=LEFT><INPUT TYPE=\"text\" NAME=\"mnt\"></TD>
</TR>

<TR>
  <TD COLSPAN=2>&nbsp;</TD>
</TR>

<TR>
  <TD ALIGN=CENTER COLSPAN=2>
	<B>Image Integrity Check Options (i.e. MD5)</B>
  </TD>
</TR>

<TR>
  <TD ALIGN=RIGHT>Calculate Now:</TD>
  <TD ALIGN=LEFT>
    <INPUT TYPE=\"radio\" NAME=\"do_md5\" VALUE=\"$MD5_CALC\" CHECKED>
  </TD>
</TR>

<TR>
  <TD ALIGN=RIGHT>Ignore:</TD>
  <TD ALIGN=LEFT>
	<INPUT TYPE=\"radio\" NAME=\"do_md5\" VALUE=\"$MD5_NOTHING\">
  </TD>
</TR>


<TR>
  <TD ALIGN=RIGHT>Add:</TD>
  <TD ALIGN=LEFT>
	<INPUT TYPE=\"radio\" NAME=\"do_md5\" VALUE=\"$MD5_ADD\">
  </TD>
</TR>

<TR>
  <TD ALIGN=RIGHT>MD5: </TD>
  <TD ALIGN=LEFT>
	<INPUT TYPE=\"text\" NAME=\"md5\" SIZE=36 MAXLENGTH=32>
  </TD>
</TR>

<TR>
  <TD ALIGN=RIGHT>&nbsp;</TD>
  <TD ALIGN=LEFT>
	<INPUT TYPE=\"checkbox\" NAME=\"ver_md5\" VALUE=\"1\">
	&nbsp;Verify MD5 After Importing?
  </TD>
</TR>

<TR>
  <TD COLSPAN=2>&nbsp;</TD>
</TR>

</TABLE>

<BR><BR>
<TABLE WIDTH=\"600\" CELLSPACING=\"0\" CELLPADDING=\"2\">
<TR>
  <TD ALIGN=CENTER>
    <INPUT TYPE=\"image\" SRC=\"pict/menu_b_inew.jpg\" ALT=\"Add Image\" WIDTH=\"167\" BORDER=0>
  </TD>

</FORM>

EOF2

	print 
	  "  <TD ALIGN=CENTER>\n".
	  "    <FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
	  "    <INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$IMG_OPEN\">\n".
	  make_hidden().
	  "    <INPUT TYPE=\"image\" SRC=\"pict/menu_b_cancel.jpg\" ".
	  "ALT=\"Cancel\" WIDTH=\"167\" BORDER=0></FORM>\n".
	  "  </TD>\n".

	# HELP
	  "  <TD ALIGN=CENTER>\n".
	  "    <A HREF=\"$HELP_URL\" TARGET=\"_blank\">\n".
	  "    <IMG SRC=\"pict/menu_b_help.jpg\" ALT=\"Help\" ".
	  "WIDTH=\"167\" BORDER=0></A>\n".
	  "  </TD>\n".
	  "</TR>\n".
	  "</TABLE>\n";

    return;
};


# Add the image to the configuration by adding it to the host config file
# and the md5.txt file if that data was provided
$funcs[$IMG_ADD_DOIT] = sub {
	check_img_path(); check_ftype(); check_mnt(); check_sort();
	check_do_md5();
	print_html_header("Add a new image to an Autopsy Case");

	my $mnt = get_mnt();
	my $fstype = get_ftype();
	my $img_path = get_img_path();
	my $import_type = get_sort();

	# Test the File System
	my $out = `${TASKDIR}fsstat -f $fstype $img_path`;
	if ($out eq "") {
		print "<P>The image is not a <TT>$fstype</TT> file system<BR>\n".
		  "<P><A HREF=\"$PROGNAME?func=$IMG_ADD&$baseargs\">".
		  "<IMG SRC=\"pict/but_ok.jpg\" BORDER=\"0\" ".
		  "WIDTH=\"43\" ALT=\"Ok\">".
		  "</A>\n";
		return;
	}

	# The get the images directory and file name
	my $img = "";
	if ($img_path =~ /\/($REG_FILE)$/) {
		$img = "$IMGDIR/$1";
	}
	else {
		print_err ("Error Parsing Image Path ($img_path)");
	}

	# Get the full path of the destination
	my $img_dst = "$host_dir/$img";
	if ((-e "$img_dst") || (-l "$img_dst")) {
		print_err ("Image by the same name already exists in the Host directory ($img)");
	}

	my $orig_size = (stat("$img_path"))[7];

	# Copy, Move, or link it
	if ($import_type == $IMG_ADD_SYM) {

		log_host_info 
		  ("Sym Linking image $img_path into $args{'case'}:$args{'host'}");

		print_err ("ERROR: /bin/ln missing")
		  unless (-x '/bin/ln');

		print "Linking <TT>$img_path</TT> to <TT>$img_dst</TT><BR>\n";

		`/bin/ln -s \'$img_path\' \'$img_dst\'`;
		
	} elsif ($import_type == $IMG_ADD_COPY) {
		log_host_info 
		  ("Copying image $img_path into $args{'case'}:$args{'host'}");

		print_err ("ERROR: /bin/cp missing")
		  unless (-x '/bin/cp');

		print "Copying <TT>$img_path</TT> to <TT>$img_dst</TT><BR>\n";

		`/bin/cp \'$img_path\' \'$img_dst\'`;
	} elsif ($import_type == $IMG_ADD_MOVE) {
		log_host_info 
		  ("Moving image $img_path into $args{'case'}:$args{'host'}");

		print_err ("ERROR: /bin/mv missing")
		  unless (-x '/bin/mv');

		print "Moving <TT>$img_path</TT> to <TT>$img_dst</TT><BR>\n";

		`/bin/mv \'$img_path\' \'$img_dst\'`;
	} else {
		print_err ("Invalid Import Type: $import_type");
	}

	my $new_size = (stat("$img_dst"))[7];

	if ($new_size != $orig_size) {
		print_err ("Original image size ($orig_size) is not the same as the destination size ($new_size)");
	}

	my $do_md5 = get_do_md5();

	unless ($do_md5 == $MD5_NOTHING) {

		my $act_md5 = "";

		# Do we need to calculate an MD5?
		if (($do_md5 == $MD5_CALC) || (($do_md5 == $MD5_ADD) && 
		  (exists $args{'ver_md5'}) && ($args{'ver_md5'} == 1) ) ) {

			print "<P>Calculating MD5 of <TT>$img</TT> ".
			  "(this could take a while)<BR>\n";
			$act_md5 = calc_md5($img_dst);
			unless ($act_md5 =~ /^$REG_MD5$/o) {
				print "Error calculating MD5<BR>\n";
				return 1;
			}
			print "Current MD5: <TT>$act_md5</TT><BR>\n"; 
		}

		# And md5 value was given so we can add it to the md5.txt file
		if (($do_md5 == $MD5_ADD) && (exists $args{'md5'})) {

			my $md5 = $args{'md5'};
			unless ($md5 =~ /^$REG_MD5$/o) {
				if ($md5 eq "") {
					print "MD5 value missing<BR>\n";
				}
				else {
					print "Invalid MD5 value (32 numbers or letters a-f)<BR>\n";
				}
				print "<P><A HREF=\"$PROGNAME?func=$IMG_ADD&$baseargs\">".
				  "<IMG SRC=\"pict/but_ok.jpg\" BORDER=\"0\" ".
				  "WIDTH=\"43\" ALT=\"Ok\">".
				  "</A>\n";
				return 1;
			}
			$md5 =~ tr/[a-f]/[A-F]/;

			# They also want us to validate the MD5
		  	if ((exists $args{'ver_md5'}) && ($args{'ver_md5'} == 1) ) {

				if ($act_md5 eq $md5) {
            		print "Integrity Check Passed<BR>\n";
					log_host_info ("Integrity check passed on new image ($img)");
				} else { 
					print "<FONT COLOR=\"$DEL_COLOR[0]\">".
					  "Integrity Check Failed<BR></FONT><BR>\n".
					  "Provided: <TT>$md5</TT><BR>\n";

					log_host_info ("Integrity check failed on new image ($img)");
					return 1;
				}
			} 
			# set the act_md5 value to what was given and verified
			$act_md5 = $md5;
		}
		update_md5 ("$img", "$act_md5");
	}

	update_host_config ("image", "$img", "$fstype    $mnt");
	print "<P>Image: <TT>$img_path</TT> added to config file as <TT>$img</TT>\n";

print <<EOF;
<P>
<CENTER>
<TABLE WIDTH=600>
<TR>
  <TD WIDTH=300 ALIGN=CENTER>
    <A HREF=\"$PROGNAME?func=$IMG_OPEN&${baseargs_noimg}\">
    <IMG SRC=\"pict/menu_b_ok.jpg\" ALT=\"Ok\" WIDTH=\"167\" BORDER=\"0\">
    </A>
  </TD>
  <TD WIDTH=300 ALIGN=CENTER>
    <A HREF=\"$PROGNAME?func=$IMG_ADD&${baseargs_noimg}\">
    <IMG SRC=\"pict/menu_b_inew.jpg\" ALT=\"Ok\" WIDTH=\"167\" BORDER=\"0\">
    </A>
  </TD>
</TR>
</TABLE>
</CENTER>

EOF
	return;
};

# Display details of image based on config values
# provides links to remove the config of the image and to get the file
# system details
$funcs[$IMG_DETAILS] = sub {
	check_img('img'); check_ftype(); check_mnt();
	print_html_header("Details of $args{'img'}");

	my $mnt = get_mnt();
	my $ftype = get_ftype();

	print "<CENTER>".
	  "<IMG SRC=\"pict/menu_h_idet.jpg\" ALT=\"Image Details\">".
	  "<BR><BR><BR>\n".
	  "<TABLE WIDTH=\"600\" CELLSPACING=\"0\" CELLPADDING=\"2\" ".
	  "BACKGROUND=\"$YEL_PIX\" BORDER=0>\n".
	  "  <TR><TD COLSPAN=\"2\">&nbsp;</TD></TR>\n".
	  # Name
	  "  <TR><TD ALIGN=\"RIGHT\" WIDTH=\"300\"><B>Name:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>$args{'img'}</TT></TD></TR>\n".
	  # Mount
	  "  <TR><TD ALIGN=\"RIGHT\"><B>Mounting Point:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>$mnt</TT></TD></TR>\n".
	  # Type
	  "  <TR><TD ALIGN=\"RIGHT\"><B>File System Type:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>$ftype</TT></TD></TR>\n";

	my $md5 = lookup_md5($args{'img'}); 
	print "  <TR><TD ALIGN=\"RIGHT\"><B>MD5:</B></TD><TD><TT>".
	  (($md5 =~ /^$REG_MD5$/o)? $md5 : "&nbsp;").
	  "</TT></TD></TR>\n".

	  # Host Directory
	  "  <TR><TD ALIGN=\"RIGHT\"><B>Host Directory:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>$host_dir</TT></TD></TR>\n".
	  "  <TR><TD COLSPAN=\"2\">&nbsp;</TD></TR>\n".

	  # Strings File
	  "  <TR><TD ALIGN=\"RIGHT\"><B>Strings File:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>".
	  ((exists $img2str{$args{'img'}}) ? $img2str{$args{'img'}} : "&nbsp;").
	  "</TT></TD></TR>\n".

	  # dls file
	  "  <TR><TD ALIGN=\"RIGHT\"><B>Unallocated Data (dls) File:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>".
	  ((exists $img2dls{$args{'img'}}) ? $img2dls{$args{'img'}} : "&nbsp;").
	  "</TT></TD></TR>\n".

	  # Strings of dls
	  "  <TR><TD ALIGN=\"RIGHT\"><B>Strings of Unallocated Data File:</B></TD>".
	  "<TD ALIGN=\"LEFT\"><TT>".
	  ( ( (exists $img2dls{$args{'img'}}) &&
	  (exists $img2str{$img2dls{$args{'img'}}})) ? 
		$img2str{$img2dls{$args{'img'}}} : "&nbsp;").
	  "</TT></TD></TR>\n".
	  "  <TR><TD COLSPAN=\"2\">&nbsp;</TD></TR>\n".
	  "</TABLE>\n";

	print "<BR><BR><BR>".
	  "<TABLE WIDTH=\"600\" CELLSPACING=\"0\" CELLPADDING=\"2\">\n".
	
	# Ok
	  "<TR><TD ALIGN=CENTER>".
	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n". 
      "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$IMG_OPEN\">\n".
	  make_hidden().
	  "<INPUT TYPE=\"image\" SRC=\"pict/menu_b_ok.jpg\" ".
	  "ALT=\"Ok\" WIDTH=\"167\" BORDER=0></FORM></TD>\n".

	# File System Details
	  "<TD ALIGN=CENTER>".
	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"_blank\">\n". 
	  make_hidden().
      "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$MAIN_FR\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"mode\" VALUE=\"$FS_MAIN\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"mnt\" VALUE=\"$args{'mnt'}\">\n".
	  "<INPUT TYPE=\"image\" SRC=\"pict/menu_b_fs.jpg\" ".
	  "ALT=\"File System\" BORDER=0></FORM></TD>\n".

	# Remove Image
	  "<TD ALIGN=CENTER>".
	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n". 
      "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$IMG_DEL\">\n".
	  make_hidden().
      "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"mnt\" VALUE=\"$args{'mnt'}\">\n".
	  "<INPUT TYPE=\"image\" SRC=\"pict/menu_b_rem.jpg\" ".
	  "ALT=\"Remove\" BORDER=0></FORM></TD>\n".
	  "</TR></TABLE>\n";

	return;
};



# remove the config files
$funcs[$IMG_DEL] = sub {
	check_img('img'); check_ftype(); 
	print_html_header("Removing Configuration Settings for $args{'img'}");

	update_host_config("", $args{'img'}, "");
	update_md5($args{'img'}, "");

	print "Settings for <TT>$args{'img'}</TT> removed from ".
	  "<TT>$args{'case'}:$args{'host'}</TT>.\n".
	  "<P>NOTE: The actual file still exists in the host directory.\n";


	print "<P><A HREF=\"$PROGNAME?func=$IMG_OPEN&${baseargs_noimg}\">".
	  "<IMG SRC=\"pict/but_ok.jpg\" ALT=\"Ok\" ".
	  "WIDTH=\"43\" BORDER=\"0\"></A>\n";

	return();
};

###################################################################





# Blank Page
$funcs[$BLANK] = sub { 
	print_html_header("");
	print "<!-- This Page Intentionally Left Blank -->\n";
	return 0;
};


#
###################### FILE MODE ###################
#

#
# Make the three frames and fill them in
#
$funcs[$FIL_MAIN] = sub {

	# If we were not given the inode, then look up the root
	unless (exists $args{'inode'}) {
		my $ftype = get_ftype();
		$args{'inode'} = $enc_args{'inode'} = $root_inode{$ftype};
	}

	unless (exists $args{'dir'}) {
		$args{'dir'} = "/";
	}

	check_inode('inode'); check_dir();

	print_html_header_frameset("$args{'mnt'}$args{'dir'} on $args{'img'}");

	my $sort = $SORT_NAME;
	$sort = $args{'sort'} if (exists $args{'sort'});

	my $dmode = $DMODE_NOSHOW;
	$dmode = $args{'dmode'} if (exists $args{'dmode'});

	print "<FRAMESET COLS=\"175,*\">\n";

	# Directory Listing on Left
	my $url = "$PROGNAME?$baseargs&dir=$enc_args{'dir'}&".
	  "sort=$sort&dmode=$dmode&inode=$enc_args{'inode'}";

	print "<FRAME SRC=\"$url&func=$FIL_DIR\">\n";

	# File frameset on right
	print "<FRAMESET ROWS=\"50%,50%\">\n";

	# File Listings on top
	print "<FRAME SRC=\"$url&func=$FIL_LIST\" ".
	  "NAME=\"list\">\n";

	# File Contents
	print "<FRAME SRC=\"$PROGNAME?func=$BLANK&$baseargs\" ".
	  "NAME=\"content\">\n".
	  "</FRAMESET>\n".
	  "</FRAMESET>\n";

	return 0;
};

#
# Print the directory names for the lhs frame
# 
# THIS NEEDS TO IMPROVE TO BECOME MORE USABLE
#

$funcs[$FIL_DIR] = sub {
	check_dir(); check_sort(); check_dmode();

	print_html_header("");

	my $ftype = get_ftype();
	my $sort = get_sort();
	my $dmode = get_dmode();

	my $lcldir = "";
	my $prev_plus = ""; 			# previous number of '+' directory spacers
	my $prev_fname = "";
	my $prev_meta = "";
	my $img = get_img('img');


	# Field to enter a directory into:
    print "<P><FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"list\">\n".
      "<B>View Directory:</B><BR><TT>$args{'mnt'}</TT>".
      "<INPUT TYPE=\"text\" NAME=\"dir\" SIZE=24 MAXLENGTH=100>\n".
      "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$FIL_NAME\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"mnt\" VALUE=\"$args{'mnt'}\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"sort\" VALUE=\"$args{'sort'}\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"dmode\" VALUE=\"$args{'dmode'}\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"inode\" VALUE=\"0\">\n".
      make_hidden().

    # Ok Button
      "<P><INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".
      "ALT=\"Ok\" BORDER=\"0\"></FORM>\n";

	print "<P><HR><P>\n";

	my $base_url = "$PROGNAME?$baseargs&sort=$sort";

	# All deleted files button
	print "<A HREF=\"$base_url&func=$FIL_DEL&inode=$root_inode{$ftype}&dir=\" ".
	  "TARGET=\"list\">".
	  "<IMG BORDER=\"0\" ".
	  "SRC=\"pict/file_b_alldel.jpg\" ".
	  "WIDTH=\"127\" ".
	  "ALT=\"Show All Deleted Files\">".
	  "</A><P>\n";

	# The dmode arg shows if we should expand the whole directory listing
	# or not 
	if ($dmode == $DMODE_NOSHOW) {
		print "<A HREF=\"$base_url&func=$FIL_MAIN&dmode=$DMODE_SHOW\" ".
		  "TARGET=\"_parent\">".
	  	  "<IMG SRC=\"pict/file_b_expand.jpg\" ALT=\"Expand All Directories\" ".
	  	  "BORDER=\"0\"></A><P><HR>\n";

		return;
	}
	else {
		print "<A HREF=\"$base_url&func=$FIL_MAIN&dmode=$DMODE_NOSHOW\" ".
		  "TARGET=\"_parent\">".
		  "<IMG SRC=\"pict/file_b_hide.jpg\" ALT=\"Hide All Directories\" ".
		  "BORDER=\"0\"></A><P><HR>\n";
	}


	$base_url .= "&dmode=$dmode";

	log_host_inv ("$args{'img'}: List of all directories");
	
	# We need to maintain state to create dir and this is done by
	# counting the + marks.
	my @out = `\'${TASKDIR}fls\' -f $ftype -ruD \'$img\'`;

	# Print root 
	my $url = "$base_url&func=$FIL_LIST&inode=$root_inode{$ftype}&dir=";
	print "<P><A HREF=\"$url\" TARGET=\"list\">$args{'mnt'}</A><BR>\n";


	foreach $_ (@out) {
		if (/^(\*)?(\+*)\s*[\-d]\/[\-d]\s*(\d+)\-?\d*\-?\d*\s*(\(realloc\))?:\t(.+)$/) {

			my $del = $1;
			my $plus = $2;
			my $meta = $3;
			my $re = $4;
			my $fname = $5;
	
			# Adjust the dir value using the '++' values to determine
			# how "deep" we are
			unless ($prev_plus eq $plus) {
				# are we in 1 more
				if ($plus eq $prev_plus.'+') {
					$lcldir .= ($prev_fname."/");
				}
				# we are back (at least one)
				elsif (defined $plus) {
					my @dirs = split ('/', $lcldir); 
					my $idx = -1;
					$lcldir = "";

					while (($idx = index ($plus, '+', $idx+1)) != -1) {
						$lcldir .= ($dirs[$idx]."/");
					}
				}
			}

			$prev_plus = $plus;
			$prev_fname = $fname;
			$prev_meta = $meta;

			$url = "$base_url&func=$FIL_LIST&inode=$meta".
			  "&dir=".url_encode($lcldir.$fname."/");

			print "<FONT COLOR=\"$DEL_COLOR[0]\">" if defined $del;
			print "+$plus<A HREF=\"$url\" TARGET=\"list\"><TT>/$fname</TT></A><BR>\n";
			print "</FONT>" if defined $del;
		}
	}
	return 0;

};	# end of FIL_DIR


# Print the files and directories for the upper rhs frame
# These can be sorted in any format
#
# We need to find a way to cache this data
#
$funcs[$FIL_LIST] = sub {
	check_inode('inode'); check_dir(); check_sort(); check_dmode();

	my $fname = "$args{'mnt'}$args{'dir'}";

	my $sp = "&nbsp;&nbsp;";

	print_html_header("Entries in $fname");

	my (@itype, @dtype, @name, @mod, @acc, @chg, @size, @gid, @uid, @inode);
	my (@dir, @entry, @del, @realloc, @inode_int);

	my $sort = get_sort();
	my $ftype = get_ftype();
	my $inode = get_inode('inode');
	my $img = get_img('img');


	log_host_inv ("$args{'img'}: Directory listing of $fname ($inode)");

	# execute command
	my @out = `\'${TASKDIR}fls\' -f $ftype -la -z \'$tz\' -s $ts \'$img\' $inode`;

	# Make the big table, small table, and start the current directory

	my $iurl = 
	  "$PROGNAME?$baseargs&dmode=$enc_args{'dmode'}&sort=$sort";

print <<EOF1;
<!-- Big Table -->
<TABLE CELLSPACING=\"0\" CELLPADDING=\"2\" BORDER=0>

<!-- Small Table -->
<TR>
  <TD COLSPAN=19>
    <TABLE BORDER=0 ALIGN=\"left\" CELLSPACING=\"0\" CELLPADDING=\"2\" WIDTH=500>
    <TR>
      <TD COLSPAN=2><B>Current Directory:</B> <TT>

        <A HREF=\"${iurl}&func=$FIL_LIST&inode=$root_inode{$ftype}&dir=\">$args{'mnt'}</A>&nbsp;

EOF1

	# Each file in the path will get its own link
	$iurl .= "&func=$FIL_NAME&inode=0";
	my $path = "";
	my @dir_split = split ('/', $args{'dir'});
	while (scalar @dir_split > 1) {
		my $d = shift @dir_split;

		next if ($d eq '');

		$path .= "$d/";
		print 
		  "        <A HREF=\"${iurl}&dir=$path\">/${d}/</A>&nbsp;\n";
	}
	print "        /$dir_split[0]/&nbsp;\n"
	  if (scalar @dir_split == 1);

	print "      </TT></TD>\n".
	  "    </TR>\n";


	# Add Note Button
	$iurl = "&$baseargs&dir=$enc_args{'dir'}&inode=$enc_args{'inode'}";
	if ($USE_NOTES == 1) {

print <<EOF2;
    <TR>
      <TD WIDTH=\"100\" ALIGN=LEFT>
        <A HREF=\"$PROGNAME?func=$NOTES_ENT$iurl\" TARGET=\"_blank\">
          <IMG BORDER=\"0\" SRC=\"pict/but_addnote.jpg\" WIDTH=\"89\"ALT=\"Add Note About Directory\">
         </A>
      </TD>
EOF2

	}

	# Generate MD5 List Button
print <<EOF3;

      <TD WIDTH=\"206\" ALIGN=LEFT>
        <A HREF=\"$PROGNAME?func=$FIL_MD5$iurl\" TARGET=\"_blank\">
          <IMG BORDER=\"0\" SRC=\"pict/file_b_md5list.jpg\" WIDTH=\"206\" ALT=\"Generate list of MD5 values\">
        </A>
      </TD>
    </TR>
  <!-- END of Little Table -->
  </TABLE>
  </TD>
</TR>
<TR>
  <TD COLSPAN=19><HR></TD>
</TR>

EOF3

	# Make the Table and Headers
	my $url="$PROGNAME?func=$FIL_MAIN&$baseargs&inode=$enc_args{'inode'}".
	  "&dir=$enc_args{'dir'}&dmode=$enc_args{'dmode'}";

	print "<TR VALIGN=\"MIDDLE\" ".
	  "BACKGROUND=\"$YEL_PIX\">\n";


	# Print the Headers - If the sorting mode is set to it, then don't
	# make it a link and print a different button
	if ($sort == $SORT_DEL) {
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<IMG BORDER=\"0\" ".
		  "SRC=\"pict/file_h_del_cur.jpg\" ".
		  "WIDTH=\"49\" ".
		  "ALT=\"Deleted Files\">".
		  "</TD>\n";
	} else {
		$iurl = $url."&sort=$SORT_DEL";
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<A HREF=\"$iurl\" TARGET=\"_parent\">".
		  "<IMG BORDER=\"0\" ".
		  "SRC=\"pict/file_h_del_link.jpg\" ".
		  "WIDTH=\"28\" ".
		  "ALT=\"Deleted Files\">".
		  "</A></TD>\n";
	}

	# type only gets one column for two 'types'
	print "  <TD BACKGROUND=\"$YEL_PIX\">$sp</TD>\n".
	  "  <TH ALIGN=\"CENTER\" BACKGROUND=\"$YEL_PIX\">".
	  "&nbsp;&nbsp;Type&nbsp;&nbsp;<BR>";

	if ($sort == $SORT_DTYPE) {
		print "dir";
	} else {
		$iurl = $url."&sort=$SORT_DTYPE";
		print "<A HREF=\"$iurl\" TARGET=\"_parent\">dir</A>";
	}

	print "&nbsp;/&nbsp;";

	if ($sort == $SORT_ITYPE) {
		print "in</TH>\n";
	} else {
		$iurl = $url."&sort=$SORT_ITYPE";
		print "<A HREF=\"$iurl\" TARGET=\"_parent\">in</A></TH>\n";
	}

	print "  <TD BACKGROUND=\"$YEL_PIX\">$sp</TD>\n";

	if ($sort == $SORT_NAME) {
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<IMG BORDER=\"0\" ".
		  "SRC=\"pict/file_h_nam_cur.jpg\" ".
		  "WIDTH=\"76\" ".
		  "ALT=\"File Name\">".
		  "</TD>\n";
	} else {
		$iurl = $url."&sort=$SORT_NAME";
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<A HREF=\"$iurl\" TARGET=\"_parent\">".
		  "<IMG BORDER=\"0\" ".
		  "SRC=\"pict/file_h_nam_link.jpg\" ".
		  "WIDTH=\"50\" ".
		  "ALT=\"File Name\">".
		  "</A></TD>\n";
	}

	print "  <TD BACKGROUND=\"$YEL_PIX\">$sp</TD>\n";

	# Modified / Written
	if ($sort == $SORT_MOD) {
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">";
		if ($mtime_str{$ftype} eq 'Modified') {	
			print "<IMG BORDER=\"0\" ".
			  "SRC=\"pict/file_h_mod_cur.jpg\" ".
			  "WIDTH=\"84\" ".
			  "ALT=\"Modified Time\">";
		} else {
			print "<IMG BORDER=\"0\" ".
			  "SRC=\"pict/file_h_wr_cur.jpg\" ".
			  "WIDTH=\"89\" ".
			  "ALT=\"Written Time\">";
		}
		print "</TD>\n";
	} else {
		$iurl = $url."&sort=$SORT_MOD";
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<A HREF=\"$iurl\" TARGET=\"_parent\">";
		if ($mtime_str{$ftype} eq 'Modified') {	
			print "<IMG BORDER=\"0\" ".
			  "SRC=\"pict/file_h_mod_link.jpg\" ".
			  "WIDTH=\"62\" ".
			  "ALT=\"Modified Time\">";
		} else {
			print "<IMG BORDER=\"0\" ".
			  "SRC=\"pict/file_h_wr_link.jpg\" ".
			  "WIDTH=\"60\" ".
			  "ALT=\"Written Time\">";
		}
		print "</A></TD>\n";
	}

	print "  <TD BACKGROUND=\"$YEL_PIX\">$sp</TD>\n";

	# Accessed
	if ($sort == $SORT_ACC) {
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<IMG BORDER=\"0\" ".
		  "SRC=\"pict/file_h_acc_cur.jpg\" ".
		  "WIDTH=\"90\" ".
		  "ALT=\"Access Time\">".
		  "</TD>\n";
	} else {
		$iurl = $url."&sort=$SORT_ACC";
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<A HREF=\"$iurl\" TARGET=\"_parent\">".
		  "<IMG BORDER=\"0\" ".
		  "SRC=\"pict/file_h_acc_link.jpg\" ".
		  "WIDTH=\"66\" ".
		  "ALT=\"Access Time\">".
		  "</A></TD>\n";
	}

	print "  <TD BACKGROUND=\"$YEL_PIX\">$sp</TD>\n";

	# Change / Create
	if ($sort == $SORT_CHG) {
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">";
		if ($ctime_str{$ftype} eq 'Changed') {	
			print "<IMG BORDER=\"0\" ".
			  "SRC=\"pict/file_h_chg_cur.jpg\" ".
			  "WIDTH=\"90\" ".
			  "ALT=\"Change Time\">";
		} else {
			print "<IMG BORDER=\"0\" ".
			  "SRC=\"pict/file_h_cre_cur.jpg\" ".
			  "WIDTH=\"84\" ".
			  "ALT=\"Create Time\">";
		}
		print "</TD>\n";
	} else {
		$iurl = $url."&sort=$SORT_CHG";
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<A HREF=\"$iurl\" TARGET=\"_parent\">";
		if ($ctime_str{$ftype} eq 'Changed') {	
			print "<IMG BORDER=\"0\" ".
			  "SRC=\"pict/file_h_chg_link.jpg\" ".
			  "WIDTH=\"62\" ".
			  "ALT=\"Change Time\">";
		} else {
			print "<IMG BORDER=\"0\" ".
			  "SRC=\"pict/file_h_cre_link.jpg\" ".
			  "WIDTH=\"59\" ".
			  "ALT=\"Create Time\">";
		}
		print "</A></TD>\n";
	}

	print "  <TD BACKGROUND=\"$YEL_PIX\">$sp</TD>\n";

	# Size
	if ($sort == $SORT_SIZE) {
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<IMG BORDER=\"0\" ".
		  "SRC=\"pict/file_h_siz_cur.jpg\" ".
		  "WIDTH=\"53\" ".
		  "ALT=\"Size\">".
		  "</TD>\n";
	} else {
		$iurl = $url."&sort=$SORT_SIZE";
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<A HREF=\"$iurl\" TARGET=\"_parent\">".
		  "<IMG BORDER=\"0\" ".
		  "SRC=\"pict/file_h_siz_link.jpg\" ".
		  "WIDTH=\"31\" ".
		  "ALT=\"Size\">".
		  "</A></TD>\n";
	}

	print "  <TD BACKGROUND=\"$YEL_PIX\">$sp</TD>\n";

	# UID
	if ($sort == $SORT_UID) {
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<IMG BORDER=\"0\" ".
		  "SRC=\"pict/file_h_uid_cur.jpg\" ".
		  "WIDTH=\"49\" ".
		  "ALT=\"UID\">".
		  "</TD>\n";
	} else {
		$iurl = $url."&sort=$SORT_UID";
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<A HREF=\"$iurl\" TARGET=\"_parent\">".
		  "<IMG BORDER=\"0\" ".
		  "SRC=\"pict/file_h_uid_link.jpg\" ".
		  "WIDTH=\"27\" ".
		  "ALT=\"UID\">".
		  "</A></TD>\n";
	}

	print "  <TD BACKGROUND=\"$YEL_PIX\">$sp</TD>\n";

	# GID
	if ($sort == $SORT_GID) {
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<IMG BORDER=\"0\" ".
		  "SRC=\"pict/file_h_gid_cur.jpg\" ".
		  "WIDTH=\"49\" ".
		  "ALT=\"GID\">".
		  "</TD>\n";
	} else {
		$iurl = $url."&sort=$SORT_GID";
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<A HREF=\"$iurl\" TARGET=\"_parent\">".
		  "<IMG BORDER=\"0\" ".
		  "SRC=\"pict/file_h_gid_link.jpg\" ".
		  "WIDTH=\"28\" ".
		  "ALT=\"GID\">".
		  "</A></TD>\n";
	}

	print "  <TD BACKGROUND=\"$YEL_PIX\">$sp</TD>\n";

	# Inode
	if ($sort == $SORT_INODE) {
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<IMG BORDER=\"0\" ".
		  "SRC=\"pict/file_h_meta_cur.jpg\" ".
		  "WIDTH=\"62\" ".
		  "ALT=\"Meta\">".
		  "</TD>\n";
	} else {
		$iurl = $url."&sort=$SORT_INODE";
		print "  <TD ALIGN=\"LEFT\" BACKGROUND=\"$YEL_PIX\">".
		  "<A HREF=\"$iurl\" TARGET=\"_parent\">".
		  "<IMG BORDER=\"0\" ".
		  "SRC=\"pict/file_h_meta_link.jpg\" ".
		  "WIDTH=\"41\" ".
		  "ALT=\"Meta\">".
		  "</A></TD>\n";
	}
	print "</TR>\n";



	if (scalar (@out) == 0) {
		print "</TABLE>\n<CENTER>No Contents</CENTER>\n";
		return 0;
	}

	my $cnt = 0;

	# sort into arrays
	foreach $_ (@out) {
		if (/^([\?dfcbrlsw-])\/([\?dfcbrlsw-])\s*(\*?)\s*($REG_INODE)(\(realloc\))?:\t(.+?)\t($REG_DATE)\t($REG_DATE)\t($REG_DATE)\t(\d+)\t(\d+)\t(\d+)$/o) {

			my $lcldir = $args{'dir'};
			$dtype[$cnt] = $1;
			$itype[$cnt] = $2;
			$del[$cnt] = $3;
			$inode[$cnt] = $4;
			$realloc[$cnt] = "";
			$realloc[$cnt] = $5 if (defined $5);
			$name[$cnt] = $6;
			$mod[$cnt] = $7;
			$acc[$cnt] = $8;
			$chg[$cnt] = $9;
			$size[$cnt] = $10;
			$gid[$cnt] = $11;
			$uid[$cnt] = $12;

			if ($inode[$cnt] =~ /^(\d+)(-\d+(-\d+)?)?$/) {
				$inode_int[$cnt] = $1;
			} else {
				$inode_int[$cnt] = $inode[$cnt];
			}

			# We must adjust the dir for directories
			if ($itype[$cnt] eq 'd') {
				# special cases for .. and .
				if ($name[$cnt] eq '..') {
					my @dirs = split ('/', $lcldir);
					my $i;
					$lcldir = "";
					for ($i = 0; $i < $#dirs; $i++) {
						$lcldir .= ($dirs[$i].'/');
					}
				}
				elsif ($name[$cnt] ne '.') {
					$lcldir .= ($name[$cnt].'/');
				}
				$name[$cnt] .= '/';
			}
			else {
				$lcldir .= $name[$cnt];
			}


			# format the date so that the time and time zone are on the
			# same line
			$mod[$cnt] = "$1&nbsp;$2"  
			  if ($mod[$cnt] =~ /($REG_DAY\s+$REG_TIME)\s+($REG_ZONE2)/o);

			$acc[$cnt] = "$1&nbsp;$2"  
			  if ($acc[$cnt] =~ /($REG_DAY\s+$REG_TIME)\s+($REG_ZONE2)/o);

			$chg[$cnt] = "$1&nbsp;$2"  
			  if ($chg[$cnt] =~ /($REG_DAY\s+$REG_TIME)\s+($REG_ZONE2)/o);

			$dir[$cnt] = url_encode($lcldir);
			$entry[$cnt] = $cnt;
			$cnt++;

		} 
		# We missed it for some reason
		else {
			print "<TR><TD COLSPAN=10>Error parsing string: $_</TD></TR>\n";
		}
	}

	# Sort the above array based on the sort argument
	my @sorted;	# an array of indices

	if ($sort == $SORT_DTYPE) {
		@sorted = sort {
			$dtype[$a] cmp $dtype[$b] or
			lc($name[$a]) cmp lc($name[$b])
		} @entry;
	} elsif ($sort == $SORT_ITYPE) {
		@sorted = sort {
			$itype[$a] cmp $itype[$b] or
			lc($name[$a]) cmp lc($name[$b])
		} @entry;
	} elsif ($sort == $SORT_NAME) {
		@sorted = sort {
			lc($name[$a]) cmp lc($name[$b])
		} @entry;
	} elsif ($sort == $SORT_MOD) {
		@sorted = sort {
			$mod[$a] cmp $mod[$b] or
			lc($name[$a]) cmp lc($name[$b])
		} @entry;
	} elsif ($sort == $SORT_ACC) {
		@sorted = sort {
			$acc[$a] cmp $acc[$b] or
			lc($name[$a]) cmp lc($name[$b])
		} @entry;
	} elsif ($sort == $SORT_CHG) {
		@sorted = sort {
			$chg[$a] cmp $chg[$b] or
			lc($name[$a]) cmp lc($name[$b])
		} @entry;
	} elsif ($sort == $SORT_SIZE) {
		@sorted = sort {
			$size[$a] <=> $size[$b] or
			lc($name[$a]) cmp lc($name[$b])
		} @entry;
	} elsif ($sort == $SORT_UID) {
		@sorted = sort {
			$uid[$a] <=> $uid[$b] or
			lc($name[$a]) cmp lc($name[$b])
		} @entry;
	} elsif ($sort == $SORT_GID) {
		@sorted = sort {
			$gid[$a] <=> $gid[$b] or
			lc($name[$a]) cmp lc($name[$b])
		} @entry;
	} elsif ($sort == $SORT_INODE) {
		@sorted = sort {
			$inode_int[$a] <=> $inode_int[$b] or
			lc($name[$a]) cmp lc($name[$b])
		} @entry;
	} elsif ($sort == $SORT_DEL) {
		@sorted = sort {
			$del[$b] cmp $del[$a] or
			lc($name[$a]) cmp lc($name[$b])
		} @entry;
	}

	# print them based on sorting
	my $row = 0;
	foreach my $i (@sorted) {
		my $url;
		my $target;
		my $func;
		my $color;
		my $lcolor;
		if ($del[$i] eq '*') {
			$color = "<FONT COLOR=\"".$DEL_COLOR[$realloc[$i] ne ""]."\">";
			$lcolor = $color;
		} else {
			$color = "<FONT COLOR=\"$NORM_COLOR\">";
			$lcolor = "<FONT COLOR=\"$LINK_COLOR\">";
		}

		# directories have different targets and func values
		if ($itype[$i] eq 'd') {
			$target = "list";
			$url="$PROGNAME?func=$FIL_LIST&$baseargs&inode=$inode_int[$i]".
			  "&sort=$sort&dir=$dir[$i]&dmode=$enc_args{'dmode'}";
		}
		else {
			$target = "content";
			$url="$PROGNAME?func=$FIL_CMENU_FR&$baseargs&inode=$inode[$i]".
			   "&sort=$sort&dir=$dir[$i]&dmode=$enc_args{'dmode'}";
		}

		if (($row % 2) == 0) {
			print "<TR VALIGN=\"TOP\" BGCOLOR=\"$BACK_COLOR\">\n  <TD ALIGN=\"CENTER\">";
		} else {
			print "<TR VALIGN=\"TOP\" BGCOLOR=\"$BACK_COLOR_TABLE\">\n  <TD ALIGN=\"CENTER\">";
		}

		print "<IMG SRC=\"pict/file_b_check.jpg\" BORDER=\"0\">\n"
		  if ($del[$i] eq '*') ;

		print "</TD>\n".
		  "  <TD>$sp</TD>\n".
		  "  <TD ALIGN=\"CENTER\">${color}$dtype[$i]&nbsp;/&nbsp;$itype[$i]</TD>\n".
		  "  <TD>$sp</TD>\n";

		# for valid files and directories make a link
		if ( ($inode_int[$i] >= $first_inode{$ftype}) && 
		 ($size[$i] > 0) && 
		 (($itype[$i] eq 'r') || ($itype[$i] eq 'd'))) {
			print "  <TD><A HREF=\"$url\" TARGET=\"$target\">$lcolor";
		} 
		else {
			print "  <TD>$color";
		}
		print "<TT>$name[$i]</TT></TD>\n".
		  "  <TD>$sp</TD>\n".
		  "  <TD>${color}$mod[$i]</TD>\n".
		  "  <TD>$sp</TD>\n".
		  "  <TD>${color}$acc[$i]</TD>\n".
		  "  <TD>$sp</TD>\n".
		  "  <TD>${color}$chg[$i]</TD>\n".
		  "  <TD>$sp</TD>\n".
		  "  <TD>${color}$size[$i]</TD>\n".
		  "  <TD>$sp</TD>\n".
		  "  <TD>${color}$uid[$i]</TD>\n".
		  "  <TD>$sp</TD>\n".
		  "  <TD>${color}$gid[$i]</TD>\n".
		  "  <TD>$sp</TD>\n";
		  
		# for a valid inode, make a link to inode browsing mode
		if ($inode_int[$i] >= $first_inode{$ftype}) {
			my $iurl="$PROGNAME?func=$MAIN_FR&mode=$INO_MAIN&$baseargs&inode=$inode[$i]";
			print "<TD><A HREF=\"$iurl\" TARGET=\"_blank\">$lcolor";
		}
		else {
			print "<TD>$color";
		}
		print "$inode[$i]</A> $realloc[$i]</TD>\n</TR>\n";

		$row++;
	}

	print "</TABLE>\n";
	return 0;

}; #end of FIL_LIST


# This takes a directory name as an argument and converts it to
# the inode value and calls FIL_LIST
#
# The inode value can be anything when this is run, it will be 
# overwritten
$funcs[$FIL_NAME] = sub {
	check_dir(); 

	my $ftype = get_ftype();
	my $img = get_img('img');
	my $dir = get_dir();

	log_host_inv ("$args{'img'}: Finding meta data address for $dir");

	# Use 'ifind -n' to get the inode
    my $inode = `\'${TASKDIR}ifind\' -f $ftype -n \'$dir\' \'$img\'`;
	# Do the Taint Checking
	$inode = $1
	  if ($inode =~ /^($REG_INODE)$/);
 
	unless ($inode =~ /^$REG_INODE$/) {
		print_check_err ("Error finding meta data address for $dir: $inode");
	}

	# Verify it is a directory with istat
	my $out = `\'${TASKDIR}istat\' -f $ftype \'$img\' $inode`;
	unless (($out =~ /mode:\s+d/)  || ($out =~ /DOS Mode: Directory/)) {
		print_html_header("");

	# Give link to contents if it is a file

print <<EOF;

<TT>$dir</TT> (inode $inode) is not a directory
<P>
<A HREF=\"$PROGNAME?func=$FIL_CMENU_FR&$baseargs&inode=$inode&dir=$dir\" TARGET=\"content\">
  <IMG SRC=\"pict/but_view.jpg\" ALT=\"view contents\" BORDER=\"0\">
</A>

EOF
		return 1;
	}

	# Set the inode variables
	$enc_args{'inode'} = $args{'inode'} = $inode;

	$args{'dir'} .= "/"
		unless ($args{'dir'} =~ /.*?\/$/);
	$enc_args{'dir'} .= "/"
		unless ($enc_args{'dir'} =~ /.*?\/$/);

	# List the directory contents
	& {$funcs[$FIL_LIST]};

	return 0;
};


# Content Frame
# This creates two frames for the lower rhs frame
#
$funcs[$FIL_CMENU_FR] = sub {
	check_inode('inode'); check_dir();

	print_html_header_frameset("");

	print "<FRAMESET ROWS=\"65,*\">\n";

	print "<FRAME SRC=\"$PROGNAME?func=$FIL_CMENU&$baseargs".
	  "&dir=$enc_args{'dir'}&inode=$enc_args{'inode'}".
	  "&sort=$FIL_SORT_ASC\">\n";

	print "<FRAME SRC=\"$PROGNAME?func=$FIL_CONT&$baseargs".
	  "&dir=$enc_args{'dir'}&inode=$enc_args{'inode'}".
	  "&sort=$FIL_SORT_ASC\" NAME=\"cont2\">\n</FRAMESET>";

	return 0;
};


# This is the index for the lower rhs frame
# Choose the content display type here
$funcs[$FIL_CMENU] = sub {
	check_inode('inode'); check_dir(); check_sort(); 

	print_html_header("");

	my $inode = get_inode('inode');
	my $img = get_img('img');
	my $ftype = get_ftype();

	# get the type of contents
	my $file_type = 
	  `\'${TASKDIR}icat\' -f $ftype \'$img\' $inode | \'${TASKDIR}file\' -z -b -`;

	# We already have the path in the content window below, so save space
	# print "<CENTER><TT>$args{'mnt'}$args{'dir'}</TT>\n";
	print "<CENTER>\n";
	my $url = "&$baseargs&dir=$enc_args{'dir'}&inode=$enc_args{'inode'}";

	# Print the options for output display
	print "<TABLE CELLSPACING=\"0\" CELLPADDING=\"2\">\n<TR>\n".
	  "<TD>ASCII (<A HREF=\"$PROGNAME?func=$FIL_CONT&sort=$FIL_SORT_ASC$url\"".
 	  "TARGET=\"cont2\">display</A> - ".
	  "<A HREF=\"$PROGNAME?func=$FIL_REP&sort=$FIL_SORT_ASC$url\"".
	  "TARGET=\"_blank\">report</A>)</TD>\n".
	  "<TD>*</TD>\n".
	  "<TD>Strings (".
	  "<A HREF=\"$PROGNAME?func=$FIL_CONT&sort=$FIL_SORT_STR$url\"".
 	  "TARGET=\"cont2\">display</A> - ".
	  "<A HREF=\"$PROGNAME?func=$FIL_REP&sort=$FIL_SORT_STR$url\"".
	  "TARGET=\"_blank\">report</A>)</TD>\n".
	  "<TD>*</TD>\n".
	  "<TD><A HREF=\"$PROGNAME?func=$FIL_SAVE&$url\">".
	  "Export</A></TD>\n";

	# if the file is either image or HTML, then let them view it 
	if (($file_type =~ /image data/) || ($file_type =~ /HTML document text/) ||
	 ($file_type =~ /PC bitmap data/)) {
	  print "<TD>*</TD>\n<TD><A HREF=\"$PROGNAME?func=$CELL_MAIN$url\"".
	  "TARGET=\"_blank\">View</A></TD>\n";
	}

	print "<TD>*</TD>\n".
	  "<TD><A HREF=\"$PROGNAME?func=$NOTES_ENT$url\" TARGET=\"_blank\">".
	  "Add Note</A></TD>\n" if ($USE_NOTES == 1);

	print "</TR></TABLE>\n";

	print "File Type: $file_type";
	print "</CENTER>";

	return 0;
};

# display deleted files only
#
# Sorting should be added to this
$funcs[$FIL_DEL] = sub {
	check_inode('inode'); check_dir(); check_sort(); 

	print_html_header("Deleted files on $args{'img'} $args{'mnt'}");

	my $inode = get_inode('inode');
	my $img = get_img('img');
	my $ftype = get_ftype();
	my $sort = get_sort();

	my $sp = "&nbsp;&nbsp;";

	log_host_inv ("$args{'img'}: Listing all deleted files");

	my @out = `\'${TASKDIR}fls\' -f $ftype -ldr -z \'$tz\' -s $ts \'$img\' $inode`;

	print "<TABLE CELLSPACING=\"0\" CELLPADDING=\"2\"  BORDER=0>\n".
	  "<TR VALIGN=\"MIDDLE\" ALIGN=\"LEFT\" ".
	  "BACKGROUND=\"$YEL_PIX\">\n";

	# Type
	print "<TH ALIGN=\"CENTER\">&nbsp;&nbsp;Type&nbsp&nbsp;<BR>".
	  "dir&nbsp;/&nbsp;in</TH>".
	  "<TD>$sp</TD>\n";


	# Name
	print "  <TD><IMG BORDER=\"0\" ".
	  "SRC=\"pict/file_h_nam_link.jpg\" ".
	  "WIDTH=\"50\" ".
	  "ALT=\"File Name\">".
	  "</TD>\n".
	  "<TD>$sp</TD>\n";

	# Mod / Written
	print "  <TD><IMG BORDER=\"0\" ";
	if ($mtime_str{$ftype} eq 'Modified') {
		print "SRC=\"pict/file_h_mod_link.jpg\" ".
		  "WIDTH=\"62\" ".
		  "ALT=\"Modified Time\">";
	} else {
		print "SRC=\"pict/file_h_wr_link.jpg\" ".
		  "WIDTH=\"60\" ".
		  "ALT=\"Written Time\">";
	}
	print "</TD>\n".
	  "<TD>$sp</TD>\n";

	# Access
	print "  <TD><IMG BORDER=\"0\" ".
	  "SRC=\"pict/file_h_acc_link.jpg\" ".
	  "WIDTH=\"66\" ".
	  "ALT=\"Access Time\">".
	  "</TD>\n".
	  "<TD>$sp</TD>\n";

	# Change / Create
	print "  <TD><IMG BORDER=\"0\" ";
	if ($ctime_str{$ftype} eq 'Changed') {	
		print "SRC=\"pict/file_h_chg_link.jpg\" ".
		  "WIDTH=\"62\" ".
		  "ALT=\"Change Time\">";
	} else {
		print  "SRC=\"pict/file_h_cre_link.jpg\" ".
		  "WIDTH=\"59\" ".
		  "ALT=\"Create Time\">";
	}
	print "</TD>\n".
	  "<TD>$sp</TD>\n";

	# Size
	print "  <TD><IMG BORDER=\"0\" ".
	  "SRC=\"pict/file_h_siz_link.jpg\" ".
	  "WIDTH=\"31\" ".
	  "ALT=\"Size\">".
	  "</TD>\n".
	  "<TD>$sp</TD>\n";

	# UID
	print "  <TD><IMG BORDER=\"0\" ".
	  "SRC=\"pict/file_h_uid_link.jpg\" ".
	  "WIDTH=\"27\" ".
	  "ALT=\"UID\">".
	  "</TD>\n".
	  "<TD>$sp</TD>\n";

	# GID
	print "  <TD><IMG BORDER=\"0\" ".
	  "SRC=\"pict/file_h_gid_link.jpg\" ".
	  "WIDTH=\"28\" ".
	  "ALT=\"GID\">".
	  "</TD>\n".
	  "<TD>$sp</TD>\n";

	# Inode
	print "  <TD><IMG BORDER=\"0\" ".
	  "SRC=\"pict/file_h_meta_link.jpg\" ".
	  "WIDTH=\"41\" ".
	  "ALT=\"Meta\">".
	  "</TD>\n".
	  "<TD>$sp</TD>\n";

	if (scalar (@out) == 0) {
		print "</TABLE>\n<CENTER>None</CENTER>\n";
		return 0;
	}

	my $row = 0;
	foreach $_ (@out) {

		if (/^([\?dfcbrlsw-])\/([\?dfcbrlsw-])\s*(\*?)\s*($REG_INODE)(\(realloc\))?:\t(.+?)\t($REG_DATE)\t($REG_DATE)\t($REG_DATE)\t(\d+)\t(\d+)\t(\d+)$/o) {

			# We have to remove the / from the beginning of the file name so
			# save all values so they aren't lost
			my $dt = $1;
			my $it = $2;
			my $d = $3;
			my $i = $4;
			my $r = 0;
			$r = 1 if (defined $5);
			my $n = $6;
			my $m = $7;
			my $a = $8;
			my $c = $9;
			my $s = $10;
			my $g = $11; 
			my $u = $12;

			if ($n =~ /^\/(.*)/) {
				$n = $1;
			}
			my $enc_n = url_encode($n);
			my $iurl="$PROGNAME?func=$INO_CONT&$baseargs&inode=$i";

			my $i_int = $i;
			$i_int = $1 if ($i =~ /(\d+)-\d+-\d+/);

			if (($row % 2) == 0) {
				print "<TR VALIGN=\"TOP\" BGCOLOR=\"$BACK_COLOR\">\n";
			} else {
				print "<TR VALIGN=\"TOP\" BGCOLOR=\"$BACK_COLOR_TABLE\">\n";
			}

			print "<TD ALIGN=\"CENTER\"><FONT COLOR=\"$DEL_COLOR[$r]\">".
			  "$dt&nbsp;/&nbsp;$it</TD>".
			  "<TD>$sp</TD>\n";

			if ($it eq 'd') {
				my $url="$PROGNAME?func=$FIL_LIST&$baseargs&inode=$i".
					"&sort=$sort&dir=$enc_n";

				print "<TD>";
				if ($i_int >= $first_inode{$ftype}) {
					print "<A HREF=\"$url\" target=\"_self\">";
				} 
				print "<FONT COLOR=\"$DEL_COLOR[$r]\"><TT>".
				  "$args{'mnt'}$n</TT></TD>".
				  "<TD>$sp</TD>\n";
			}
			else {
				my $url="$PROGNAME?func=$FIL_CMENU_FR&$baseargs&inode=$i".
					"&sort=$sort&dir=$enc_n";
			
				print "<TD>";
				if (($i_int >= $first_inode{$ftype}) && ($it eq 'r')) {
					print "<A HREF=\"$url\" target=\"content\">";
				} 
				print "<FONT COLOR=\"$DEL_COLOR[$r]\"><TT>".
				  "$args{'mnt'}$n</TT></TD>".
				  "<TD>$sp</TD>\n";
			}


			$m = "$1&nbsp;$2"  
			  if ($m =~ /($REG_DAY\s+$REG_TIME)\s+($REG_ZONE2)/o);
			$a = "$1&nbsp;$2"  
			  if ($a =~ /($REG_DAY\s+$REG_TIME)\s+($REG_ZONE2)/o);
			$c = "$1&nbsp;$2"  
			  if ($c =~ /($REG_DAY\s+$REG_TIME)\s+($REG_ZONE2)/o);

			print "<TD><FONT COLOR=\"$DEL_COLOR[$r]\">$m</TD>".
			  "<TD>$sp</TD>\n".
			  "<TD><FONT COLOR=\"$DEL_COLOR[$r]\">$a</TD>".
			  "<TD>$sp</TD>\n".
			  "<TD><FONT COLOR=\"$DEL_COLOR[$r]\">$c</TD>".
			  "<TD>$sp</TD>\n".
			  "<TD><FONT COLOR=\"$DEL_COLOR[$r]\">$s</TD>".
			  "<TD>$sp</TD>\n".
			  "<TD><FONT COLOR=\"$DEL_COLOR[$r]\">$g</TD>".
			  "<TD>$sp</TD>\n".
			  "<TD><FONT COLOR=\"$DEL_COLOR[$r]\">$u</TD>".
			  "<TD>$sp</TD>\n";

			print "<TD>";
			if ($i_int >= $first_inode{$ftype}) {
				print "<A HREF=\"$iurl\" target=\"content\">";
			}
			print "<FONT COLOR=\"$DEL_COLOR[$r]\">$i</A>";
			print " (realloc)" if $r;
			print "</TD></TR>\n";
		}
		else {
			print "Error parsing string: $_\n<BR>";
		}

		$row++;
	}
	print "</TABLE>\n";
};


#
# Display the actual content here
#
# NOTE: This has a media type of raw text
#
$funcs[$FIL_CONT] = sub {
	check_inode('inode'); check_dir(); check_sort(); 

	print_text_header();
	print "\n";

	my $sort = get_sort();
	my $inode = get_inode('inode');
	my $img = get_img('img');
	my $ftype = get_ftype();

	my $fname = "$args{'mnt'}$args{'dir'}";

	if ($sort == $FIL_SORT_ASC) {
		log_host_inv ("$args{'img'}: Viewing $fname ($inode) as ASCII");

		my @out = `\'${TASKDIR}icat\' -f $ftype -H \'$img\' $inode`;
		print "Contents Of File: $fname\n\n\n\n";
		print_output (@out);
	} elsif ($sort == $FIL_SORT_STR) {
		log_host_inv ("$args{'img'}: Viewing $fname ($inode) as strings");

		my @out = `\'${TASKDIR}icat\' -f $ftype -H \'$img\' $inode | \'$STRINGS_EXE\' -a`;
		print "String Contents Of File: $fname\n\n\n\n";
		print_output (@out);
	}

	return 0;
};

# Export the contents of a file
$funcs[$FIL_SAVE] = sub {
	check_inode('inode'); check_dir(); 


	my $inode = get_inode('inode');
	my $img = get_img('img');
	my $ftype = get_ftype();
	my $fname = "$args{'mnt'}$args{'dir'}";
	
	log_host_inv ("$args{'img'}: Saving contents of $fname ($inode)");

	my @out = `\'${TASKDIR}icat\'  -f $ftype \'$img\' $inode`;


	print_oct_header();

	# We can't trust the mnt and dir values (since there 
	# could be bad ASCII values, so only allow basic chars into name
	$fname =~ tr/a-zA-Z0-9\_\-\@\,/\./c;
	$fname = $1 if ($fname =~ /^\.(.*)$/); 

	print "Content-Disposition: inline; ".
	  "filename=${args{'img'}}-${fname}.raw;\n\n";

	print @out;

	# we exit instead of return so that we don't get two \n\n at the end
	exit(0);
};




# Display a report for a file
# This is intended to have its own window
#
$funcs[$FIL_REP] = sub {
	check_inode('inode'); check_dir(); check_sort();

	print_text_header();

	my $sort = get_sort();
	my $img = get_img('img');
	my $inode = get_inode('inode');
	my $ftype = get_ftype();
	my $type;
	my $fname = "$args{'mnt'}$args{'dir'}";


	# We can't trust the mnt and dir values (since there 
	# could be bad ASCII values, so only allow basic chars into name
	$fname =~ tr/a-zA-Z0-9\_\-\@\,/\./c;
	$fname = $1 if ($fname =~ /^\.+(.*)$/); 
	$fname = $1 if ($fname =~ /^(.*?)\.+$/); 

	print "Content-Disposition: inline; ".
	  "filename=${args{'img'}}-${fname}.";

	$fname = "$args{'mnt'}$args{'dir'}";
	if ($sort == $FIL_SORT_ASC) {
		log_host_inv ("$args{'img'}: Generating ASCII report for $fname ($inode)");
		print "arpt;\n\n";
		$type = "ascii";
	}elsif ($sort == $FIL_SORT_STR) {
		log_host_inv ("$args{'img'}: Generating strings report for $fname ($inode)");
		print "srpt;\n\n";
		$type = "string";
	} else {
		print "\n\ninvalid sort value";
		return 1;
	}


	# NOTE: There is a space in the beginning of the separator lines in
	# order to make clear@stamper.itconsult.co.uk time stamping happy
	# I think it confuses the lines that begin at the lhs with PGP 
	# headers and will remove the second line.
	#
	print "           Autopsy $type Report (ver $VER)\n\n".
		  "-" x 62 ."\n".
		"File: $fname\n";

	my $md5 = `\'${TASKDIR}icat\' -f $ftype -H \'$img\' $inode | \'${TASKDIR}md5\'`;
	chomp $md5;
	print "MD5 of file: $md5\n";
	if ($sort == $FIL_SORT_STR) {
		$md5 = `\'${TASKDIR}icat\' -f $ftype -H \'$img\' $inode | \'$STRINGS_EXE\' -a | \'${TASKDIR}md5\'`;
		chomp $md5;
		print "MD5 of strings: $md5\n";
	}

	print "Image: $img\n";
	print "Image Type: $ftype\n";

	my $date = localtime();
	print "Date Generated: $date\n".
		"Investigator: $args{'inv'}\n".
		"-" x 62 ."\n";

	foreach $_ (`\'${TASKDIR}istat\' -f $ftype -z \'$tz\' -s $ts \'$img\' $inode`) {
        print "$_";
	}

	my $file_type = 
	  `\'${TASKDIR}icat\' -f $ftype \'$img\' $inode | \'${TASKDIR}file\' -z -b -`;
	print "\nFile Type: $file_type";

	print "\n"."-" x 62 ."\n";

	if ($sort == $FIL_SORT_ASC) {
		print_output (`\'${TASKDIR}icat\' -f $ftype -H \'$img\' $inode`);
	} elsif ($sort == $FIL_SORT_STR) {
		print_output (`\'${TASKDIR}icat\' -f $ftype -H \'$img\' $inode | \'$STRINGS_EXE\' -a`);
	}

	return 0;
};


# Generate the MD5 value for every file in a given directory and save
# them to a text file
$funcs[$FIL_MD5] = sub {
	check_inode('inode'); check_dir();

	print_text_header();

	my $img = get_img('img');
	my $inode = get_inode('inode');
	my $ftype = get_ftype();
	my $fname = "$args{'mnt'}$args{'dir'}";
	$fname = 'root' if ($fname eq '/');

	# We can't trust the mnt and dir values (since there 
	# could be bad ASCII values, so only allow basic chars into name
	$fname =~ tr/a-zA-Z0-9\_\-\@\,/\./c;

	# remove .'s at beginning and end
	$fname = $1 if ($fname =~ /^\.+(.*)$/); 
	$fname = $1 if ($fname =~ /^(.*?)\.+$/); 
	
	print "Content-Disposition: inline; ".
	  "filename=$fname.md5;\n\n";

	$fname = "$args{'mnt'}$args{'dir'}";

	my @out = `\'${TASKDIR}fls\' -f $ftype -Fu \'$img\' $inode`;

	print "MD5 Values for files in $fname ($args{'img'})\n\n";

	foreach $_ (@out) {
		# area for allocated files
		if ((/r\/[\w\-]\s+([\d\-]+):\s+(.*)$/) ||
		  (/-\/r\s+([\d\-]+):\s+(.*)$/)) {
			my $in = $1;
			my $name = $2;

			my $md5out = `\'${TASKDIR}icat\' -f $ftype \'$img\' $in | \'${TASKDIR}md5\'`;
			chomp $md5out;
			print "$md5out\t$name\n";
		}
		elsif (/[\w\-]\/[\w\-]\s+([\d\-]+):\s+(.*)$/) {
        # ignore, non-file types such as sockets or symlinks that do not have
        # MD5 values that make sense
		}
		# Hmmmm
		else {
			print "Error parsing string: $_\n";
		}
	}

};


################# BLOCKS ##########################

# Generate the 2 frames for block browsing
$funcs[$BLK_MAIN] = sub {

	print_html_header_frameset("Data Browse on $args{'img'}");

	print "<FRAMESET COLS=\"20%,80%\">\n";

	# Data: Listings
	print "<FRAME SRC=\"$PROGNAME?func=$BLK_ENT&$baseargs".
	  "&block=$enc_args{'block'}\">\n";

	# Data Contents
	if (exists $args{'block'}) {
		my $len = get_len();

		print "<FRAME SRC=\"$PROGNAME?func=$BLK_CMENU_FR&".
		  "block=$enc_args{'block'}&$baseargs&len=$len\" ".
		  "NAME=\"content\">\n</FRAMESET>\n";
	} 
	else {
		print "<FRAME SRC=\"$PROGNAME?func=$BLANK&$baseargs\" ".
		  "NAME=\"content\">\n</FRAMESET>\n";
	}

	return 0;
};

# Frame to enter the data into
$funcs[$BLK_ENT] = sub {

	print_html_header("");

	my $ftype = get_ftype();

	print  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" ".
	  "TARGET=\"content\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$BLK_CMENU_FR\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
	  make_hidden().

	# Address
	  "<B>$addr_unit{$ftype} Number:</B><BR>&nbsp;&nbsp;&nbsp;&nbsp;".
	  "<INPUT TYPE=\"text\" NAME=\"block\" SIZE=12 MAXLENGTH=12";
	print " VALUE=\"$enc_args{'block'}\"" if (exists $args{'block'});
	print ">\n";

	# Number of units
	print "<P><B>Number of ${addr_unit{$ftype}}s:</B>".
	  "<BR>&nbsp;&nbsp;&nbsp;&nbsp;".
	  "<INPUT TYPE=\"text\" NAME=\"len\" VALUE=\"1\" SIZE=6 MAXLENGTH=6>\n";

	# dls images do not get to select this
	if ($ftype ne 'dls') {
	print 
	  "<P><B>Address Type:</B><BR>&nbsp;&nbsp;&nbsp;&nbsp;".
	  "<SELECT NAME=\"btype\" SIZE=1>\n".
	  "<OPTION VALUE=\"$BTYPE_DD\" SELECTED>Regular (dd)</OPTION>\n".
	  "<OPTION VALUE=\"$BTYPE_DLS\">Unallocated (dls)</OPTION>\n".
	  "</SELECT>\n";
	}
	else {
	  print "<INPUT TYPE=\"hidden\" NAME=\"btype\" VALUE=\"$BTYPE_DD\">\n";
	}


	# Lazarus
	print "<P><B>Lazarus Addr:</B> ".
	  "<INPUT TYPE=\"checkbox\" NAME=\"btype2\">\n".
	  "<P><INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".
	  "ALT=\"Ok\" BORDER=\"0\">\n".
	  "</FORM>\n";

	print "<P>".
	  "<A HREF=\"$PROGNAME?func=$BLK_DLS&$baseargs\" TARGET=\"content\">".
	  "<IMG SRC=\"pict/but_alloc_list.jpg\" BORDER=\"0\" ALT=\"Allocation List\">".
	  "</A><BR>\n" unless ($ftype eq 'dls');

    if ( ($ftype ne 'dls') && (exists $img2dls{$args{'img'}}) ) {
    print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"_top\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$MAIN_FR\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"mode\" VALUE=\"$BLK_MAIN\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$img2dls{$args{'img'}}\">\n".
      make_hidden().
      "<P><INPUT TYPE=\"IMAGE\" SRC=\"pict/srch_b_lun.jpg\" ".
      "ALT=\"Load Unallocated Image\" BORDER=\"0\">\n<BR></FORM>\n";
    }

    elsif ( ($ftype eq 'dls') && (exists $mod2img{$args{'img'}}) ) {
    print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"_top\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$MAIN_FR\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"mode\" VALUE=\"$BLK_MAIN\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$mod2img{$args{'img'}}\">\n".
      make_hidden().
      "<P><INPUT TYPE=\"IMAGE\" SRC=\"pict/srch_b_lorig.jpg\" ".
      "ALT=\"Load Original Image\" BORDER=\"0\">\n<BR></FORM>\n";
    }


	return 0;
};

# generate frame for block content
$funcs[$BLK_CMENU_FR] = sub {
	check_block();

	print_html_header_frameset("");

	my $sort = $BLK_SORT_ASC;
	$sort = $1 if ((exists $args{'sort'}) && ($args{'sort'} =~ /^(\d+)$/));

	my $len = get_len();

	my $blk;

	my $ifind = get_ifind();

	# off is 1 if a lazarus block number as they are off by one
	my $off = 0;
	$off = -1 if (exists $args{'btype2'});

	# Do we need to convert from dls value to dd value ? 
	if ((exists $args{'btype'}) && ($args{'btype'} == $BTYPE_DLS)) {

		my $img = get_img('img');
		my $b = get_block() + $off;
		my $ftype = get_ftype();

		$blk = `\'${TASKDIR}dcalc\' -f $ftype -u $b \'$img\'`;
		if ($blk !~ /^\d+$/) {
			print "$blk\n";
			return 1;
		}
	}
	else {
		$blk = get_block() + $off;
	}

	print "<FRAMESET ROWS=\"25%,75%\">\n".
	  "<FRAME SRC=\"$PROGNAME?func=$BLK_CMENU&$baseargs".
	  "&block=$blk&sort=$sort&len=$len&ifind=$ifind\">\n".
	  "<FRAME SRC=\"$PROGNAME?func=$BLK_CONT&$baseargs".
	  "&block=$blk&sort=$sort&len=$len\" NAME=\"cont2\">\n".
	  "</FRAMESET>";

	return 0;
};

sub print_ifind {
    my $block = get_block();

    my $img = get_img('img');
    my $ftype = get_ftype();

	log_host_inv ("$args{'img'}: Finding $meta_str{$ftype} for data unit $block");

    my $inode = `\'${TASKDIR}ifind\' -f $ftype -d $block \'$img\'`;
      
    if ($inode =~ /^($REG_INODE)$/o) {
        $inode = $1;
        my $tmpr = $args{'mnt'};
        print "<B>Pointed to by $meta_str{$ftype}:</B> ".
          "<A HREF=\"$PROGNAME?func=$MAIN_FR&mode=$INO_MAIN&$baseargs&".
          "inode=$inode\" TARGET=\"_blank\">$inode</A><BR>\n";
 
        print "<B>Pointed to by file:</B><BR>\n";
        foreach $_ (`\'${TASKDIR}ffind\' -f $ftype -a \'$img\' $inode`) {
            chop ;
			# Make it red if it is deleted
            if (/^(\*)\s+\/*(.*)$/) {
                print_output("<TT><FONT COLOR=\"$DEL_COLOR[0]\">$tmpr$2</FONT></TT> (deleted)<BR>\n");
			# If it starts with a '/' then it must be a file
            } elsif (/^\/(.*)$/) {
                print_output("<TT>$tmpr$1</TT><BR>\n");
			# this must be an error
            } else {
                print_output("$_<BR>\n");
            }
        }
    }
    else {
        print "$inode\n";
    }
}



# Generate index for block content
$funcs[$BLK_CMENU] = sub {
	check_block(); 

	print_html_header("");

	my $block = get_block();
	my $prev = $block - 1;
	my $next = $block + 1;

	my $sort = get_sort();
	my $ftype = get_ftype();
	my $img = get_img('img');
	my $ifind = get_ifind();

	my $len = get_len();
	my $bs = get_unitsize();
	my $len_str = $bs * $len;

	print "<CENTER><FONT SIZE=3>";
	my $url = "$PROGNAME?func=$BLK_CMENU_FR&$baseargs&sort=$sort&len=$len".
	  "&ifind=$ifind";

	# Next and Previous pointers
	print "<TABLE CELLSPACING=\"0\" CELLPADDING=\"2\">\n".
	  "<TR>\n";


	# Previous
	if ($prev < $first_addr{$ftype}) {
		print "<TD ALIGN=\"right\">&nbsp;</TD>\n";
	}
	else {
		print "<TD ALIGN=\"right\">".
		  "<A HREF=\"$url&block=$prev\" TARGET=\"_parent\">\n".
		  "<IMG SRC=\"pict/but_prev.jpg\" ALT=\"previous\" ".
		  "WIDTH=\"89\" BORDER=\"0\"></A></TD>\n";
	}

	# Next
	print "<TD ALIGN=\"left\"><A HREF=\"$url&block=$next\"".
	  " TARGET=\"_parent\">".
	  "<IMG SRC=\"pict/but_next.jpg\" ALT=\"next\" ".
	  "WIDTH=\"89\" BORDER=\"0\"></A></TD>\n</TR>\n";

	print
	  "<TR><TD ALIGN=\"right\"><A HREF=\"$PROGNAME?func=$BLK_SAVE&$baseargs&".
	  "block=$block&len=$len\">".
	  "<IMG SRC=\"pict/but_export.jpg\" BORDER=\"0\" ALT=\"Export\"></A></TD>\n";

	if ($USE_NOTES == 1) {
		print 
		  "<TD ALIGN=\"left\">".
		  "<A HREF=\"$PROGNAME?func=$NOTES_ENT&$baseargs&block=$block&len=$len\" ".
		  "TARGET=\"_blank\">".
		  "<IMG SRC=\"pict/but_addnote.jpg\" BORDER=\"0\" ".
		  "WIDTH=\"89\" ALT=\"Add Note\"></A></TD>\n";
	}
	else {
		print "<TD ALIGN=\"left\">&nbsp;</TD>\n";
	}

	print "</TR></TABLE>\n";

	# Display formats
	print "<TABLE CELLSPACING=\"0\" CELLPADDING=\"2\">\n".
	  "<TR><TD>ASCII (";
	if ($sort == $BLK_SORT_ASC) {
		print "display - ";
	} else {
		print "<A HREF=\"$PROGNAME?func=$BLK_CMENU_FR&$baseargs&".
		  "sort=$BLK_SORT_ASC&block=$block&len=$len\" TARGET=\"_parent\">".
		  "display</A> - \n";
	}

	print "<A HREF=\"$PROGNAME?func=$BLK_REP&$baseargs&sort=$BLK_SORT_ASC".
	  "&block=$block&len=$len\" TARGET=\"_blank\">report</A>)</TD>\n".
	  "<TD>*</TD>\n";

	print "<TD>Hex (";
	if ($sort == $BLK_SORT_HEX) {
		print "display - ";
	} else {
		print "<A HREF=\"$PROGNAME?func=$BLK_CMENU_FR&$baseargs&".
		  "sort=$BLK_SORT_HEX&block=$block&len=$len\" TARGET=\"_parent\">".
		  "display</A> - \n";
	}

	print "<A HREF=\"$PROGNAME?func=$BLK_REP&$baseargs&sort=$BLK_SORT_HEX".
	  "&block=$block&len=$len\" TARGET=\"_blank\">report</A>)</TD>\n".
	  "<TD>*</TD>\n";

	print "<TD>Strings (";
	if ($sort == $BLK_SORT_STR) {
		print "display - ";
	} else {
		print "<A HREF=\"$PROGNAME?func=$BLK_CMENU_FR&$baseargs&".
		  "sort=$BLK_SORT_STR&block=$block&len=$len\" TARGET=\"_parent\">".
		  "display</A> - \n";
	}

	print "<A HREF=\"$PROGNAME?func=$BLK_REP&$baseargs&sort=$BLK_SORT_STR".
	  "&block=$block&len=$len\" TARGET=\"_blank\">report</A>)</TD>\n".
	  "</TR></TABLE>\n";

	# Special case for 'dls', else print the allocation status
	if ($ftype ne 'dls') {
		my $file_type = 
		  `\'${TASKDIR}dcat\' -f $ftype \'$img\' $block | \'${TASKDIR}file\' -z -b -`;

		print "<B>File Type:</B> $file_type<BR></CENTER>\n";

		my @out = `\'${TASKDIR}dstat\' -f $ftype \'$img\' $block`;
		if (scalar @out == 0) {
			print "Invalid $addr_unit{$ftype} address<BR>\n";
			return;
		}
		print "<B>$addr_unit{$ftype}</B> $block<BR>\n";
		foreach $_ (@out) {
			if ($_ =~ /((Not )?Allocated)/) {
				print "<FONT COLOR=\"$DEL_COLOR[0]\">" if (defined $2);
				print "<B>$1</B><BR>";
				print "</FONT>" if (defined $2);
			}
			elsif ($_ =~ /Group: (\d+)/) {
				print "<B>Group:</B> $1<BR>\n";
			}
		} 


		# Make ifind an option
		$url = "$PROGNAME?func=$BLK_CMENU&$baseargs&sort=$sort&len=$len&".
		  "block=$block";
		if ($ifind == 0) {
			print "<A HREF=\"$url&ifind=1\">Find Meta Data Address</A><BR>\n";
		} else {
			print "<A HREF=\"$url&ifind=0\">Hide Meta Data Address</A><BR>\n";
			print_ifind();
		}
	} else {

		print "</CENTER>\n";

		if (exists $mod2img{$args{'img'}}) {
			print "<A HREF=\"$PROGNAME?func=$BLK_CMENU_FR&".
			  "${baseargs_noimg}".
			  "mnt=&img=$mod2img{$args{'img'}}&".
			  "block=$block&sort=$sort&len=$len&btype=$BTYPE_DLS\" ".
			  "TARGET=\"_parent\">View Original</A><BR>\n";
		}
	}

	return 0;
};

#Display actual block content
$funcs[$BLK_CONT] = sub {
	check_block(); check_sort();

	print_text_header();
	print "\n";

	my $sort = get_sort();
	my $block = get_block();
	my $img = get_img('img');
	my $ftype = get_ftype();

	my $len = get_len();
	my $bs = get_unitsize();
	my $len_str = $bs * $len;

	my $str = "Contents of $addr_unit{$ftype} $block ($len_str bytes) in $args{'img'}\n\n\n";

	my $log_str = "contents of $addr_unit{$ftype} $block ($len_str bytes)";

	if ($sort == $BLK_SORT_HEX) {
		print "Hex ".$str;
		log_host_inv ("$args{'img'}: Displaying Hex $log_str");
		print `\'${TASKDIR}dcat\' -f $ftype -h \'$img\' $block $len_str`;
	} 
	elsif ($sort == $BLK_SORT_ASC) {
		print "ASCII ".$str;
		log_host_inv ("$args{'img'}: Displaying ASCII $log_str");
		print `\'${TASKDIR}dcat\' -f $ftype -a \'$img\' $block $len_str`;
	}
	elsif ($sort == $BLK_SORT_STR) {
		print "String ".$str;
		log_host_inv ("$args{'img'}: Displaying string $log_str");
		print `\'${TASKDIR}dcat\' -f $ftype \'$img\' $block $len_str | \'$STRINGS_EXE\' -a`;
	}

	return 0;
};

$funcs[$BLK_REP] = sub {
	check_block(); check_sort();

	print_text_header();

	my $sort = get_sort();
	my $img = get_img('img');
	my $block = get_block();
	my $ftype = get_ftype();
	my $len = get_len();
	my $type;

	my $bs = get_unitsize();
	my $len_str = $len * $bs;


	print "Content-Disposition: inline; ".
	  "filename=$args{'img'}-$addr_unit{$ftype}$args{'block'}.";

	if ($sort == $BLK_SORT_ASC) {
		print "arpt;\n\n";
		log_host_inv ("$args{'img'}: Generating ASCII report on data unit $block");
		$type = "ascii";
	} elsif ($sort == $BLK_SORT_STR) {
		print "srpt;\n\n";
		log_host_inv ("$args{'img'}: Generating strings report on data unit $block");
		$type = "string";
	} elsif ($sort == $BLK_SORT_HEX) {
		print "hrpt;\n\n";
		log_host_inv ("$args{'img'}: Generating hex report on data unit $block");
		$type = "hex";
	} else {
		print "\n\n";
		print "invalid sort value";
		return 1;
	}



	print "           Autopsy $type $addr_unit{$ftype} Report (ver $VER)\n\n".
	  "-" x 62 ."\n";

	

	if ($ftype ne 'dls') {
	  
		print "$addr_unit{$ftype}: $args{'block'}\n";
		print "Length: $len_str bytes\n";

		my $inode = `\'${TASKDIR}ifind\' -f $ftype -d $block \'$img\'`;
		if ($inode =~ /^($REG_INODE)$/o) {
			my $tmpi = $1;
			print "Pointed to by $meta_str{$ftype}: $tmpi\n";

			my $tmpr = $args{'mnt'};
			print "Pointed to by files:\n";
			foreach $_ (`\'${TASKDIR}ffind\' -f $ftype -a \'$img\' $tmpi`) {
				chop ;
				if (/^(\*)\s+\/*(.*)$/) {
					print_output("  $tmpr$2 (deleted)\n");
				} elsif (/^\/(.*)$/) {
					print_output("  $tmpr$1\n");
				} else {
					print_output("  $_\n");
				}
			}
		} else {
			print "Not allocated to any meta data structures\n";
		}
	} # not dls
	else {
		print "$args{'block'}\n";
		print "Length: $len_str bytes\n";
	}


	my $md5 = `\'${TASKDIR}dcat\' -f $ftype \'$img\' $block $len_str | \'${TASKDIR}md5\'`;
	chop $md5;
	print "MD5 of raw $addr_unit{$ftype}: $md5\n";

	if ($sort == $BLK_SORT_HEX) {
		$md5 = `\'${TASKDIR}dcat\' -f $ftype -h \'$img\' $block $len_str | \'${TASKDIR}md5\'`;
	} elsif ($sort == $BLK_SORT_ASC) {
		$md5 = `\'${TASKDIR}dcat\' -f $ftype -a \'$img\' $block $len_str | \'${TASKDIR}md5\'`;
	} elsif ($sort == $BLK_SORT_STR) {
		$md5 = `\'${TASKDIR}dcat\' -f $ftype \'$img\' $block $len_str | \'$STRINGS_EXE\' -a | \'${TASKDIR}md5\'`;
	}

	chop $md5;
	print "MD5 of $type output: $md5\n";

	print "Image: $img\n";
	print "Image Type: $ftype\n";

	my $date = localtime();

	print "Date Generated: $date\n".
	  "Investigator: $args{'inv'}\n".
	  "-" x 62 ."\n";


	if ($sort == $BLK_SORT_HEX) {
		print_output (`\'${TASKDIR}dcat\' -f $ftype -h \'$img\' $block $len_str`);
	} 
	elsif ($sort == $BLK_SORT_ASC) {
		print_output(`\'${TASKDIR}dcat\' -f $ftype -a \'$img\' $block $len_str`);
	}
	elsif ($sort == $BLK_SORT_STR) {
		print_output(`\'${TASKDIR}dcat\' -f $ftype \'$img\' $block $len_str | \'$STRINGS_EXE\' -a`);
	}

	return 0;
};


#
# Display the block allocation list
#
$funcs[$BLK_DLS] = sub {
	print_html_header("Block Allocation List");

my $DLS_GAP = 500;

	my $img = get_img('img');
	my $ftype = get_ftype();

	my $min = 0;
	$min = get_min() if (exists $args{'min'});
	my $max = $min + $DLS_GAP - 1;

	# set fmin to the minimum for the file system
	my $fmin = $min;
	$fmin = $first_addr{$ftype} if ($min < $first_addr{$ftype});

	log_host_inv ("$args{'img'}: Block Allocation List for $min to $max");
	print "<CENTER><H2>$addr_unit{$ftype}: $min - $max</H2>";

	my $tmp;
	print "<FONT SIZE=3>\n";
	if ($min - $DLS_GAP >= 0) {
		$tmp = $min - $DLS_GAP;
		print "<A HREF=\"$PROGNAME?func=$BLK_DLS&$baseargs&min=$tmp\">".
		   "<IMG SRC=\"pict/but_prev.jpg\" ALT=\"previous\" ".
		   "WIDTH=\"89\" BORDER=\"0\"></A> ";
	}
	$tmp = $min + $DLS_GAP;
	print " <A HREF=\"$PROGNAME?func=$BLK_DLS&$baseargs&min=$tmp\">".
	  "<IMG SRC=\"pict/but_next.jpg\" ALT=\"next\" ".
	  "WIDTH=\"89\" BORDER=\"0\"></A><BR>";
	print "</FONT></CENTER>\n";

	foreach $_ (`\'${TASKDIR}dls\' -elb -f $ftype \'$img\' $fmin-$max`) {
		if (/^(\d+)\|([af])/) {
			print "<A HREF=\"$PROGNAME?func=$BLK_CMENU_FR&$baseargs&block=$1\">".
			  "$1:</A> ";
			if ($2 eq "a") {
				print "allocated<BR>\n";
			} else {
				print "<FONT COLOR=\"$DEL_COLOR[0]\">free</FONT><BR>\n";
			}
		}
	}

	print "<CENTER><FONT SIZE=3>\n";
	if ($min - $DLS_GAP >= 0) {
		$tmp = $min - $DLS_GAP;
		print "<A HREF=\"$PROGNAME?func=$BLK_DLS&$baseargs&min=$tmp\">".
		   "<IMG SRC=\"pict/but_prev.jpg\" ALT=\"previous\" ".
		   "WIDTH=\"89\" BORDER=\"0\"></A> ";
	}
	$tmp = $min + $DLS_GAP;
	print " <A HREF=\"$PROGNAME?func=$BLK_DLS&$baseargs&min=$tmp\">".
	  "<IMG SRC=\"pict/but_next.jpg\" ALT=\"next\" ".
	  "WIDTH=\"89\" BORDER=\"0\"></A><BR>";
	print "</FONT></CENTER>\n";
};

$funcs[$BLK_SAVE] = sub {
	check_block(); 

	print_oct_header();

	my $block = get_block();
	my $img = get_img('img');
	my $ftype = get_ftype();
	my $len = get_len();
	my $bs = get_unitsize();
	my $len_str = $len * $bs;

	log_host_inv ("$args{'img'}: Saving contents of data unit $block ($len_str bytes)");

	print "Content-Disposition: inline; filename=$args{'img'}".
	  "-$addr_unit{$ftype}$block.raw;\n\n";

	print `\'${TASKDIR}dcat\' -f $ftype \'$img\' $block $len_str`;

	# we exit instead of return so that we don't get two \n\n at the end
	exit(0);
};


########################### INODE ####################
$funcs[$INO_MAIN] = sub {

	print_html_header_frameset("Meta Data Browse on $args{'img'}");
	print "<FRAMESET COLS=\"20%,80%\">\n";

	# Inode Enter Location
	print "<FRAME SRC=\"$PROGNAME?func=$INO_ENT&$baseargs".
	  "&inode=$enc_args{'inode'}\">\n";

	# Inode Contents
	if (exists $enc_args{'inode'}) {
		print "<FRAME SRC=\"$PROGNAME?func=$INO_CONT&".
		  "inode=$enc_args{'inode'}&$baseargs\" ".
		  "NAME=\"content\">\n</FRAMESET>\n";
	}
	else {
		print "<FRAME SRC=\"$PROGNAME?func=$BLANK&$baseargs\" ".
		  "NAME=\"content\">\n</FRAMESET>\n";
	}

	return 0;
};

# Generate the frame to enter the data into
$funcs[$INO_ENT] = sub {
	print_html_header("");

	my $ftype = get_ftype();

	# Address
	print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"content\">\n".
	  "<B>$meta_str{$ftype} Number:</B><BR>&nbsp;&nbsp&nbsp;&nbsp;".
	  "<INPUT TYPE=\"text\" NAME=\"inode\" SIZE=12 MAXLENGTH=12";

	print " VALUE=\"$enc_args{'inode'}\"" if exists ($args{'inode'});

	print ">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$INO_CONT\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
	  make_hidden().

	# Ok Button
	  "<P><INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".
	  "ALT=\"Ok\" BORDER=\"0\"></FORM>\n";

	# Allocation List
	print "<P>".
	  "<A HREF=\"$PROGNAME?func=$INO_ILS&$baseargs\" TARGET=\"content\">".
	  "<IMG SRC=\"pict/but_alloc_list.jpg\" BORDER=\"0\" ALT=\"Allocation List\">".
	  "</A>\n";

	return 0;
};

# Display the contents of inode
$funcs[$INO_CONT] = sub {
	check_inode('inode'); 

	print_html_header("");

	my $inode = get_inode('inode');
	my $img = get_img('img');
	my $ftype = get_ftype();

	log_host_inv ("$args{'img'}: Displaying details of $meta_str{$ftype} $inode");

	my $inode_int = $inode;
	$inode_int = $1 if ($inode =~ /^(\d+)-\d+(-\d)?/);

	my $prev = $inode_int - 1;
	my $next = $inode_int + 1;

	print "<FONT SIZE=3><CENTER>\n";
	print "<A HREF=\"$PROGNAME?func=$INO_CONT&$baseargs&inode=$prev\">".
	  "<IMG SRC=\"pict/but_prev.jpg\" ALT=\"previous\" ".
	  "WIDTH=\"89\" BORDER=\"0\"></A>\n" 
	  unless ($prev < $first_inode{$ftype});
	print "<A HREF=\"$PROGNAME?func=$INO_CONT&$baseargs&inode=$next\">".
	  "<IMG SRC=\"pict/but_next.jpg\" ALT=\"next\" ".
	  "WIDTH=\"89\" BORDER=\"0\"></A>\n<BR>";

	print "<TABLE CELLSPACING=\"0\" CELLPADDING=\"2\">\n<TR>".
	  "<TD><A HREF=\"$PROGNAME?func=$INO_REP&$baseargs&inode=$inode\"".
	  " TARGET=\"_blank\">".
	  "<IMG SRC=\"pict/but_report.jpg\" ALT=\"report\" BORDER=\"0\">".
	  "</A></TD>\n".
	  "<TD><A HREF=\"$PROGNAME?func=$FIL_CMENU_FR&$baseargs&inode=$inode&".
	  "dir=$args{'img'}-inode-$inode\" TARGET=\"_blank\">".
	  "<IMG SRC=\"pict/but_view.jpg\" ALT=\"view contents\" BORDER=\"0\">".
	  "</A></TD>\n".
	  "<TD><A HREF=\"$PROGNAME?func=$INO_SAVE&$baseargs&inode=$inode&\">".
	  "<IMG SRC=\"pict/but_export.jpg\" ALT=\"export\" BORDER=\"0\">".
	  "</A></TD>";

	print 
	  "<TD><A HREF=\"$PROGNAME?func=$NOTES_ENT&$baseargs&inode=$inode&\" ".
	  "TARGET=\"_blank\">".
	  "<IMG SRC=\"pict/but_addnote.jpg\" ALT=\"Add Note\" ".
	  "WIDTH=\"89\" BORDER=\"0\">".
	  "</A></TD>" if ($USE_NOTES == 1);

	print "</TR></TABLE>\n</FONT></CENTER>\n<FONT SIZE=3>";

	my $tmpr = $args{'mnt'};



	if ($ftype =~ /fat/) {
		print "<A HREF=\"$PROGNAME?func=$INO_FFIND&$baseargs&".
		  "inode=$inode\" TARGET=\"_blank\">Find File</A><BR>";
	} else {

		print "<B>Pointed to by file:</B><BR>\n"; 

		my @out = `\'${TASKDIR}ffind\' -f $ftype -a \'$img\' $inode`;
		# An error was likely sent to stderr, so just exit
		if (scalar @out == 0) {
			print "<BR>Invalid $meta_str{$ftype} value<BR>\n";
			return;
		}
		foreach $_ (@out) {
			chop ;
			if (/^(\*)\s+\/*(.*)$/) {
				print_output("<TT><FONT COLOR=\"$DEL_COLOR[0]\">$tmpr$2</FONT></TT> (deleted)<BR>\n");
			} elsif (/^\/(.*)$/) {
				print_output("<TT>$tmpr$1</TT><BR>\n");
			} else {
				print_output("$_<BR>\n");
			}
		}
	}

	my $file_type = 
	  `\'${TASKDIR}icat\' -f $ftype \'$img\' $inode | \'${TASKDIR}file\' -z -b -`;
	print "<B>File Type:</B><BR>$file_type<BR>\n";

	# MD5 Value
	my $md5out = `\'${TASKDIR}icat\' -f $ftype \'$img\' $inode | \'${TASKDIR}md5\'`;
	chomp $md5out;
	print "<B>MD5:</B><BR><TT>$md5out</TT><BR>\n";


	# Hash Database Lookups
	if ((($NSRLDB ne "") || ($alert_db ne "") || ($exclude_db ne "")) &&
	  ($md5out =~ /^$REG_MD5$/o)) {

	    print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"_blank\">\n".
		  make_hidden().
		  "<INPUT TYPE=\"hidden\" NAME=\"md5\" VALUE=\"$md5out\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$HASH_LOOKUP\">\n".
		  "<TABLE CELLPADDING=\"2\" CELLSPACING=\"8\"><TR>\n";

		if ($NSRLDB ne "") {
	  		print "<TD ALIGN=\"left\">".
			  "<INPUT TYPE=\"checkbox\" NAME=\"hash_nsrl\" VALUE=\"1\" CHECKED>".
			  "NSRL</TD>\n";
		}
		if ($alert_db ne "") {
	  		print "<TD ALIGN=\"left\">".
			  "<INPUT TYPE=\"checkbox\" NAME=\"hash_alert\" VALUE=\"1\" CHECKED>".
			  "Alert Database</TD>\n";
		}
		if ($exclude_db ne "") {
	  		print "<TD ALIGN=\"left\">".
			  "<INPUT TYPE=\"checkbox\" NAME=\"hash_exclude\" VALUE=\"1\" CHECKED>".
			  "Exclude Database</TD>\n";
		}
		print "<TD ALIGN=\"left\"><INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".        
		  "ALT=\"Ok\" BORDER=\"0\"></TD></TR></TABLE>\n</FORM>\n";
	}


	# istat output
	print "<B>Details:</B><BR>\n";
	my $mode = 0;	# set to 1 when showing blocks
	my $force = 0;	# set to 1 if size of inode is 0 

	my @output;
	if (exists ($args{'force'})) {
		my $f = get_force();
		@output = `\'${TASKDIR}istat\' -f $ftype -z \'$tz\' -s $ts -b $f \'$img\' $inode`;
	} else {
		@output = `\'${TASKDIR}istat\' -f $ftype -z \'$tz\' -s $ts \'$img\' $inode`;
	}
	foreach $_ (@output) {
		if ($mode == 1) {
			if (/^Indirect Blocks/) {
				print "$_<BR>\n";
				next;
			}
			elsif (/^Type: (\S+) \((\d+\-\d+)\) (.*)$/) {
				print "Type: $1 (".
				  "<A HREF=\"$PROGNAME?func=$FIL_CMENU_FR&$baseargs".
				  "&inode=$inode_int-$2&dir=$args{'img'}-inode-$inode_int-$2\" ".
				  "TARGET=\"_blank\">$2</A>) $3<BR>\n";
				next;
			}

			my $blk;
			foreach $blk (split (/ /, $_)) {
				print "<A HREF=\"$PROGNAME?func=$MAIN_FR&mode=$BLK_MAIN&".
				  "$baseargs&block=$blk\" TARGET=\"_blank\">$blk</A>  ";
			}
			print "<BR>\n";
		}
		else {
			if (/^Not Allocated$/) {
				print "<FONT COLOR=\"$DEL_COLOR[0]\">$_</FONT><BR>\n";
			}
			else {
				print "$_<BR>\n";
			}
			$mode = 1 if (/^Direct Blocks|^Sectors/);
			$mode = 1 if (/^Attributes/);

			if ((/^size: (\d+)/) && ($1 == 0)) {
				$force = 1;
			}
		}
	}

	# display a text box to force X number of blocks to be displayed
	if ($force == 1)  {
	    print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  make_hidden().
		  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"inode\" VALUE=\"$inode\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$INO_CONT\">\n";

        print "Enter number of $addr_unit{$ftype}s to display: <INPUT TYPE=\"TEXT\" ".
		  "VALUE=5 NAME=\"force\" SIZE=\"3\">\n";

		print "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_force.jpg\" ".
			  "ALT=\"Force\" BORDER=\"0\"> (because the size is 0)\n</FORM>\n";
	}

};

$funcs[$INO_FFIND] = sub {

	check_inode('inode'); 

	print_html_header("Find File");

	my $inode = get_inode('inode');
	my $img = get_img('img');
	my $ftype = get_ftype();

	my $tmpr = $args{'mnt'};
	print "<B>Pointed to by file:</B><BR>\n"; 

	foreach $_ (`\'${TASKDIR}ffind\' -f $ftype -a \'$img\' $inode`) {
		chop ;
		if (/(\*)\s+\/*(.*)/) {
			print_output("<TT><FONT COLOR=\"$DEL_COLOR[0]\">$tmpr$2</FONT></TT> (deleted)<BR>\n");
		} elsif (/^\/(.*)$/) {
			print_output("<TT>$tmpr$1</TT><BR>\n");
		} else {
			print_output("$_<BR>\n");
		}
	}
};


$funcs[$INO_SAVE] = sub {
	check_inode('inode'); 

	print_oct_header();

	my $inode = get_inode('inode');
	my $img = get_img('img');
	my $ftype = get_ftype();

	log_host_inv ("$args{'img'}: Saving contents of $meta_str{$ftype} $inode");

	print "Content-Disposition: inline; filename=$args{'img'}".
	  "-inode$inode.raw;\n\n";

	print `\'${TASKDIR}icat\' -f $ftype \'$img\' $inode`;

	# exit instead of return so we don't get \n\n at the end
	exit(0);
};

$funcs[$INO_REP] = sub {
	check_inode('inode'); 

	print_text_header();

	my $inode = get_inode('inode');
	my $img = get_img('img');
	my $ftype = get_ftype();

	log_host_inv ("$args{'img'}: Generating report for $meta_str{$ftype} $inode");

	print "Content-Disposition: inline; ".
	  "filename=$args{'img'}-inode$inode.rpt;\n\n";

	print "           Autopsy $meta_str{$ftype} Report (ver $VER)\n\n".
	  "-" x 62 ."\n".
	  "$meta_str{$ftype}: $args{'inode'}\n";

	print "Pointed to by file:\n"; 
	my $tmpr = $args{'mnt'};
	foreach $_ (`\'${TASKDIR}ffind\' -f $ftype -a \'$img\' $inode`) {
		chop ;
		if (/^(\*)\s+\/*(.*)$/) {
			print_output("  $tmpr$2 (deleted)\n");
		} elsif (/^\/(.*)$/) {
			print_output("  $tmpr$1\n");
		} else {
			print_output("  $_\n");
		}
	}
	my $md5 = `\'${TASKDIR}istat\' -f $ftype -z \'$tz\' -s $ts \'$img\' $inode | \'${TASKDIR}md5\'`;
	chop $md5;
	print "MD5 of istat output: $md5\n";

	print "Image: $img\n";
	print "Image Type: $ftype\n";

	my $date = localtime();
	print "Date Generated: $date\n".
	  "Investigator: $args{'inv'}\n".
	  "-" x 62 ."\n";

	foreach $_ (`\'${TASKDIR}istat\' -f $ftype -z \'$tz\' -s $ts \'$img\' $inode`) {
        	print "$_";
	}

	my $file_type = 
	  `\'${TASKDIR}icat\' -f $ftype \'$img\' $inode | \'${TASKDIR}file\' -z -b -`;
	print "\nFile Type: $file_type";

	print "\n"."-" x 62 ."\n";

	return 0;
};


# Display the Inode Allocation Table
$funcs[$INO_ILS] = sub {
my $ILS_GAP = 500;
 
	my $ftype = get_ftype();
	my $img = get_img('img');

    my $min = 0;

	$min = get_min() if (exists $args{'min'});
    my $max = $min + $ILS_GAP - 1;  

	# Because we can not use inodes 0 and 1 for most FS, set fmin to the
	# minimum for this fs
	my $fmin = $min;
	$fmin = $first_inode{$ftype} if ($min < $first_inode{$ftype});
        
	print_html_header("$meta_str{$ftype} Allocation List $fmin -&gt $max");

	log_host_inv ("$args{'img'}: $meta_str{$ftype} Allocation List for $min to $max");

	print "<CENTER><H2>$meta_str{$ftype}: $fmin - $max</H2>";
        
	# Display next and previous links
    my $tmp;
    print "<FONT SIZE=3>\n";
    if ($min > $first_inode{$ftype}) {
        $tmp = $min - $ILS_GAP;
        print "<A HREF=\"$PROGNAME?func=$INO_ILS&$baseargs&min=$tmp\">".
           "<IMG SRC=\"pict/but_prev.jpg\" ALT=\"previous\" ".
		   "WIDTH=\"89\" BORDER=\"0\"></A> ";
    }
    $tmp = $min + $ILS_GAP;
    print " <A HREF=\"$PROGNAME?func=$INO_ILS&$baseargs&min=$tmp\">".
      "<IMG SRC=\"pict/but_next.jpg\" ALT=\"next\" ".
	  "WIDTH=\"89\" BORDER=\"0\"></A><BR>";
    print "</FONT></CENTER>\n";

	# The list
	foreach $_ (`\'${TASKDIR}ils\' -e -s $ts -f $ftype \'$img\' $fmin-$max`) {
		if (/^($REG_INODE)\|([af])\|\d+\|\d+\|\d+\|\d+\|\d+\|/o) {
			print "<A HREF=\"$PROGNAME?func=$INO_CONT&$baseargs&inode=$1\">".
			  "$1:</A> ";
			if ($2 eq "a") {
				print "allocated<BR>\n";
			} else {
				print "<FONT COLOR=\"$DEL_COLOR[0]\">free</FONT><BR>\n";
			}
		}
	}

	# Display next and previous links
    print "<CENTER><FONT SIZE=3>\n";
    if ($min > $first_inode{$ftype}) {
        $tmp = $min - $ILS_GAP;
        print "<A HREF=\"$PROGNAME?func=$INO_ILS&$baseargs&min=$tmp\">".
           "<IMG SRC=\"pict/but_prev.jpg\" ALT=\"previous\" ".
		   "WIDTH=\"89\" BORDER=\"0\"></A> ";
    }
    $tmp = $min + $ILS_GAP;
    print " <A HREF=\"$PROGNAME?func=$INO_ILS&$baseargs&min=$tmp\">".
      "<IMG SRC=\"pict/but_next.jpg\" ALT=\"next\" ".
	  "WIDTH=\"89\" BORDER=\"0\"></A><BR>";
    print "</FONT></CENTER>\n";

};

############ SEARCHING ##################


my $CASE_INSENS = 1;
my $CASE_SENS = 0;

my $REG_EXP = 1;
my $STRING = 0;

# Form to enter search data
$funcs[$SRCH_ENT] = sub {
	print_html_header("Search on $args{'img'}");

	print "<CENTER><H3>Keyword Search on <TT>$args{'img'}</TT></H3>\n";

	print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
	  "Enter String: <INPUT TYPE=\"text\" NAME=\"str\"><BR><BR>\n".
	  make_hidden().
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$SRCH_RMAIN\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
	  "<INPUT TYPE=\"checkbox\" NAME=\"srch_case\" VALUE=\"$CASE_INSENS\">".
	  "Case Insensitive\n".
	  "<INPUT TYPE=\"checkbox\" NAME=\"regexp\" VALUE=\"$REG_EXP\">".
	  "Regular Expression<BR><BR>\n".
	  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/srch_b_srch.jpg\" ".
	  "ALT=\"Search\" BORDER=\"0\">\n</FORM>\n";

	my $ftype = get_ftype();


	# If we are a non-dls image and one exists - make a link
	if ( ($ftype ne 'dls') && (exists $img2dls{$args{'img'}}) ) {
	print 
	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"_top\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$MAIN_FR\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"mode\" VALUE=\"$SRCH_MAIN\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$img2dls{$args{'img'}}\">\n".
	  make_hidden().
	  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/srch_b_lun.jpg\" ".
	  "ALT=\"Load Unallocated Image\" BORDER=\"0\">\n<BR></FORM>\n";
	}

	# If we are a dls and the original exists - make a link
	elsif ( ($ftype eq 'dls') && (exists $mod2img{$args{'img'}}) ) {
	print 
	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"_top\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$MAIN_FR\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"mode\" VALUE=\"$SRCH_MAIN\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$mod2img{$args{'img'}}\">\n".
	  make_hidden().
	  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/srch_b_lorig.jpg\" ". 
	  "ALT=\"Load Original Image\" BORDER=\"0\">\n<BR></FORM>\n";
	}

	print "<A HREF=\"help/grep.html\" TARGET=\"_new\">grep cheat sheet</A>\n".
	  "<BR><BR>\n";

	print "<P>(Note that strings that cross ".
	  "<U>non-consecutive</U> $addr_unit{$ftype}s in a file will not be found)\n";


	# Section for previous searches
	my $srch_name = get_srch_file(0);
	if (-e $srch_name) {
		print "<HR><H3>Previous Searches</H3>\n".
		  "<TABLE WIDTH=600>\n";
		my $row_idx = 0;

		# Cycle through the files
		for (my $srch_idx = 0; ;$srch_idx++) {

			$srch_name = get_srch_file($srch_idx);
			
			last unless (-e $srch_name);

			# Open the file to get the string and count
			unless (open (SRCH, "$srch_name")) {
				print "Error opening search file: $srch_name\n";
				return 1;
			}
			my $prev_str = "";
			my $prev_cnt = 0;
			while (<SRCH>) {
				unless (/^(\d+)\|(.*?)?\|(.*)$/) {
					print "Error pasing header of search file: $srch_name\n";
					return 1;
				}
				$prev_cnt = $1;
				$prev_str = $3;
				if (length ($prev_str) > 32) {
					$prev_str = substr($prev_str, 0, 32);
					$prev_str .= "...";
				}

				last;
			}
			close(SRCH);

			print "<TR>\n" if ($row_idx == 0); 

			print "  <TD ALIGN=CENTER WIDTH=150>\n".
		  	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$SRCH_RMAIN\">\n".
		  	  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
		  	  "<INPUT TYPE=\"hidden\" NAME=\"srchidx\" VALUE=\"$srch_idx\">\n".
			  make_hidden();

			print "<INPUT TYPE=\"SUBMIT\" VALUE=\"$prev_str ($prev_cnt)\">".
			  "<BR></FORM>\n";

			if ($row_idx == 3) {
				print "</TR>\n";
				$row_idx = 0;
			} else {
				$row_idx++;
			}
		}
		print "</TABLE>\n";
	}

	# Predefined expressions from search.pl
	print "<HR><H3>Predefined Searches</H3>\n";
	print "<TABLE WIDTH=600>\n";
	my $row_idx = 0;
	my $r;
	foreach $r (keys %auto_srch) {

		$auto_srch_reg{$r} = 0 unless (defined $auto_srch_reg{$r});
		$auto_srch_csense{$r} = 1 unless (defined $auto_srch_csense{$r});

		print "<TR>\n" if ($row_idx == 0); 

		print "  <TD ALIGN=CENTER WIDTH=150>\n".
	  	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
	  	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$SRCH_RMAIN\">\n".
	  	  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
	  	  "<INPUT TYPE=\"hidden\" NAME=\"str\" VALUE=\"$auto_srch{$r}\">\n".
		  make_hidden();

		if ($auto_srch_reg{$r} == 1) {
	  		print 
			  "<INPUT TYPE=\"hidden\" NAME=\"regexp\" VALUE=\"$REG_EXP\">\n";
		} 
		if ($auto_srch_csense{$r} == 0) {
	  		print
			  "<INPUT TYPE=\"hidden\" NAME=\"srch_case\" VALUE=\"$CASE_INSENS\">\n";
		}
	  	print "<INPUT TYPE=\"SUBMIT\" VALUE=\"$r\"><BR></FORM>\n".
		  "  </TD>\n";
		
		if ($row_idx == 3) {
			print "</TR>\n";
			$row_idx = 0;
		} else {
			$row_idx++;
		}
	}
	print "</TABLE>\n";


	# Section for Strings file and 'dls' file

	print "<HR><TABLE CELLSPACING=\"40\" CELLPADDING=\"2\">\n<TR>";

	# Strings File
	unless (defined $img2str{$args{'img'}}) {

		(my $img_dir, my $str_img) = split (/\//,$args{'img'});

		print "<TD ALIGN=\"CENTER\"><H3>Generate Strings File</H3>".
		  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  "File Name: <INPUT TYPE=\"text\" NAME=\"fname\" ".
		  "VALUE=\"$str_img.str\"><BR><BR>\n".
		  "Generate MD5? ".                      
		  "<INPUT TYPE=\"checkbox\" NAME=\"md5\" VALUE=\"1\" CHECKED><BR><BR>".
		  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$SRCH_MAKESTR\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"fname_mode\" VALUE=\"$FNAME_MODE_INIT\">\n".
		  make_hidden().
		  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/srch_b_str.jpg\" ". 
		  "ALT=\"Extract Strings\" BORDER=\"0\">\n</FORM></TD>\n";
	}

	# Unallocated Space File
	unless (($ftype eq 'dls') || (defined $img2dls{$args{'img'}})) {


		print "<TD ALIGN=\"CENTER\"><H3>Create Unallocated Data File</H3>".
		  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  "File Name: <INPUT TYPE=\"text\" NAME=\"fname\" ";
		
		(my $img_dir, my $dls_img) = split (/\//,$args{'img'});
		if ($dls_img =~ /^(.*?)\.dd$/) {
			print "VALUE=\"$1.dls\"><BR><BR>\n";
		} else {
			print "VALUE=\"${dls_img}.dls\"><BR><BR>\n";
		}

		print "Generate MD5? ".                      
		  "<INPUT TYPE=\"checkbox\" NAME=\"md5\" VALUE=\"1\" CHECKED><BR><BR>".
		  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$SRCH_MAKEDLS\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"fname_mode\" VALUE=\"$FNAME_MODE_INIT\">\n".
		  make_hidden().
		  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/srch_b_un.jpg\" ". 
		  "ALT=\"Extract Unallocated Data\" BORDER=\"0\">\n<BR></FORM>\n";
	}

	print "</TR></TABLE>\n</CENTER>\n";

	return 0;
};

# MAIN WITH RESULTS
# Page that makes frame with the results on left and data units on right
$funcs[$SRCH_RMAIN] = sub {

	# A string was given for a new search
	if (exists $args{'str'}) {
		check_str();

		print_html_header_frameset("Search on $args{'img'} for $args{'str'}");

		print "<FRAMESET COLS=\"35%,65%\">\n";

		my $srch_case = "";
		$srch_case = "&srch_case=$args{'srch_case'}" 
		  if (exists $args{'srch_case'});

		my $regexp = "";
		$regexp = "&regexp=$args{'regexp'}" 
		  if (exists $args{'regexp'});

		# Block List
		print "<FRAME SRC=\"$PROGNAME?func=$SRCH_DOSRCH&".
		  "$baseargs$srch_case$regexp&str=$enc_args{'str'}\">\n";
	}
	elsif (exists $args{'srchidx'}) {
		check_srchidx();

		print_html_header_frameset("Search on $args{'img'} for Index $args{'idx'}");

		print "<FRAMESET COLS=\"35%,65%\">\n";

		# Block List
		print "<FRAME SRC=\"$PROGNAME?func=$SRCH_READSRCH&".
		  "$baseargs&srchidx=$enc_args{'srchidx'}\">\n";
	}

	# Block Contents
	print "<FRAME SRC=\"$PROGNAME?func=$BLANK&$baseargs\" NAME=\"content\">\n".
	  "</FRAMESET>\n";

	return 0;
};



# Find an empty file to save the keyword searches to
sub find_srch_file {
    my $tmp_img = $args{'img'};
    $tmp_img =~ tr/\//\-/;

    my $out_name = "${host_dir}${DATADIR}/$tmp_img";
    my $i;
    for ($i = 0; -e "${out_name}-${i}.srch"; $i++) { }

	return "${out_name}-${i}.srch";
}

# Pass the index and get the full path of the file returned
sub get_srch_file {
	my $idx = shift;
    my $tmp_img = $args{'img'};
    $tmp_img =~ tr/\//\-/;
    return "${host_dir}${DATADIR}/$tmp_img-${idx}.srch";
}

$funcs[$SRCH_READSRCH] = sub {
	check_srchidx(); 

	print_html_header("");

	my $srch_name = get_srch_file($args{'srchidx'});
	unless (open (SRCH, "$srch_name")) {
		print "Error opening search file: $srch_name\n";
		return 1;
	}

	my @results;
	my $prev_str = "";
	my $grep_flag = "";

	while (<SRCH>) {
		if ($. == 1) {
			unless (/^(\d+)\|(.*?)?\|(.*)$/) {
				print "Error pasing header of search file: $srch_name\n";
				return 1;
			}
			$grep_flag = $2;
			$prev_str = $3;
		} else {
			push @results, "$_";
		}
	}
	close(SRCH);
	print_srch_results($prev_str, $grep_flag, \@results);

	return 0;
};


# performs actual search, saves hits to file, and calls method to print
$funcs[$SRCH_DOSRCH] = sub {
	check_str(); 

	print_html_header("");

	my $img = get_img('img');
	my $ftype = get_ftype();

	my $orig_str = get_str();
	my $grep_str = $orig_str;   # we will escape some values in the grep ver


	# Check for a search string 
	if ($orig_str eq "") {
		print "You must enter a string value to search<BR>\n";
		print "<B><A HREF=\"$PROGNAME?func=$SRCH_ENT&$baseargs\" ".
		  "TARGET=\"_parent\">New Search</A></B>\n<P>";
		return 1;
	}


	my $log = "";			# Log entry string
	my $grep_flag = "";		# Flags to pass to grep

	# Check if search is case insensitive
	my $case = 0;
	if ((exists $args{'srch_case'}) && ($args{'srch_case'} == $CASE_INSENS)) {
		$grep_flag = "-i";
		$case = 1;
		$log .= "Case Insensitive ";
	}

	# Check if search is a regular expression
	my $regexp = 0;
	if ((exists $args{'regexp'}) && ($args{'regexp'} == $REG_EXP)) {
		$grep_flag .= " -E";
		$regexp = 1;
		$log .= "Regular Expression ";
	}

	# if not a reg-exp, we need to escape some special values that
	# 'grep' will misinterpret
	else {
		$grep_str =~ s/\\/\\\\/g;	# \
		$grep_str =~ s/\./\\\./g;	# .
		$grep_str =~ s/\[/\\\[/g;	# [
		$grep_str =~ s/\^/\\\^/g;	# ^
		$grep_str =~ s/\$/\\\$/g;	# $
		$grep_str =~ s/\"/\\\"/g;	# "
		$grep_str =~ s/^\-/\\\-/;	# starting with - (mistakes for an arg)
	}


	log_host_inv ("$args{'img'}: ${log}search for $grep_str");

	# Get the addressable unit of image
	my $bs = get_unitsize();

	my @out;

	# Use the strings file if it exists
	if (defined $img2str{$args{'img'}}) {
		my $str_img = "${host_dir}/$img2str{$args{'img'}}";
		@out = `\'$GREP_EXE\' $grep_flag \'$grep_str\' \'$str_img\'`;
	}
	# Run strings on the image first and then grep that
	else {
		@out = `\'$STRINGS_EXE\' -a -t d \'$img\' | \'$GREP_EXE\' $grep_flag \'$grep_str\'`;
	} 



	my $cnt = scalar(@out);

	# $re_str is used to find the "hit" in the output
	my $re_str = $orig_str;

	# make this lowercase if we are doing case insens 
	$re_str =~ tr/[A-Z]/[a-z]/ if ($case == 1);

	my $re_str_len = length ($re_str);

	# array to pass to printing method
	my @results;

	foreach $_ (@out) {
		if (/^\s*(\d+)\s+(.+)$/)  {
			my $idx = 0;
			my $off = $1;
			my $hit_orig = $2;

			my $hit = $hit_orig;
			$hit =~ tr/[A-Z]/[a-z]/ if ($case == 1);

			my $hit_len = length ($hit);

			# I'm not sure how to find a grep re in the hit yet, so 
			# for now we do not get the exact offset
			if ($regexp) {
				my $b = int ($off / $bs);
				my $o = int ($off % $bs);

				# $hit =~ s/\n//g;
				push @results, "${b}|${o}|";
				next;
			}


			# There could be more than one keyword in the string
			# so cylcle through all of them
			while (($idx = index ($hit, $re_str, $idx)) > -1) {

				my $b = int (($off + $idx) / $bs);
				my $o = int (($off + $idx) % $bs);

				# The summary of the hit starts 5 chars before it
				my $sum_min = $idx - 5;
				$sum_min = 0 if ($sum_min < 0);

				# Goto 5 after, if there is still space
				my $sum_max = $idx + $re_str_len + 5;
				$sum_max = $hit_len if ($sum_max > $hit_len);

				my $sum_hit = substr ($hit_orig, $sum_min, $sum_max - $sum_min);
				# remove new lines
				$sum_hit =~ s/\n/ /g;

				push @results, "${b}|${o}|$sum_hit";

				# advance index to find next hit
				$idx++;
			}
		}
		elsif (/^\s*(\-\d+):?\s*(.+)$/) {
			print "ERROR: Negative byte offset ($1) Your version of ".
			  "strings likely does not support large files: $2<BR>\n";
		}
		else {
			print "Error parsing string: $_<BR>\n";
		}
	}

	# Find a file to save the results to
	my $srch_name = find_srch_file();
	unless (open(IDX, ">$srch_name")) {
		print "Error opening $srch_name\n";
		return (1);
	}

	# Print the header 
    $cnt = scalar(@results);
	print IDX "$cnt|${grep_flag}|${orig_str}\n";

	for (my $i = 0; $i < $cnt; $i++) {
		print IDX "$results[$i]\n";
	}
	close(IDX);

	print_srch_results($grep_str, $grep_flag, \@results);

	return 0;
};


# Args are search string, grep flags, and array of hits
sub print_srch_results {

	if (scalar (@_) != 3) {
		print "Missing Args for print_srch_results()\n";
		return 1;
	}

	my $grep_str = shift();
	my $grep_flag = shift();
	my @results = @{shift()};
    my $cnt = scalar(@results);

	my $ftype = get_ftype();
	my $addr_str = $addr_unit{$ftype};

	print "<B><A HREF=\"$PROGNAME?func=$SRCH_ENT&$baseargs\" ".
	  "TARGET=\"_parent\">New Search</A></B>\n<P>";

	my $grep_str_html = html_encode($grep_str);
	if ($cnt == 0) {    
		print "<B><TT>$grep_str_html</TT> was not found</B><BR>\n";
	} elsif ($cnt == 1) {
		print "<B>1 occurrence of <TT>$grep_str_html</TT> was found</B><BR>\n";
	} else {
		print "<B>$cnt occurrences of <TT>$grep_str_html</TT> were found</B><BR>\n";
	}

	print "Search Options:<BR>\n";
	if ($grep_flag =~ /\-i/) {
		print "&nbsp;&nbsp;Case Insensitive<BR>\n";
	} else {
		print "&nbsp;&nbsp;Case Sensitive<BR>\n";
	}
	if ($grep_flag =~ /\-E/) {
		print "&nbsp;&nbsp;Regular Expression<BR>\n";
	}

	print "<HR>\n";

	my $prev = -1;
	for (my $i = 0; $i < $cnt; $i++) {

		unless ($results[$i] =~ /^(\d+)\|(\d+)\|(.*)?$/) {
			print "Error parsing search array: $results[$i]\n";
			return 1;
		}

		my $blk = $1;
		my $off = $2;
		my $str = $3;

		if ($blk != $prev) {
			my $url="$PROGNAME?func=$BLK_CMENU_FR&$baseargs&block=$blk";
			
			print "<BR>\n$addr_str $blk (<A HREF=\"$url&sort=$BLK_SORT_HEX\" ". 
			  "TARGET=content>Hex</A> - ".
			  "<A HREF=\"$url&sort=$BLK_SORT_ASC\" TARGET=content>".
			  "Ascii</A>";

			print " - <A HREF=\"$PROGNAME?$baseargs&func=$BLK_CMENU_FR&".
			  "mnt=$enc_args{'mnt'}&img=$mod2img{$args{'img'}}&".
			  "btype=$BTYPE_DLS&block=$blk\" TARGET=content>Original</A>"
			  if (($ftype eq 'dls') && (exists $mod2img{$args{'img'}}));

			print ")<BR>";
			$prev = $blk;
		}

		my $occ = $i + 1;
		if ($str ne "")  {
			$str = html_encode($str);	
			print "$occ: $off (<TT>$str</TT>)<BR>\n";
		} else {
			print "$occ: $off<BR>\n";
		}
	}


	return 0;
}


# Make a strings -t d file for the image to decrease the search time
$funcs[$SRCH_MAKESTR] = sub {
	check_fname(); check_fname_mode(); 

	print_html_header("");

	my $fname = get_fname();
	my $fname_rel = get_fname_rel();
	my $mode = $args{'fname_mode'};

	if ((-e "$fname") && ($FNAME_MODE_INIT == $mode)) {
		print "File Already Exists: $fname_rel\n";

		my $hidden = 
		  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$SRCH_MAKESTR\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
		  make_hidden();

		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"md5\" VALUE=\"$args{'md5'}\">\n" 
			if (exists $args{'md5'});

		print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  "New Name: <INPUT TYPE=\"text\" NAME=\"fname\">\n".
		  "<TABLE CELLSPACING=\"30\" CELLPADDING=\"2\"><TR><TD>".
		  "$hidden".
		  "<INPUT TYPE=\"hidden\" NAME=\"fname_mode\" VALUE=\"$FNAME_MODE_INIT\">\n".
		  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_new_name.jpg\" ". 
		  "ALT=\"Use New Name\" BORDER=\"0\">\n</FORM></TD>\n";

		print "<TD><FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  "$hidden".
		  "<INPUT TYPE=\"hidden\" NAME=\"fname\" VALUE=\"$args{'fname'}\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"fname_mode\" VALUE=\"$FNAME_MODE_OVER\">\n".
		  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_replace.jpg\" ". 
		  "ALT=\"Replace\" BORDER=\"0\">\n".
		  "</FORM></TD></TR></TABLE>";

		  return 0;
	}

	my $img = get_img('img');

	print "Extracting strings from <TT>$args{'img'}</TT> and saving to ".
	  "<TT>$args{'fname'}</TT><BR><BR>\n";

	log_host_inv ("$args{'img'}: Saving ASCII strings to $fname_rel");

	print_output (`\'$STRINGS_EXE\' -a -t d \'$img\' > \'$fname\'`);

	# Verify that it worked
	unless (open (STR, "$fname")) { 
		print "Error opening $fname<BR>\n".
		  "Either an error occurred while generating the file or ".
		  "no ASCII strings exist";
		return (1);
	}

	my $sz = 0;
	while (<STR>) {
		unless (/^\s*\d+\s+\S.*$/) {
			print ("Error making strings file: $_");
			return (1);
		}
		$sz = 1;
		last;
	}

	if ($sz == 0) {
		print "Strings file has no valid entries, there could be no ASCII".
		  " strings in the original image";

		print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$SRCH_ENT\">\n".
		  make_hidden().
		  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".        
		  "ALT=\"Ok\" BORDER=\"0\">\n</FORM>";
		return (1);
	}

	close(STR);

	# append to config
	update_host_config("strings", $fname_rel, 
	  "$args{'img'}");
	print "<TT>$fname_rel</TT> added to host config file<BR><BR>";


	$img2ftype{$fname_rel} = "strings";
	$mod2img{$fname_rel} = $args{'img'};
	$img2str{$args{'img'}} = $fname_rel;

    # Calculate MD5
    if ((exists $args{'md5'}) && ($args{'md5'} == 1)) {
        print "Calculating MD5 Value<BR><BR>\n";
        my $m = int_create_wrap ($fname, $fname_rel);
        print "MD5 Value: <TT>$m</TT><BR><BR>\n";
    }

    print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$SRCH_ENT\">\n".
	  make_hidden().
	  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".        
	  "ALT=\"Ok\" BORDER=\"0\">\n</FORM>\n";
    
	return 0;
};

$funcs[$SRCH_MAKEDLS] = sub {
	check_fname(); check_fname_mode(); 

	print_html_header("");

	my $fname = get_fname();
	my $fname_rel = get_fname_rel();
	my $mode = $args{'fname_mode'};

	if ((-e "$fname") && ($FNAME_MODE_INIT == $mode)) {
		print "File Already Exists: $fname_rel\n";
		my $hidden = 
		  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$SRCH_MAKEDLS\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
		  make_hidden();

		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"md5\" VALUE=\"$args{'md5'}\">\n" 
			if (exists $args{'md5'});

		print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  "New Name: <INPUT TYPE=\"text\" NAME=\"fname\"> ".
		  "<TABLE CELLSPACING=\"30\" CELLPADDING=\"2\"><TR><TD>".
		  "$hidden".
		  "<INPUT TYPE=\"hidden\" NAME=\"fname_mode\" VALUE=\"$FNAME_MODE_INIT\">\n".
		  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_new_name.jpg\" ".               
		  "ALT=\"Use New Name\" BORDER=\"0\">\n</FORM></TD>\n";

		print "<TD><FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_replace.jpg\" ".               
		  "ALT=\"Replace\" BORDER=\"0\"><BR>\n".
		  "$hidden".
		  "<INPUT TYPE=\"hidden\" NAME=\"fname\" VALUE=\"$args{'fname'}\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"fname_mode\" VALUE=\"$FNAME_MODE_OVER\">\n".
		  "</FORM></TD></TR></FORM>";

		  return 0;
	}

	my $img = get_img('img');
	my $ftype = get_ftype();

	log_host_inv ("$args{'img'}: Saving unallocated data to $fname_rel");

	print "Extracting unallocated data from <TT>$args{'img'}</TT> and ".
	  "saving to <TT>$fname_rel</TT><BR><BR>\n";

	print_output (`\'${TASKDIR}dls\' -f $ftype \'$img\' > \'$fname\'`);


	# append to fsmorgue 
	update_host_config("dls", $fname_rel, $args{'img'}); 

	print "<TT>$fname_rel</TT> added to host config file<BR><BR>";

	$img2ftype{$fname_rel} = "dls";
	$mod2img{$fname_rel} = $args{'img'};
	$img2dls{$args{'img'}} = $fname_rel;

    # Calculate MD5
    if ((exists $args{'md5'}) && ($args{'md5'} == 1)) {
        print "Calculating MD5 Value<BR><BR>\n";
        my $m = int_create_wrap ($fname, $fname_rel);
        print "MD5 Value: <TT>$m</TT><BR><BR>\n";
    }
    

	print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$fname_rel\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$SRCH_ENT\">\n".
	  make_hidden().
	  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".               
	  "ALT=\"Ok\" BORDER=\"0\">\n</FORM>\n";

	return 0;
};



############ FILE SYSTEM ##################

$funcs[$FS_STAT] = sub {
	print_html_header("File System Status");

	log_host_inv ("$args{'img'}: Displaying file system details");

	my $img = get_img('img');
	my $ftype = get_ftype();
	my $fat = 0;
	foreach $_ (`\'${TASKDIR}fsstat\' -f $ftype  \'$img\'`) {

		# Special case for FAT
		# We will be giving hyperlinks in the FAT table dump
		if ($fat == 1) {
			# Ignore the divider
			if (/\-\-\-\-\-\-\-\-\-\-/) {
				print "$_<BR>";
				next;
			}

			if (/^((\d+)\-\d+\s+\((\d+)\)) \-\> ([\w]+)$/) {
				my $full = $1;
				my $blk = $2;
				my $len = $3;
				my $next = $4;

				# Print the tag so that other FAT entries can link to it
				print "<A NAME=\"$blk\">\n";

				print "<A HREF=\"$PROGNAME?$baseargs&func=$MAIN_FR&mode=$BLK_MAIN&".
				  "block=$blk&len=$len\" TARGET=\"_blank\">$full</A> -> ";

				if ($next eq 'EOF') {
					print "EOF<BR>\n";
				}
				else {
				  print "<A HREF=\"#$next\">$next</A><BR>\n";
				}
			}
			else {
				$fat = 0;
        		print "$_<BR>";
			}
		}
		else {
        	print "$_<BR>";
		}

		# Set the flag if we reach the FAT 
		$fat = 1 if (($ftype =~ /fat/) && ($_ =~ /FAT CONTENTS/));
	}
};


############ INTEGRITY CHECKS ##################


# Special func for printing integrity check menu
# We show any file that we have a reference for

# pass the md5 hash (from md5.txt) and then the sorted array
sub int_menu_print {
	my %md5s = %{$_[0]};
	my @sort = @{$_[1]};

	for (my $i = 0; $i <= $#sort; $i++) {

		print "<TR><TD ALIGN=\"right\"><TT><B>$sort[$i]</B></TT></TD>\n";

		# It already exists, so make verify button
		if (exists $md5s{$sort[$i]}) {
			print "<TD><TT>$md5s{$sort[$i]}</TT></TD>".
			  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"cont\">\n".
			  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$sort[$i]\">\n".
			  make_hidden().
			  "<TD><INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$INT_CHECK\">\n".
			  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/int_b_valid.jpg\" ".               
			  "ALT=\"Validate\" BORDER=\"0\">\n".
			  "</FORM></TD></TR>\n";
		}
		# Generate New button
		else {
			print "<TD>&nbsp;</TD><TD>".
			  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"cont\">\n".
			  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$sort[$i]\">\n".
			  make_hidden().
			  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$INT_CREATE\">\n".
			  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/int_b_calc.jpg\" ".               
			  "ALT=\"Calculate\" BORDER=\"0\">\n".
			  "</FORM></TD></TR>\n";
		}
	}

	return;
};


# Create a frame with two rows, one with the list of images to check
# and then the bottom actually does it.  
$funcs[$INT_LIST_FR] = sub {
	print_html_header_frameset("$args{'case'}:$args{'host'} Integrity Check");

	print "<FRAMESET ROWS=\"80%,20%\">\n";

	# Block List
	print "<FRAME SRC=\"$PROGNAME?func=$INT_LIST&$baseargs\">\n";
	print "<FRAME SRC=\"$PROGNAME?func=$BLANK\" NAME=\"cont\">\n";

	print "</FRAMESET>\n";

	return 0;
};

# Reads the MD5 file to fill in the MENU list for the integrity
# check mode
$funcs[$INT_LIST] = sub {
	print_html_header("Image Integrity Menu");

	my %md5s;
	my @dls;
	my @str;
	my @fs;
	my @body;
	my @tl;

	# Read the known values if the file exists
	if (open (FILE, "${host_dir}${IMGDIR}/$MD5_FILE")) { 
		# Read the md5 values into a hash
		while (<FILE>) {
			s/^\s+//;
			s/\s+$//;

			if (/($REG_MD5)\s+(.*)/o) {
				$md5s{"$2"} = $1;
				$md5s{"$2"} =~ tr/[a-f]/[A-F]/;
			}
			else {
				print "Error reading line $. of $MD5_FILE: $_<BR>\n";
				return 1;
			}
		}
		close (FILE);
	}

	if (open (FILE, "${host_dir}${DATADIR}/$MD5_FILE")) { 
		# Read the md5 values into a hash
		while (<FILE>) {
			s/^\s+//;
			s/\s+$//;

			if (/($REG_MD5)\s+(.*)/o) {
				$md5s{"$2"} = $1;
				$md5s{"$2"} =~ tr/[a-f]/[A-F]/;
			}
			else {
				print "Error reading line $. of $MD5_FILE: $_<BR>\n";
				return 1;
			}
		}
		close (FILE);
	}

	# sort the images into the different types
	foreach my $k (keys %img2ftype) {
		if ($img2ftype{$k} eq "dls") {
			push @dls, $k;
		} 
		elsif ($img2ftype{$k} eq "strings") {
			push @str, $k;
		} 
		elsif ($img2ftype{$k} eq "body") {
			push @body, $k;
		} 
		elsif ($img2ftype{$k} eq "timeline") {
			push @tl, $k;
		} 
		else {
			push @fs, $k;
		}
	}


	print "<CENTER><TABLE CELLSPACING=\"10\" CELLPADDING=\"2\">";

	# File system images
	if (scalar @fs > 0) {
		print "<TR><TH COLSPAN=3>".
		  "<IMG SRC=\"pict/int_h_img.jpg\" ALT=\"File System Images\">".
		  "</TH></TR>\n";
		my @sort = sort {$a cmp $b} @fs;
		int_menu_print (\%md5s, \@sort);
	}

	# Unallocated (dls) images
	if (scalar @dls > 0) {
		print  "<TR><TH COLSPAN=3>&nbsp;</TH></TR>\n".
		  "<TR><TH COLSPAN=3>".
		  "<IMG SRC=\"pict/int_h_unalloc.jpg\" ALT=\"Unallocated Data Files\">".
		  "</TH></TR>\n";
		my @sort = sort {$a cmp $b} @dls;
		int_menu_print (\%md5s, \@sort);
	}

	# Strings files (of dls or fs images)
	if (scalar @str > 0) {
		print "<TR><TH COLSPAN=3>&nbsp;</TH></TR>\n".
		  "<TR><TH COLSPAN=3>".
		  "<IMG SRC=\"pict/int_h_str.jpg\" ALT=\"Strings of Images\">".
		  "</TH></TR>\n";
		my @sort = sort {$a cmp $b} @str;
		int_menu_print (\%md5s, \@sort);

	}

	# timeline body files
	if (scalar @body > 0) {
		print "<TR><TH COLSPAN=3>&nbsp;</TH></TR>\n".
		  "<TR><TH COLSPAN=3>".
		  "<IMG SRC=\"pict/int_h_data.jpg\" ALT=\"Timeline Data Files\">".
		  "</TH></TR>\n";
		my @sort = sort {$a cmp $b} @body;
		int_menu_print (\%md5s, \@sort);
	}

	# timeline files
	if (scalar @tl > 0) {
		print "<TR><TH COLSPAN=3>&nbsp;</TH></TR>\n".
		  "<TR><TH COLSPAN=3>".
		  "<IMG SRC=\"pict/int_h_tl.jpg\" ALT=\"Timelines\">".
		  "</TH></TR>\n";
		my @sort = sort {$a cmp $b} @tl;
		int_menu_print (\%md5s, \@sort);
	}


print <<EOF;
</TABLE>
<P>
<TABLE CELLSPACING=20 WIDTH=600 CELLPADDING=2>
<TR>
  <TD><A HREF=\"$PROGNAME?$baseargs&func=$IMG_OPEN\" TARGET=\"_top\">
    <IMG SRC=\"pict/menu_b_ok.jpg\" ALT=\"Ok\" 
    WIDTH=\"167\" BORDER=\"0\">
  </A>
  </TD>
  <TD><A HREF=\"$PROGNAME?$baseargs&func=$INT_LIST_FR\" TARGET=\"_top\">
    <IMG SRC=\"pict/menu_b_ref.jpg\" ALT=\"Refresh\" 
    WIDTH=\"167\" BORDER=\"0\">
  </A>
  </TD>
  <TD ALIGN=CENTER>
    <A HREF=\"$HELP_URL\" TARGET=\"_blank\">
    <IMG SRC=\"pict/menu_b_help.jpg\" ALT=\"Help\" 
    WIDTH=\"167\" BORDER=0>
  </A>
  </TD>
</TR>
</TABLE>

EOF
	return;
};


# Pass the relative path (images/xyz) of the file.  The MD5 is
# returned (or NULL) (in all caps)
sub lookup_md5 {
	my $img = shift;
	my $md5 = "";

	(my $img_dir) = split (/\//,$img);
	my $md5_file = "${host_dir}${img_dir}/$MD5_FILE";

	if (-e "$md5_file") {
		unless (open (FILE, $md5_file)) { 
			print "Error opening $md5_file<BR>\n";
			return "";
		}

		while (<FILE>) {
			s/^\s+//;
			s/\s+$//;

			if (/($REG_MD5)\s+(.*)/o) {
				my $m = $1;
				if ($2 =~ /$img$/) {
					$md5 = $m;
					$md5 =~ tr/[a-f]/[A-F]/;
					last;
				}
			}
			else {
				print "Error reading line $. of $md5_file: $_<BR>\n";
				return "";
			}
		}
		close (FILE);
	}

	return $md5;
};


$funcs[$INT_CHECK] = sub {
	# we do a check_img because it was skipped in the main function
	check_img('img');
	print_html_header("Image Integrity Check");

	my $md5 = lookup_md5($args{'img'});

	if ($md5 eq "") {
		print "The MD5 value of <TT>$args{'img'}</TT> was not found<BR>".
		  "It can be calculated by pressing the button below.".
          "<BR><BR>\n<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
          "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$INT_CREATE\">\n".
          "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
		  make_hidden().
		  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/int_b_calc.jpg\" ".               
		  "ALT=\"Calculate\" BORDER=\"0\">\n</FORM>";
		return 1;
	}

	log_host_inv ("$args{'img'}: Checking image integrity");

	print "<FONT SIZE=3>Original MD5: <TT>$md5</TT><BR>\n";

	# We have the original value, now get the new one
	my $img = get_img('img');
	my $cur = calc_md5($img);

	if ($cur =~ /^$REG_MD5$/o) {
	    print "Current MD5: <TT>$cur</TT><BR><BR>\n";

		if ($cur eq $md5) {
			print "Pass<BR>\n";
			log_host_inv ("$args{'img'}: Image integrity check PASSED");
		} else {
			print "<FONT COLOR=\"$DEL_COLOR[0]\">Fail: Restore from backup".
			  "</FONT><BR>\n";

			log_host_inv ("$args{'img'}: Image integrity check FAILED");
		}
		return 0;
	}
	else {
		print "$cur<BR>\n";
		return 1;
	}
};

# Calculate the MD5 value of a file (given the full path)
# return the value in upper case
sub calc_md5 {
	my $img = shift;
    my $out = `\'${TASKDIR}md5\' \'$img\'`;
    if ($out =~ /($REG_MD5)\s+$img/) {
        my $m = $1;
        $m =~ tr/[a-f]/[A-F]/;
		return $m;
    } else {
		return $out;
    }
}


# Pass it the full path and the short name
# and it adds it to md5.txt and returns the MD5
sub int_create_wrap  {
	my $img = shift;
	my $name = shift;

	my $m = calc_md5 ($img);
	update_md5 ($name, $m) if ($m =~ /^$REG_MD5$/o); 
	return $m;
}

$funcs[$INT_CREATE] = sub {
	print_html_header("Image Integrity Creation");
	print "Calculating MD5 value for <TT>$args{'img'}</TT><BR>\n";
	log_host_inv ("$args{'img'}: Calculating MD5 value");

	my $img = get_img('img');
	my $m = int_create_wrap ($img, $args{'img'});

    print "MD5: <TT>$m</TT><BR>\n";
	(my $img_dir) = split (/\//,$args{'img'});
    print "<BR>Value added to <TT>${host_dir}${img_dir}/$MD5_FILE</TT><BR><BR>\n";
};


####################################################################
# TIME LINE

my %m2d = ("Jan", 1, "Feb", 2, "Mar", 3, "Apr", 4, "May", 5, "Jun", 6,
    "Jul", 7, "Aug", 8, "Sep", 9, "Oct", 10, "Nov", 11, "Dec", 12);
my @d2m = ("", "Jan","Feb","Mar","Apr", "May", "Jun", "Jul", "Aug",
  "Sep", "Oct", "Nov", "Dec");

# Call the appropriate function based on the value of sort
$funcs[$TL_MAIN] = sub {
	print_html_header_frameset("Timeline: $args{'case'}:$args{'host'}");

	print "<FRAMESET ROWS=\"38,*\">\n";

	my $mode = $TL_MAIN;
	$mode = get_mode() if (exists $args{'mode'});

	# Listing
	print "<FRAME SRC=\"$PROGNAME?func=$TL_TABS&$baseargs&mode=$mode\">\n";

	my $str = "";

	# Contents
	if ($mode == $TL_MAIN) {
		print "<FRAME SRC=\"$PROGNAME?func=$BLANK\" ".
		  "NAME=\"content\">\n</FRAMESET>\n";

		return;
	}
	# elsif ($mode == $TL_BODY_ENT) 
	elsif ($mode == $TL_TL_ENT) {
		$str .= "&body=$args{'body'}" if (exists $args{'body'});
	}
	elsif ($mode == $TL_VIEW_FR) {
		$str .= "&tl=$args{'tl'}" if (exists $args{'tl'});
	}
	# elsif ($mode == $NOTES_MAIN) 

	print "<FRAME SRC=\"$PROGNAME?func=$mode&$baseargs$str\" ".
	  "NAME=\"content\">\n</FRAMESET>\n";

	return 0;
};



$funcs[$TL_BODY_ENT] = sub {
	print_html_header("");

	my $i;
    my %mnt2img;

    # Cycle through each image we read from fsmorgue
    foreach $i (keys %img2mnt) {
		next if (($img2ftype{$i} eq "strings") || ($img2ftype{$i} eq "dls"));

		$mnt2img{"$img2mnt{$i}--$i"} = $i;
    }

    # sort via ftype and then mount point (which includes the name)
	my @mnt = sort {
		lc($img2ftype{$mnt2img{$a}}) cmp lc($img2ftype{$mnt2img{$b}}) or
		lc($a) cmp lc($b)
	} keys %mnt2img; 

	print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$TL_BODY_DOIT\">\n".
	  make_hidden().
	  "<P>1.  Select one or more of the following images to collect data from:\n".
	  "<TABLE CELLSPACING=\"8\" CELLPADDING=\"2\">";

	for (my $i = 0; $i <= $#mnt; $i++) {
		my $img = $mnt2img{$mnt[$i]};

		print "<TR><TD><INPUT TYPE=\"checkbox\" NAME=\"$img\" VALUE=\"1\">".
		  "</TD><TD><TT>$img2mnt{$img}</TT></TD><TD><TT>$img</TT></TD>".
		  "<TD>$img2ftype{$img}</TD>\n";
	}


	print "</TABLE><P>2.  Select the data types to gather:<BR>\n". 
	  "<TABLE CELLSPACING=\"8\" CELLPADDING=\"2\"><TR>".
	  "<TD><INPUT TYPE=\"checkbox\" NAME=\"al_file\" VALUE=\"1\" CHECKED>".
	  "</TD><TD>Allocated Files</TD>".
	  "<TD><INPUT TYPE=\"checkbox\" NAME=\"unal_file\" VALUE=\"1\" CHECKED>".
	  "</TD><TD>Unallocated Files</TD>".
	  "<TD><INPUT TYPE=\"checkbox\" NAME=\"unal_inode\" VALUE=\"1\" CHECKED>".
	  "</TD><TD>Unallocated Meta Data Structures</TD></TR></TABLE>\n".
	  "<P>3.   Enter name of output file (<TT>body</TT>):<BR>".
	  "<TT>$DATADIR/</TT>".
	  "<INPUT TYPE=\"text\" NAME=\"fname\" VALUE=\"body\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"fname_mode\" VALUE=\"$FNAME_MODE_INIT\">\n".
	  "<P>4.   Generate MD5 Value? ".
	  "<INPUT TYPE=\"checkbox\" NAME=\"md5\" VALUE=\"1\" CHECKED>";

	print "<P><INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".
	  "ALT=\"Ok\" BORDER=\"0\"></FORM>\n";
};

$funcs[$TL_BODY_DOIT] = sub {
	check_fname(); check_fname_mode();
	print_html_header("");

    my $fname_rel = get_fname_rel();
    my $fname = get_fname();

    my $mode = $args{'fname_mode'};

    if ((-e "$fname") && ($FNAME_MODE_INIT == $mode)) {
        print "File Already Exists: $fname_rel\n";
  
		my $hidden = make_hidden();

		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"func\" ".
		  "VALUE=\"$TL_BODY_DOIT\">\n";

		my $i;
		foreach $i (%img2mnt) {
          	$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"$i\" VALUE=\"1\">\n"
			  if (exists $args{$i});
		}

		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"al_file\" ".
		  "VALUE=\"$args{'al_file'}\">\n" if (exists $args{'al_file'});
		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"unal_file\" ".
		  "VALUE=\"$args{'unal_file'}\">\n" if (exists $args{'unal_file'});
		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"unal_inode\" ".
		  "VALUE=\"$args{'unal_inode'}\">\n" if (exists $args{'unal_inode'});
		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"md5\" ".
		  "VALUE=\"$args{'md5'}\">\n" if (exists $args{'md5'});
 

		# Make a new name 
		print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
          "New Name: <INPUT TYPE=\"text\" NAME=\"fname\">".
		  "<TABLE CELLSPACING=\"30\" CELLPADDING=\"2\"><TR><TD>".
          "<INPUT TYPE=\"hidden\" NAME=\"fname_mode\" VALUE=\"$FNAME_MODE_INIT\"
>\n".
		  "$hidden".
		  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_new_name.jpg\" ".               
		  "ALT=\"Use New Name\" BORDER=\"0\">\n</FORM></TD>\n";



		# Overwrite it
		print "<TD><FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_replace.jpg\" ".               
		  "ALT=\"Replace\" BORDER=\"0\"><BR>\n".
          "<INPUT TYPE=\"hidden\" NAME=\"fname\" VALUE=\"$args{'fname'}\">\n".
          "<INPUT TYPE=\"hidden\" NAME=\"fname_mode\" VALUE=\"$FNAME_MODE_OVER\"
>\n".
		  "$hidden".
          "</FORM></TD></TR></TABLE>";

          return 0;
    }

	# we will be appending to the file so we should del it now
	if (-e "$fname") {
		unlink ($fname);
	}	


	my $log_files = "";
	my $log_type = "";

	my $al_file = 0;
	if (exists $args{'al_file'}) {
		$al_file = $args{'al_file'}; 
		$log_type .= "Allocated Files";
	}

	my $unal_file = 0;
	if (exists $args{'unal_file'}) {
		$unal_file = $args{'unal_file'};
		$log_type .= ", " if ($log_type ne "");
		$log_type .= "Unallocated Files";
	}

	my $unal_inode = 0;
	if (exists $args{'unal_inode'}) {
		$unal_inode = $args{'unal_inode'}; 
		$log_type .= ", " if ($log_type ne "");
		$log_type .= "Unallocated Meta Data Structures";
	}



	if (($unal_inode == 0) && ($unal_file == 0) && ($al_file == 0)) {
		print "No data types were selected.  You must select at least one.<BR>\n";
		return 1;
	}


	my $i;
	my $found = 0;
	foreach $i (keys %img2mnt) {
		if (exists $args{$i}) {

			$found = 1;
			my $ftype = $img2ftype{$i};
			my $img = $host_dir.$i;
			my $mnt = $img2mnt{$i};
		
			$log_files .= ", " if ($log_files ne "");
			$log_files .= "$i";

			if (($al_file) && ($unal_file)) {
				print "Running <TT>fls -r -m</TT> on <TT>$i</TT><BR>\n";
				foreach $_ (`\'${TASKDIR}fls\' -z \'$tz\' -s $ts -m \'$mnt\' -f $ftype -r \'$img\' >> \'$fname\'`) {
					print "$_<BR>\n";
				}
			}
			elsif ($al_file) {
				print "Running <TT>fls -ru -m</TT> on <TT>$i</TT><BR>\n";
				foreach $_ (`\'${TASKDIR}fls\' -z \'$tz\' -s $ts -m \'$mnt\' -f $ftype -ru \'$img\' >> \'$fname\'`) {
					print "$_<BR>\n";
				}
			}
			elsif ($unal_file) {
				print "Running <TT>fls -rd -m</TT> on <TT>$i</TT><BR>\n";
				foreach $_ (`\'${TASKDIR}fls\' -z \'$tz\' -s $ts -m \'$mnt\' -f $ftype -rd \'$img\' >> \'$fname\'`) {
					print "$_<BR>\n";
				}
			}

 			if ($unal_inode) {
				print "Running <TT>ils -m</TT> on <TT>$i</TT><BR>\n";
				my $tz_back = "";
				$tz_back = $ENV{TZ} if (exists $ENV{TZ});

				$ENV{TZ} = $tz;

				foreach $_ (`\'${TASKDIR}ils\' -s $ts -m -f $ftype \'$img\' >> \'$fname\'`) {
					print "$_<BR>\n";
				}
				$ENV{TZ} = $tz_back;
			}
		}
	}

	unless ($found) {
		print "No images were given for analysis.  At least one must be selected.<BR>\n";
		return 1;
	}

	
	log_host_inv ("Saving timeline data for $log_type for $log_files to $fname_rel");

	# append to  host config
	update_host_config ("body", $fname_rel);

	print "<BR>Body file saved to <TT>$fname</TT><BR><BR>\n".
	  "Entry added to host config file<BR><BR>\n";

	# Calculate MD5
	if ((exists $args{'md5'}) && ($args{'md5'} == 1)) {
		print "Calculating MD5 Value<BR><BR>\n";
		my $m = int_create_wrap ($fname, $fname_rel);
		print "MD5 Value: <TT>$m</TT><BR><BR>\n";
	}

	print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"_top\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"body\" VALUE=\"$args{'fname'}\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$TL_MAIN\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"mode\" VALUE=\"$TL_TL_ENT\">\n".
	  make_hidden().
	  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".
	  "ALT=\"Ok\" BORDER=\"0\">\n</FORM>\n";

	return 0;
};

$funcs[$TL_TL_ENT] = sub {
	print_html_header("");
	
	my @body;
	# Find the body files if we will be looking for them
	unless (exists $args{'body'}) {
		foreach my $k (keys %img2ftype) {
			if ($img2ftype{$k} eq "body") {
				push @body, $k;
			}
		}

		if (scalar(@body) == 0) {
			print "There are currently no <TT>body</TT> files ".
			  "for this host.<BR>You must create the intermediate ".
			  "data file before you can perform this step<BR>\n".
			  "<P><A TARGET=\"_top\"  ".
			  "HREF=\"$PROGNAME?$baseargs&func=$TL_MAIN&mode=$TL_BODY_ENT\">".
			  "<IMG SRC=\"pict/but_ok.jpg\" ALT=\"Ok\" ".
			  "WIDTH=\"43\" BORDER=\"0\">".
			  "</A>\n";
			return 1;
		}
	}
	print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$TL_TL_DOIT\">\n".
	  make_hidden().
	  "1.  Select the data input file (<TT>body</TT>):\n".
	  "<TABLE CELLSPACING=\"0\" CELLPADDING=\"2\">";

	# if the body file was specified then just print it
	if (exists $args{'body'}) {
		print "<TR><TD><INPUT TYPE=\"radio\" NAME=\"body\" ".
		  "VALUE=\"$args{'body'}\" CHECKED>".
		  "</TD><TD>$args{'body'}</TD>\n";
	}
	else {
		my @body_sort = sort {lc($a) cmp lc($b)} @body;
		for (my $i = 0; $i <= $#body_sort; $i++) {
			(my $img_dir, my $str_img) = split (/\//,$body_sort[$i]);

			print "<TR><TD><INPUT TYPE=\"radio\" NAME=\"body\" ".
			  "VALUE=\"$str_img\"></TD><TD>$str_img</TD>\n";
		}
	}

	my $cur_mon = 1 + (localtime())[4];
	my $cur_year = 1900 + (localtime())[5];

	# STARTING DATE
	print "</TABLE>\n".
	  "<P>2.  Enter the starting date:<BR>\n".
	  "None: <INPUT TYPE=\"radio\" NAME=\"st_none\" VALUE=\"1\" CHECKED><BR>".
	  "Specify: <INPUT TYPE=\"radio\" NAME=\"st_none\" VALUE=\"0\">  ".
	  "<SELECT NAME=\"st_mon\" SIZE=\"1\">";

	for my $i (1 .. 12) {
		if ($i == $cur_mon) {
			print "<OPTION SELECTED VALUE=\"$i\">$d2m[$i]</OPTION>\n";
		} else {
			print "<OPTION VALUE=\"$i\">$d2m[$i]</OPTION>\n";
		}
	}

	print "</SELECT>".
	  "<SELECT NAME=\"st_day\" SIZE=\"1\">".
	  "<OPTION SELECTED>1</OPTION>\n";

	for my $i (2 .. 31) {
		print "<OPTION VALUE=\"$i\">$i</OPTION>\n";
	}


	print "</SELECT>".
	  "<INPUT TYPE=\"text\" NAME=\"st_year\" SIZE=\"6\" VALUE=\"$cur_year\">\n";


	# END DATE
	print "<P>3.   Enter the ending date:<BR>\n".
	  "None: <INPUT TYPE=\"radio\" NAME=\"end_none\" VALUE=\"1\" CHECKED><BR>\n".
	  "Specify: <INPUT TYPE=\"radio\" NAME=\"end_none\" VALUE=\"0\">  \n".
	  "<SELECT NAME=\"end_mon\" SIZE=\"1\">\n";

	for my $i (1 .. 12) {
		if ($i == $cur_mon) {
			print "<OPTION SELECTED VALUE=\"$i\">$d2m[$i]</OPTION>\n";
		} else {
			print "<OPTION VALUE=\"$i\">$d2m[$i]</OPTION>\n";
		}
	}

	print "</SELECT>\n".
	  "<SELECT NAME=\"end_day\" SIZE=\"1\">\n".
	  "<OPTION SELECTED VALUE=\"1\">1</OPTION>\n";

	for my $i (2 .. 31) {
		print "<OPTION VALUE=\"$i\">$i</OPTION>\n";
	}

	print "</SELECT>".
	  "<INPUT TYPE=\"text\" NAME=\"end_year\" SIZE=\"6\" VALUE=\"$cur_year\">\n";


	# FILE NAME
	print "<P>4.   Enter the file name to save as:<BR>".
	  "<TT>$DATADIR/</TT><INPUT TYPE=\"text\" SIZE=36 NAME=\"fname\"><BR>\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"fname_mode\" VALUE=\"$FNAME_MODE_INIT\">\n";


	# Get only the UNIX images - since only they have /etc/passwd and group
	my @unix_imgs;
	my $root_img = "";
    foreach my $i (keys %img2ftype) {
		my $f = $img2ftype{$i};

		next unless (($f =~ /^linux/) || ($f =~ /bsd$/) ||
		  ($f =~ /^solaris$/) || ($f =~ /^bsdi$/)) ;

		push @unix_imgs, $i;

		# Keep a reference to an image with '/' as the mounting point
		$root_img = $i 
		  if ($img2mnt{$i} eq '/');
	}

	if (scalar @unix_imgs > 0) {

		print "<P>5.  Select the UNIX image that contains the /etc/passwd and /etc/group files:<BR>\n";

		print "<SELECT NAME=\"pw_img\">\n";

		# If we did not find an image that has a / mounting point, then
		# we will use none as the default.  
		if ($root_img eq "") {	
			print "<OPTION VALUE=\"\" SELECTED>None</OPTION>\n";
		} else {
			print "<OPTION VALUE=\"\">None</OPTION>\n";
		}

	    foreach my $img (@unix_imgs) {
			if ($root_img eq $img) {	
		    	print 
				  "<OPTION VALUE=\"$img\" SELECTED>$img ($img2mnt{$img})".
				  "</OPTION>\n";
			} else {
		    	print 
				  "<OPTION VALUE=\"$img\">$img ($img2mnt{$img})</OPTION>\n";
			}
		}

		print "</SELECT>\n";
		print "<P>6.  Generate MD5 Value? ";
	}
	else {
		print "<P>5.  Generate MD5 Value? ";
	}

	print "<INPUT TYPE=\"checkbox\" NAME=\"md5\" VALUE=\"1\" CHECKED>\n";

	# Create Button
	print "<P><INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".
	  "ALT=\"Ok\" BORDER=\"0\">\n</FORM>\n";

	return 0;
};


$funcs[$TL_TL_DOIT] = sub {
	check_fname(); check_body(); 

	print_html_header("");

	my $body = get_body();

    my $fname = get_fname();
    my $fname_rel = get_fname_rel();

    my $mode = $args{'fname_mode'};
                
    if ((-e "$fname") && ($FNAME_MODE_INIT == $mode)) {
        print "File Already Exists: <TT>$fname_rel</TT><BR>\n";

		my $hidden = "<INPUT TYPE=\"hidden\" NAME=\"body\" VALUE=\"$args{'body'}\">".
		make_hidden();

		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"st_none\" ".
		  "VALUE=\"$args{'st_none'}\">\n" if (exists $args{'st_none'});
		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"st_year\" ".
		  "VALUE=\"$args{'st_year'}\">\n" if (exists $args{'st_year'});
		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"st_day\" ".
		  "VALUE=\"$args{'st_day'}\">\n" if (exists $args{'st_day'});
		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"st_mon\" ".
		  "VALUE=\"$args{'st_mon'}\">\n" if (exists $args{'st_mon'});
		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"end_none\" ".
		  "VALUE=\"$args{'end_none'}\">\n" if (exists $args{'end_none'});
		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"end_year\" ".
		  "VALUE=\"$args{'end_year'}\">\n" if (exists $args{'end_year'});
		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"end_day\" ".
		  "VALUE=\"$args{'end_day'}\">\n" if (exists $args{'end_day'});
		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"end_mon\" ".
		  "VALUE=\"$args{'end_mon'}\">\n" if (exists $args{'end_mon'});
		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"tz\" ".
		  "VALUE=\"$args{'tz'}\">\n" if (exists $args{'tz'});
		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"pw_img\" ".
		  "VALUE=\"$args{'pw_img'}\">\n" if (exists $args{'pw_img'});
		$hidden .= "<INPUT TYPE=\"hidden\" NAME=\"md5\" ".
		  "VALUE=\"$args{'md5'}\">\n" if (exists $args{'md5'});
   
		# Make a new name 
		print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
          "New Name: <INPUT TYPE=\"text\" NAME=\"fname\">".
		  "<TABLE CELLSPACING=\"30\" CELLPADDING=\"2\"><TR><TD>".
          "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$TL_TL_DOIT\">\n".
          "<INPUT TYPE=\"hidden\" NAME=\"fname_mode\" VALUE=\"$FNAME_MODE_INIT\">\n".
		  "$hidden\n".
		  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_new_name.jpg\" ".               
		  "ALT=\"Use New Name\" BORDER=\"0\">\n</FORM></TD>\n";



		# Overwrite it
        print "<TD><FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_replace.jpg\" ".               
		  "ALT=\"Replace\" BORDER=\"0\"><BR>\n".
          "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$TL_TL_DOIT\">\n".
          "<INPUT TYPE=\"hidden\" NAME=\"fname\" VALUE=\"$args{'fname'}\">\n".
          "<INPUT TYPE=\"hidden\" NAME=\"fname_mode\" VALUE=\"$FNAME_MODE_OVER\"
>\n".
		  "$hidden\n".
		  "</FORM></TD></TR></TABLE>";

		return 0;
    }

	my $mon;
	my $day;
	my $year;

	my $date = "";

	# Get the start date
	unless ((exists $args{'st_none'}) && ($args{'st_none'} == 1)) {

		if (exists $args{'st_mon'}) {
			check_st_mon();
			$mon = get_st_mon();
		}
		if (exists $args{'st_year'}) {
			check_st_year();
			$year = get_st_year();
		}
		if ((exists $args{'st_day'}) && ($args{'st_day'} =~ /^(\d\d?)$/)) {
			$day = $1;
			if (($day < 1) || ($day > 31)) {
				print ("Invalid start day\n");
				return 1;
			}
		} else {
			print ("Invalid start day\n");
			return 1;
		}

		$date = "$mon/$day/$year";
	}

	unless ((exists $args{'end_none'}) && ($args{'end_none'} == 1)) {
		
		if ($date eq "") {
			print "Begin date must be given if ending date is given<BR>";
			return 1;
		}

		if ((exists $args{'end_mon'}) && ($args{'end_mon'} =~ /^(\d\d?)$/)) {
			$mon = $1;
			if (($mon < 1) || ($mon > 12)) {
				print ("Invalid end month\n");
				return 1;
			}
		} else {
			print ("Invalid end month\n");
			return 1;
		}
		if ((exists $args{'end_year'}) && ($args{'end_year'} =~ /^(\d\d\d\d)$/)) {
			$year = $1;
			if (($year < 1970) || ($year > 2020)) {
				print ("Invalid ending year\n");
				return 1;
			}

		} else {
			print ("Invalid end year\n");
			return 1;
		}
		if ((exists $args{'end_day'}) && ($args{'end_day'} =~ /^(\d\d?)$/)) {
			$day = $1;
			if (($day < 1) || ($day > 31)) {
				print ("Invalid end day\n");
				return 1;
			}
		} else {
			print ("Invalid end day\n");
			return 1;
		}

		$date .= "-$mon/$day/$year";
	}


	# temp strings for the password and group files
	my $pw_tmp = "";
	my $gr_tmp = "";
	my $mac_args = "";
	my $log = "";

	# Password and Group Files
	if ((exists $args{'pw_img'}) && ($args{'pw_img'} ne "")) {
		check_img('pw_img');
		my $pw_img = get_img('pw_img');

		my $ftype = $img2ftype {$args{'pw_img'}};

		$log .= "Password & Group File ($pw_img) ";

		# Get the passwd file inode and copy the file
		my $pwi = `\'${TASKDIR}ifind\' -f $ftype -n \'etc/passwd\' \'$pw_img\'`;

		# Do the Taint Checking
		if ($pwi =~ /^($REG_INODE)$/) {
			$pwi = $1; 

			$log .= "Password Inode ($pwi) ";
			# Find a temp name that we can call it
			my $i;
			for ($i = 0; ; $i++) {
				unless (-e "$fname.pw-$i") {
					$pw_tmp = "$fname.pw-$i";				
					last;
				}
			}

			`\'${TASKDIR}icat\' -f $ftype \'$pw_img\' $pwi > \'$pw_tmp\'`;
			$mac_args .= " -p \'$pw_tmp\' ";

		} else {
			print ("Error finding /etc/passwd inode in $pw_img ($pwi)<BR>");
			log_host_inv ("$pw_img: /etc/passwd file not found for timeline");
		}

		# Get the group file inode and copy the file
		my $gri = `\'${TASKDIR}ifind\' -f $ftype -n \'etc/group\' \'$pw_img\'`;

		# Do the Taint Checking
		if ($gri =~ /^($REG_INODE)$/) {
			$gri = $1; 

			$log .= "Group Inode ($gri) ";

			# Find a temp name that we can call it
			my $i;
			for ($i = 0; ; $i++) {
				unless (-e "$fname.gr-$i") {
					$gr_tmp = "$fname.gr-$i";				
					last;
				}
			}
			`\'${TASKDIR}icat\' -f $ftype \'$pw_img\' $gri > \'$gr_tmp\'`;
			$mac_args .= " -g \'$gr_tmp\' ";
		} else {
			print ("Error finding /etc/group inode in $pw_img ($gri)<BR>");
			log_host_inv ("$pw_img: /etc/group file not found for timeline");
		}
	}

	if ($date eq "") {
		print "Creating Timeline using all dates (Time Zone: $tz)<BR>\n";
		log_host_inv ("$args{'body'}: Creating timeline using all dates (TZ: $tz) ${log}to $fname_rel");
	} else {
		print "Creating Timeline for $date (Time Zone: $tz)<BR>\n";
		log_host_inv ("$args{'body'}: Creating timeline for $date (TZ: $tz) ${log}to $fname_rel");
	}

	# mactime needs the path to run the 'date' command
	$ENV{PATH} = "/bin:/usr/bin";
	foreach $_ (`LANG=C LC_ALL=C \'${TASKDIR}mactime\' -b \'$body\' -z \'$tz\' -i day \'${fname}.sum\' $mac_args $date > \'$fname\'`) {
		print "$_<BR>\n";
	}
	$ENV{PATH} = "";


	# Remove the password and group files
	unlink ("$pw_tmp") if ($pw_tmp ne "");
	unlink ("$gr_tmp") if ($gr_tmp ne "");

	print "<BR>Timeline saved to <TT>$fname</TT><BR><BR>\n";

	# append to fsmorgue 
	update_host_config ("timeline", $fname_rel);
	print "Entry added to host config file<BR><BR>\n";


    # Calculate MD5
    if ((exists $args{'md5'}) && ($args{'md5'} == 1)) {
        print "Calculating MD5 Value<BR><BR>\n";
        my $m = int_create_wrap ($fname, $fname_rel);
        print "MD5 Value: <TT>$m</TT><BR><BR>\n";
    }

	print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"_top\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"tl\" VALUE=\"$args{'fname'}\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$TL_MAIN\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"mode\" VALUE=\"$TL_VIEW_FR\">\n".
	  make_hidden().
	  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".
	  "ALT=\"Ok\" BORDER=\"0\">\n</FORM>\n".
	  "(NOTE: It is easier to view the timeline in a text editor than here)";

	return 0;
};

$funcs[$TL_VIEW_MENU] = sub {
	print_html_header("");

	my @tl;
	# Find the timelines in the images hash
	foreach my $k (keys %img2ftype) {
		if ($img2ftype{$k} eq "timeline") {
			push @tl, $k;
		}
	}


	if (scalar(@tl) == 0) {
		print "There are currently no timeline files in the ".
		"host config file.<BR>One must first be created before you ".
		"can view it<BR>\n";

		print "<P><A TARGET=\"_top\"  ".
		  "HREF=\"$PROGNAME?$baseargs&func=$TL_MAIN&mode=$TL_TL_ENT\">".
		  "<IMG SRC=\"pict/but_ok.jpg\" ALT=\"Ok\" ".
		  "WIDTH=\"43\" BORDER=\"0\">".
		  "</A>\n";

		return 1;
	}

	print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$TL_VIEW_FR\">\n".
	  make_hidden().
	  "1.  Select the timeline file:\n".
	  "<TABLE CELLSPACING=\"0\" CELLPADDING=\"2\">\n";

	my @tl_sort = sort {lc($a) cmp lc($b)} @tl;
	for (my $i = 0; $i <= $#tl_sort; $i++) {
		(my $img_dir, my $str_img) = split (/\//,$tl_sort[$i]);

		print "<TR><TD><INPUT TYPE=\"radio\" NAME=\"tl\" ".
		  "VALUE=\"$str_img\"></TD><TD>$str_img</TD>\n";
	}


	print "</TABLE>\n".
	  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".
	  "ALT=\"Ok\" BORDER=\"0\">\n</FORM>\n";
	
	return 0;
};


$funcs[$TL_VIEW_FR] = sub {
	check_tl();

	print_html_header_frameset("");
	my $tl = get_tl();
	my $url = "";

	unless (exists $args{'st_mon'}) {
		# get the start point (this design is not efficient at ALL)
		if (-z "$tl") {
			print("Timeline has no entries");
			return (1);
		}

		unless (open (TL, "$tl")) {
			print("Error opening $tl");
			return (1);
		}

		my $beg_mon;
		my $beg_year;
		while (<TL>) {
			if (/^(?:\w\w\w )?(\w\w\w)\s+\d\d\s+(\d\d\d\d)\s+\d\d:\d\d:\d\d/) {
				$url = "tl=$enc_args{'tl'}&st_mon=$m2d{$1}&st_year=$2";
			}
			last;
		}
		close TL;

		if ($url eq "") {
			print "Invalid Timeline<BR>\n";
			return 1;
		}
	}
	else {
		$url = "tl=$enc_args{'tl'}&st_mon=$enc_args{'st_mon'}&".
	  	  "st_year=$enc_args{'st_year'}";
	}

	print "<FRAMESET ROWS=\"65,*\">\n".
	  "<FRAME SRC=\"$PROGNAME?$baseargs&func=$TL_VIEW_IDX&$url\">\n".
	  "<FRAME SRC=\"$PROGNAME?$baseargs&func=$TL_VIEW&$url\">\n</FRAMESET>";

	return 0;
};

$funcs[$TL_VIEW_IDX] = sub {
	check_st_mon(); check_st_year();check_tl();

	print_html_header("");

	my $mon = get_st_mon();
	my $year = get_st_year();
	my $tl = get_tl();

	print "<CENTER><FONT SIZE=3>";
	my $url = "$PROGNAME?$baseargs&func=$TL_VIEW_FR&tl=$enc_args{'tl'}";

	# Next and Previous pointers
	my $pyear = $year;
	my $pmon = $mon - 1;
	if ($pmon == 0) {
		$pmon = 12;
		$pyear--;
	}
	print "<TABLE CELLSPACING=\"0\" CELLPADDING=\"2\">\n".
	  "<TR><TD ALIGN=\"CENTER\">".
	  "<A HREF=\"$url&st_mon=$pmon&st_year=$pyear\" TARGET=\"_parent\">".
	  "&lt;- $d2m[$pmon] $pyear</A></TD>\n".
	  "<TD>&nbsp;</TD>\n";

	if (-e "${tl}.sum") {
		print "<TD><A HREF=\"$PROGNAME?$baseargs&func=$TL_VIEW_SUM&".
		  "tl=$enc_args{'tl'}\" TARGET=\"_parent\">".
		  "Summary</TD>\n".
		  "<TD>&nbsp;</TD>\n";
	}

	my $nyear = $year;
	my $nmon = $mon + 1;
	if ($nmon == 13) {
		$nmon = 1;
		$nyear++;
	}

	print "<TD ALIGN=\"CENTER\">".
	  "<A HREF=\"$url&st_mon=$nmon&st_year=$nyear\" TARGET=\"_parent\">".
	  "$d2m[$nmon] $nyear -&gt</A></TD></TR></TABLE>\n";

	# Make a form to enter the next month and year to show.  
	# it defaults to the current location
    print "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\" TARGET=\"_parent\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$TL_VIEW_FR\">\n".
      "<INPUT TYPE=\"hidden\" NAME=\"tl\" VALUE=\"$enc_args{'tl'}\">\n".
      make_hidden().

	  "<TABLE CELLSPACING=\"0\" CELLPADDING=\"2\">\n".
      "<TR><TD ALIGN=\"CENTER\"><SELECT NAME=\"st_mon\" SIZE=\"1\">\n";

    for my $i (1 .. 12) {
		if ($i == $mon) {
			print "<OPTION SELECTED VALUE=\"$i\">$d2m[$i]</OPTION>\n";
		} else {
        	print "<OPTION VALUE=\"$i\">$d2m[$i]</OPTION>\n"; 
		}
    }

    print "</SELECT></TD>".
      "<TD ALIGN=\"CENTER\">".
	  "<INPUT TYPE=\"text\" NAME=\"st_year\" SIZE=\"6\" VALUE=\"$year\">".
      "</TD>".
	  "<TD ALIGN=\"CENTER\">".
	  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ALT=\"Ok\" ".
	  "BORDER=\"0\"></TD>\n".
	  "</TR></TABLE></FORM>\n";

	return 0;
};


# Display the contents of the summary file (hits per day) and show
# it as hits per month
$funcs[$TL_VIEW_SUM] = sub {
	check_tl();

	print_html_header("");
	
	my $tl = get_tl();

	$tl .= ".sum";

	unless (-e "$tl") {
		print_err ("Summary of timeline file not found (<TT>$tl</TT>)<BR>The timeline must be created with The Sleuth Kit version 1.61 or greater to have a summary\n");
	}

	open (TL, "<$tl") or die "Can not open $tl";
	my $url = "$PROGNAME?$baseargs&func=$TL_VIEW_FR&tl=$enc_args{'tl'}";

	print "<P>This page provides a monthly summary of activity.".
	  "Each day that has activity is noted with the number of events<BR>\n";

	my $p_year = "";
	my $p_mon = "";

	print "<P><TABLE CELLSPACING=2 BORDER=0>\n";

	while (<TL>) {
		my @a = split(/ /, $_);
		next unless (scalar (@a) == 5);
		my $mon = $m2d{$a[1]};
		my $year = $a[3];
		$year = $1 if ($year =~ /^(\d{4,4}):$/);

		if (($p_year ne $year) || ($p_mon ne $mon)) {
			print "<TR><TD COLSPAN=6 ALIGN=LEFT>".
			  "<A HREF=\"$url&st_mon=$mon&st_year=$year\">".
		  	  "$a[1] $year</A></TD></TR>\n";

			$p_year = $year;
			$p_mon = $mon;
		}
		print "<TR><TD>&nbsp;&nbsp;</TD><TD>$a[0]</TD>".
		  "<TD>$a[1]</TD><TD>$a[2]</TD><TD>$year</TD><TD>($a[4])</TD></TR>\n";
	}
	print "</TABLE>\n";

	close (TL);

	return 0;
};

# display a given month of the timeline
$funcs[$TL_VIEW] = sub {
	check_tl(); check_st_mon(); check_st_year();
	print_html_header("");

	my $tl = get_tl();
	my $st_mon = get_st_mon();
	my $st_year = get_st_year();


	unless (open (TL, "$tl")) {
		print("Error opening $tl");
		return (1);
	}

	log_host_inv ("$args{'tl'}: Viewing timeline for $d2m[$st_mon] $st_year");

	print "<TABLE CELLSPACING=\"5\" CELLPADDING=\"2\" WIDTH=100%>\n";

	# zone identifies if we should be printing or not
	my $zone = 0;
	my $row = 0;
	while (<TL>) {
		if (/^(?:(\w\w\w\s+)?(\w\w\w\s+\d\d\s+\d\d\d\d)\s+(\d\d:\d\d:\d\d))?\s+(\d+)\s+([mac\.]+)\s+([-\/\?\w]+)\s+([\d\w\/]+)\s+([\d\w\/]+)\s+($REG_INODE)\s+(.*)$/o) {
		
			my $day = "";
			$day = $1 if (defined $1);
			my $date = "";
			$date = $2 if (defined $2);
			my $time = "";
			$time = $3 if (defined $3);
			my $sz = $4;
			my $mac = $5;
			my $p = $6;
			my $u = $7;
			my $g = $8;
			my $i = $9;
			my $f = $10;

			# we must break this down to see if we can skip it or not
			if ($date ne "") {
				if ($date =~ /^(\w\w\w)\s+\d\d\s+(\d\d\d\d)$/) {
					if ($2 < $st_year) {
						next;
					} elsif (($2 == $st_year) && ($m2d{$1} < $st_mon)) {
						next;
					} elsif ($2 > $st_year) {
						last;
					} elsif (($2 == $st_year) && ($m2d{$1} > $st_mon)) {
						last;
					} else {
						$zone = 1;
					}
				}
			}

			# we need to print this entry
			if ($zone) {

				# the deleted inode <blah-dead-2> entries screw up in HTML
				$f = "&lt;$1 &gt" if ($f =~ /^<(.*?)>$/);

				if (($row % 2) == 0) {
					print "<TR VALIGN=\"TOP\" BGCOLOR=\"$BACK_COLOR\">\n";
				} else {
					print "<TR VALIGN=\"TOP\" BGCOLOR=\"$BACK_COLOR_TABLE\">\n";
				}

				print "<TD>$day&nbsp;$date&nbsp;$time</TD>".
				  "<TD>$sz</TD><TD>$mac</TD><TD>$p</TD>".
				  "<TD>$u</TD><TD>$g</TD><TD>$i</TD><TD>$f</TD></TR>\n";

				$row++;
			} 
		} 
		else {
			print "Error parsing string: $_<BR>\n";
		}
	}
	close TL;
	print "</TABLE>";

	return 0;
};



############ Notes ##################

# window that allows one to make a note
# use the vars that were passed to determine what a comment is being
# made about (file, inode, block)
#
$funcs[$NOTES_ENT] = sub {

	my $str;
	my $hidden;

	if ($USE_NOTES == 0) {
		print_html_header("Error");
		print "Notes Option is not enabled\n";
		return;
	}

	my $ftype = get_ftype();

	# if the inode arg exists, it is either an inode note or a file name note
	if (exists $args{'inode'}) {
		my $inode = get_inode('inode');
		my $fname = "";

		if (exists $args{'dir'}) {
			my $fname = "$args{'mnt'}$args{'dir'}";
			print_html_header("Notes for file $fname");
			print 
			  "<CENTER><B>Enter a note for <TT>$fname</TT> ($inode):</B>".
			  "<BR><BR\n";
		} else {
			print_html_header("Notes for $meta_str{$ftype} $inode");
			print 
			  "<CENTER><B>Enter a note for $meta_str{$ftype} $inode:</B>".
			  "<BR><BR>\n";
		}

		print 
		  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  "<TEXTAREA ROWS=10 COLS=50 WRAP=\"virtual\" NAME=\"note\">".
		  "</TEXTAREA><BR>\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$NOTES_WRITE\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
	  	  "<INPUT TYPE=\"hidden\" NAME=\"inode\" VALUE=\"$inode\">\n".
		  make_hidden();

		  print 
		    "<INPUT TYPE=\"hidden\" NAME=\"dir\" VALUE=\"$args{'dir'}\">\n"
		    if (exists $args{'dir'});


		# Option to add a normal note
		print 
		  "<INPUT TYPE=\"checkbox\" NAME=\"norm_note\" VALUE=\"1\" CHECKED>\n".
		  "  Add a Standard Note<BR>\n";

		# Sequencer notes

		my $ftype = get_ftype();
		my $img_path = get_img('img');
		my @out = `${TASKDIR}ils -f $ftype -e $img_path $inode`;
		unless ((exists $out[3]) && ($out[3] =~ /^$REG_INODE\|\w\|\d+\|\d+\|(\d+)\|(\d+)\|(\d+)\|/o)) {
			print "Error parsing 'ils' output: $out[0]<BR>\n";
			return 1;
		}
		my $mtime = $1;
		my $atime = $2;
		my $ctime = $3;

		$ENV{TZ} = "$tz";
		$mtime = localtime($mtime);
		$atime = localtime($atime);
		$ctime = localtime($ctime);

		print 
		  "<BR><B>Add a Sequencer Event:</B><BR>\n".
		  "<INPUT TYPE=\"checkbox\" NAME=\"mtime\" VALUE=\"1\">".
		  "&nbsp;&nbsp;M-Time (<TT>$mtime</TT>)<BR>\n".
		  "<INPUT TYPE=\"checkbox\" NAME=\"atime\" VALUE=\"1\">".
		  "&nbsp;&nbsp;A-Time (<TT>$atime</TT>)<BR>\n".
		  "<INPUT TYPE=\"checkbox\" NAME=\"ctime\" VALUE=\"1\">".
		  "&nbsp;&nbsp;C-Time (<TT>$ctime</TT>)<BR>\n";

		print 
		  "<BR><INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".
		  "ALT=\"Ok\" BORDER=\"0\">\n</FORM>\n";
	}

	# data unit comment
	elsif (exists $args{'block'}) {
		my $block = get_block();
		my $len = get_len();
		print_html_header("Notes for $addr_unit{$ftype} $block");

		print 
		  "<CENTER><B>Enter a note for $addr_unit{$ftype} $block</B><BR><BR\n".
		  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
		  "<TEXTAREA ROWS=10 COLS=50 WRAP=\"virtual\" NAME=\"note\">".
		  "</TEXTAREA><BR>\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$NOTES_WRITE\">\n".
		  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
	  	  "<INPUT TYPE=\"hidden\" NAME=\"block\" VALUE=\"$block\">\n".
	  	  "<INPUT TYPE=\"hidden\" NAME=\"len\" VALUE=\"$len\">\n".
	  	  "<INPUT TYPE=\"hidden\" NAME=\"norm_note\" VALUE=\"1\">\n".
		  make_hidden().
		  "<BR><INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".
		  "ALT=\"Ok\" BORDER=\"0\">\n</FORM>\n";
	}

	else {
		print_html_header ("ERROR");
		print "Unknown note type\n";
		return;
	}

	return;
};


# Write the note to the note file
# 
# we tell what kind of note it is based on what args are passed
#
# if inode is passed it is either a dir, file, or inode and if block is
# passed it is a block
# If the dir arg is passed it is a file or directory and if the dir arg
# ends with a '/' then it is a directory
#
# This function also writes the sequencer events from files and inodes
# but the NOTES_SEQ_WRITE does the manual ones
#
$funcs[$NOTES_WRITE] = sub {

	if ($USE_NOTES == 0) {
		print_html_header("Error");
		print "Notes Option is not enabled\n";
		return;
	}

	check_note();

	# Get rid of carriage returns that Netscape adds 
	$args{'note'} =~ tr/\r//d;


	my $ftype = get_ftype();
	my $inode = "";
	my $fname = "";
	my $block = "";
	my $len = "";
	my $type = "";

	if (exists $args{'inode'}) {
		$inode = get_inode('inode');


		if (exists $args{'dir'}) {
			$args{'dir'} .= "/"
			  if ($args{'dir'} eq "");
			$fname = "$args{'mnt'}$args{'dir'}";

			if (($args{'dir'} =~ /\/$/) || ($args{'dir'} eq "")) {
				log_host_inv ("$args{'img'}: Creating note for directory $fname ($inode)");
				$type = "dir";
			} else {
				log_host_inv ("$args{'img'}: Creating note for file $fname ($inode)");
				$type = "file";
			}
		}
		else {
			log_host_inv ("$args{'img'}: Creating note for $meta_str{$ftype} $inode");
			$type = "$meta_str{$ftype}";
		}
	}
	elsif (exists $args{'block'}) {
		$block = get_block();
		$len = get_len();

		log_host_inv ("$args{'img'}: Creating note for $addr_unit{$ftype} $block");
		$type = "$addr_unit{$ftype}";
	}
	else {
		print_html_header ("ERROR");
		print "Unknown note type\n";
		return;
	}

	print_text_header();
	print "\n";

	# Create the notes
	# Create a "normal" note
	if ((exists $args{'norm_note'}) && ($args{'norm_note'} == 1)) {

		my $notes_file = investig_notes_fname();
		open NOTES, ">>$notes_file" or die "Can't open log: $notes_file";
		print "Note added to $notes_file:\n\n";

		# Date
		my $tmp = localtime();
		print NOTES "$tmp\n";
		print "$tmp\n";

		# We have a file name
		if ($fname ne "") {
			if ($type eq 'dir') {
				print NOTES "Directory: $fname\n";
				print "Directory: $fname\n";
			}
			else {
				print NOTES "File: $fname\n";
				print "File: $fname\n";
			}
		}
		if ($inode ne "") {
			print NOTES "Image: $args{'img'}  Inode: $inode\n";
			print "Image: $args{'img'}  Inode: $inode\n";
		}
		if ($block ne "") {
			print NOTES "Image: $args{'img'}  $addr_unit{$ftype}: $block  Len: $len\n";
			print "Image: $args{'img'}  $addr_unit{$ftype}: $block  Len: $len\n";
		}

		# The actual notes and a line at the bottom
		print NOTES "\n$args{'note'}\n\n".
		  "-" x 62 ."\n";
		print "\n$args{'note'}\n\n";

		close NOTES;
	}

	return 0
	  unless (exists $args{'inode'});


	# Create a sequencer event
	return 0 
	  unless ( ((exists $args{'mtime'}) && ($args{'mtime'} == 1)) ||
	    ((exists $args{'atime'}) && ($args{'atime'} == 1)) ||
	    ((exists $args{'ctime'}) && ($args{'ctime'} == 1)) );

	my $img_path = get_img('img');

	# Get the times for the inode
	my @out = `${TASKDIR}ils -f $ftype -e $img_path $inode`;
	unless ($out[3] =~ /^$REG_INODE\|\w\|\d+\|\d+\|(\d+)\|(\d+)\|(\d+)\|/o) {
		print "Error parsing 'ils' output<BR>\n";
		return 1;
	}
	my $mtime = $1;
	my $atime = $2;
	my $ctime = $3;

	# Get rid of the carriage returns
	$args{'note'} =~ s/\n/<BR>/gs;

	my $notes_file = investig_seq_notes_fname();
	open NOTES, ">>$notes_file" or die "Can't open log: $notes_file";

	# Set the timezone to the host zone
	$ENV{TZ} = "$tz";

	if ((exists $args{'mtime'}) && ($args{'mtime'} == 1)) {

		my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
		  localtime($mtime);
		$year += 1900;
		$mon += 1;
		$mday = "0$mday" if ($mday < 10);
		$hour = "0$hour" if ($hour < 10);
		$min = "0$min" if ($min < 10);
		$sec = "0$sec" if ($sec < 10);
	
		print NOTES "$year,$mon,$mday,$hour,$min,$sec,$args{'host'},".
		  "$args{'img'},$fname,$inode,$block,$type,[M-Time]$args{'note'}\n";

		log_host_inv ("$args{'img'}: M-Time note added for inode $args{'inode'}");
		print "M-Time sequence event added\n";
	}
	if ((exists $args{'atime'}) && ($args{'atime'} == 1)) {
		my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
		  localtime($atime);
		$year += 1900;
		$mon += 1;
		$mday = "0$mday" if ($mday < 10);
		$hour = "0$hour" if ($hour < 10);
		$min = "0$min" if ($min < 10);
		$sec = "0$sec" if ($sec < 10);
	
		print NOTES "$year,$mon,$mday,$hour,$min,$sec,$args{'host'},".
		  "$args{'img'},$fname,$inode,$block,$type,[A-Time]$args{'note'}\n";

		log_host_inv ("$args{'img'}: A-Time note added for inode $args{'inode'}");
		print "A-Time sequence event added\n";
	}
	if ((exists $args{'ctime'}) && ($args{'ctime'} == 1)) {
		my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
		  localtime($ctime);
		$year += 1900;
		$mon += 1;
		$mday = "0$mday" if ($mday < 10);
		$hour = "0$hour" if ($hour < 10);
		$min = "0$min" if ($min < 10);
		$sec = "0$sec" if ($sec < 10);
	
		print NOTES "$year,$mon,$mday,$hour,$min,$sec,$args{'host'},".
		  "$args{'img'},$fname,$inode,$block,$type,[C-Time]$args{'note'}\n";

		log_host_inv ("$args{'img'}: C-Time note added for inode $args{'inode'}");
		print "C-Time sequence event added\n";
	}

	close(NOTES);

	return 0;
};



# Display the contents of the "normal" notes file
$funcs[$NOTES_READ] = sub {

	if ($USE_NOTES == 0) {
		print_html_header("Error");
		print "Notes Option is not enabled\n";
		return;
	}

	print_html_header("Contents of Notes File");

	my $notes_file = investig_notes_fname();

	log_host_inv ("Viewing contents of notes file ($notes_file)");
	if ((!(-e "$notes_file")) || (-z "$notes_file")) {
		print "No notes have been entered yet<BR>\n";
		return;
	}

	open NOTES, "<$notes_file" or die "Can't open log: $notes_file";

	my $file = "";
	my $dir = "";

	print "<TABLE WIDTH=100%>\n".
	  "<TR BGCOLOR=$BACK_COLOR><TD ALIGN=LEFT>\n";

	my $row=0;
	# This will need to change whenever the log format changes
	while (<NOTES>) {

		# we need to extract mnt from here
		$file = $1 if (/File: (.*)/);
		$dir = $1 if (/Directory: (.*)/);

		# Reset the $file if we are at the end of the current note
		if (/^\-+$/) {
			$file = "";
			$dir = "";
			if (($row++ % 2) == 0) {
	  			print "</TD></TR>\n<TR BGCOLOR=$BACK_COLOR_TABLE><TD ALIGN=LEFT>\n";
			} else {
	  			print "</TD></TR>\n<TR BGCOLOR=$BACK_COLOR><TD ALIGN=LEFT>\n";
			}
		}
		else {
			print "$_<BR>";
		}

		if (/Image: ($REG_IMG)  Inode: ([0-9\-]+)/o) {

			my $img = $1;
			my $inode = $2;

			# if we can't find this image, then it likely means that the
			# comment pertains to a different case, so we can not give
			# any links
			unless (exists $img2mnt{$img}) {
				next;
			}
			
			# file note
			if ($file ne "") {
				# extract the prepended mnt value
				my $mnt = $img2mnt{$img};
				my $fname = "";
				$fname = $1 if ($file =~ /^$mnt\/?(.*)$/);
				print "<A HREF=\"$PROGNAME?$baseargs&func=$FIL_CMENU_FR".
				  "&img=$img&inode=$inode&dir=$fname\" TARGET=\"_blank\">View</A><BR>\n";
			}
			# directory note
			elsif ($dir ne "") {
				# extract the prepended mnt value
				my $mnt = $img2mnt{$img};
				my $fname = "";
				$fname = $1 if ($dir =~ /^$mnt\/?(.*)$/);
				print "<A HREF=\"$PROGNAME?func=$MAIN_FR&".
				  "mode=$FIL_MAIN&img=$img&".
				  "$baseargs&inode=$inode&dir=$fname\" TARGET=\"_blank\">".
				  "View</A><BR>\n";

			}
			# inode note
			else {
				print "<A HREF=\"$PROGNAME?func=$MAIN_FR&".
				  "mode=$INO_MAIN&img=$img".
				  "&$baseargs&inode=$inode\" TARGET=\"_blank\">View</A><BR>\n";
			}
		}

		# block note
		elsif (/Image: ($REG_IMG)  \w+: ([0-9]+)  Len: (\d+)/o) {
			print "<A HREF=\"$PROGNAME?func=$MAIN_FR&".
			  "mode=$BLK_MAIN&img=$1&".
			  "block=$2&len=$3&$baseargs\"".
			  " TARGET=\"_blank\">View</A><BR>\n";
		}
	}

	print "</TR></TABLE>\n";

    # Ok and refresh buttons    
    print 
      "<P><CENTER><TABLE WIDTH=600>\n".
      "<TR><TD WIDTH=300 ALIGN=CENTER>\n".
      "<A HREF=\"$PROGNAME?func=$IMG_OPEN&$baseargs\">".
      "<IMG BORDER=0 SRC=\"pict/menu_b_ok.jpg\"></A>\n".
      "</TD><TD WIDTH=300 ALIGN=CENTER>\n".
      "<A HREF=\"$PROGNAME?func=$NOTES_READ&$baseargs\">".
      "<IMG BORDER=0 SRC=\"pict/menu_b_ref.jpg\"></A>\n".
      "</TD></TR></TABLE>\n";

	close NOTES;
	return;
};


#########################################################################
# Sequencer Code

# Write a sequence event that was manually entered 
$funcs[$NOTES_SEQ_WRITE] = sub {

	if ($USE_NOTES == 0) {
		print_html_header("Error");
		print "Notes Option is not enabled\n";
		return;
	}

	check_note();

	print_html_header("Writing Sequencer Event");

	# Get rid of carriage returns that Netscape adds 
	$args{'note'} =~ tr/\r//d;
	$args{'note'} =~ s/\n/<BR>/gs;

	if ($args{'note'} eq "") {
		print "A comment must be given for the event<BR>\n".
		  "<P><A HREF=\"$PROGNAME?func=$NOTES_SEQ_READ&$baseargs\">".
		  "<IMG BORDER=0 SRC=\"pict/menu_b_ok.jpg\"></A>\n"; 
		return 1;
	}

	# Check the args and add them to the final string that will be written
	my $str = "";
	unless ((exists $args{'year'}) && ($args{'year'} =~ /^(\d\d\d\d)$/))  {
		print "Invalid year<BR>\n";
		return 1;
	}
	$str .= "$1,";

	unless ((exists $args{'mon'}) && ($args{'mon'} =~ /^(\d\d?)$/))  {
		print "Invalid month<BR>\n";
		return 1;
	}
	$str .= "$1,";

	unless ((exists $args{'day'}) && ($args{'day'} =~ /^(\d\d?)$/))  {
		print "Invalid day<BR>\n";
		return 1;
	}
	$str .= "$1,";

	unless ((exists $args{'hour'}) && ($args{'hour'} =~ /^(\d\d?)$/))  {
		print "Invalid hour<BR>\n";
		return 1;
	}
	$str .= "$1,";

	unless ((exists $args{'min'}) && ($args{'min'} =~ /^(\d\d?)$/))  {
		print "Invalid min<BR>\n";
		return 1;
	}
	$str .= "$1,";

	unless ((exists $args{'sec'}) && ($args{'sec'} =~ /^(\d\d?)$/))  {
		print "Invalid sec<BR>\n";
		return 1;
	}
	$str .= "$1,";

	# There are no image, inode, file name, or data unit for this type
	$str .= "$args{'host'},,,,,";

	unless ((exists $args{'src'}) && ($args{'src'} =~ /^(\w+)$/))  {
		print "Invalid src<BR>\n";
		return 1;
	}
	$str .= "$1,$args{'note'}\n";

	# Write the string to the notes file
	my $notes_file = investig_seq_notes_fname();
	open NOTES, ">>$notes_file" or die "Can't open log: $notes_file";
	print NOTES $str;
	close NOTES;

	# Send a message to the user
	print "Event Added to Sequencer file:<BR><BR>\n".
	  "$d2m[$args{'mon'}] $args{'day'}, $args{'year'} ".
	  "$args{'hour'}:$args{'min'}:$args{'sec'}<BR><BR>\n".
	  "$args{'note'}<BR>\n".
	  "<P><A HREF=\"$PROGNAME?func=$NOTES_SEQ_READ&$baseargs\">".
	  "<IMG BORDER=0 SRC=\"pict/but_ok.jpg\"></A>\n"; 

	return 0;
};


# View the sequencer file
$funcs[$NOTES_SEQ_READ] = sub {

	if ($USE_NOTES == 0) {
		print_html_header("Error");
		print "Notes Option is not enabled\n";
		return;
	}

	print_html_header("Event Sequencer");

	print "<CENTER>\n".
	  "<H3>Event Sequencer</H3>\n";


	my $cnt = 0;
	my @entry;
	my (@year, @mon, @day, @hour, @min, @sec, @host, @img, @fname, @inode, @data, @type, @note);

	# Read the sequencer file into arrays that will be sorted
	my $notes_file = investig_seq_notes_fname();
	if (-e $notes_file) {

	open NOTES, "$notes_file" or die "Can't open log: $notes_file";
	while (<NOTES>) {

		unless (/^(\d+),(\d+),(\d+),(\d+),(\d+),(\d+),($REG_HOST),($REG_IMG)?,($REG_MNT)?,($REG_INODE)?,(\d+)?,(\w+),(.*)$/) {
			print "Error parsing sequence event entry: $_\n";
			return 1;
		}

		$year[$cnt] = $1;
		$mon[$cnt] = $2;
		$day[$cnt] = $3;
		$hour[$cnt] = $4;
		$min[$cnt] = $5;
		$sec[$cnt] = $6;
		$host[$cnt] = $7;
		$img[$cnt] = $8;
		$fname[$cnt] = $9;
		$inode[$cnt] = $10;
		$data[$cnt] = $11;
		$type[$cnt] = $12;
		$note[$cnt] = $13;

		$entry[$cnt] = $cnt;
		$cnt++;
	}

	close NOTES;

	# Sort the values by date, source, and then note
	my @sorted = sort {
		$year[$a] <=> $year[$b] or
		$mon[$a] <=> $mon[$b] or
		$day[$a] <=> $day[$b] or
		$hour[$a] <=> $hour[$b] or
		$min[$a] <=> $min[$b] or
		$sec[$a] <=> $sec[$b] or
		lc($type[$a]) cmp lc($type[$b]) or
		lc($note[$a]) cmp lc($note[$b])
	} @entry;


	# Table and header
	print "<TABLE WIDTH=800 BORDER=1>\n".
	  "<TR BACKGROUND=\"$YEL_PIX\">\n".
	  "<TH>Date & Time</TH>\n".
	  "<TH>Source</TH>\n".
	  "<TH>Event & Note</TH></TR>\n";

	# Cycle through the sorted events
	my $row = 0;
	foreach my $i (@sorted) {

		# Alternate row colors
		if (($row % 2) == 0) {
			print "<TR BGCOLOR=\"$BACK_COLOR\">\n";
		} else {
			print "<TR BGCOLOR=\"$BACK_COLOR_TABLE\">\n";
		}

		# Date & Time
		print "<TD ALIGN=LEFT VALIGN=TOP>\n".
		  "$d2m[$mon[$i]]&nbsp;$day[$i],&nbsp;$year[$i]".
		  "&nbsp;$hour[$i]:$min[$i]:$sec[$i]</TD>";

		my $img;
		if (defined $img[$i]) {
			$img = $img[$i];
		} else {
			$img = "";
		}

		print "<TD ALIGN=LEFT VALIGN=TOP>\n";
		# IF there is as name, then we will show it
		if ((defined $fname[$i]) && ($fname[$i] ne "")) {

			if (($img ne "") && (exists $img2mnt{$img}) && 
			  (defined $inode[$i])) {
				# extract the prepended mnt value
				my $mnt = $img2mnt{$img};
				my $fname = "";
				$fname = $1 if ($fname[$i] =~ /^$mnt\/?(.*)$/);

				# Check if it is a directory 
				if ($type[$i] eq 'dir') {
					print "<A HREF=\"$PROGNAME?func=$MAIN_FR&".
					  "mode=$FIL_MAIN&img=$img[$i]&".
					  "$baseargs&inode=$inode[$i]&dir=$fname\" ".
					  "TARGET=\"_blank\">\n".
					  "<TT>$fname[$i]</TT></A>\n";
				} else {
					print "<A HREF=\"$PROGNAME?func=$FIL_CMENU_FR&".
					  "img=$img[$i]&".
					  "$baseargs&inode=$inode[$i]&dir=$fname\" ".
					  "TARGET=\"_blank\">\n".
					  "<TT>$fname[$i]</TT></A>\n";
				}
			}
			else {
				print "<TT>$fname[$i]</TT>\n";
			}
		}

		# Display the inode value if there was no name
		elsif (($img ne "") && (defined $inode[$i]) && ($inode[$i] ne "")) {
			my $ftype = $img2ftype{$img};

			# Include a link if we can
			if (exists $img2mnt{$img}) {
				print "<A HREF=\"$PROGNAME?func=$MAIN_FR&".
				  "mode=$INO_MAIN&img=$img".
				  "&$baseargs&inode=$inode[$i]\" TARGET=\"_blank\">\n".
				  "$meta_str{$ftype}: $inode[$i]</A>\n";
			}
			else {
				print "$meta_str{$ftype}: $inode[$i]\n";
			}
		}

		# Otherwise, just give the source type
		else {
			print "$type[$i]\n";
		}
		print "</TD>\n";

		# Print the actual note
		$note[$i] = "&nbsp;" if ($note[$i] eq "");
		print "<TD ALIGN=LEFT>$note[$i]</TD></TR>\n";

		$row++;
	}

	print "</TABLE>\n";

	} 
	# End of if file exists
	else {
		print "No events currently exist<BR>\n";
	}

	# Ok and refresh buttons 
	print 
	  "<P><TABLE WIDTH=600>\n".
	  "<TR><TD WIDTH=300 ALIGN=CENTER>\n".
	  "<A HREF=\"$PROGNAME?func=$IMG_OPEN&$baseargs\">".
	  "<IMG BORDER=0 SRC=\"pict/menu_b_ok.jpg\"></A>\n".
	  "</TD><TD WIDTH=300 ALIGN=CENTER>\n".
	  "<A HREF=\"$PROGNAME?func=$NOTES_SEQ_READ&$baseargs\">".
	  "<IMG BORDER=0 SRC=\"pict/menu_b_ref.jpg\"></A>\n".
	  "</TD></TR></TABLE>\n";


	# Manually add a new event
	print "<HR>\n".
	  "<B>Add a New Event</B><BR><BR>\n".
	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
	  "<TEXTAREA ROWS=10 COLS=50 WRAP=\"virtual\" NAME=\"note\">".
	  "</TEXTAREA><BR>\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$NOTES_SEQ_WRITE\">\n".
	  make_hidden();

	# Month
	print
	  "<P>Date: ".
	  "<SELECT NAME=\"mon\" SIZE=\"1\">".
	  "<OPTION VALUE=1 SELECTED>$d2m[1]</OPTION>\n";

	for my $i (2 .. 12) {
		print "<OPTION VALUE=\"$i\">$d2m[$i]</OPTION>\n";
	}

	print "</SELECT>\n";

	# Day
	print "&nbsp;<SELECT NAME=\"day\" SIZE=\"1\">\n".
	  "<OPTION VALUE=01 SELECTED>01</OPTION>\n";
	for my $i (2 .. 31) {
		if ($i < 10) {
			print "<OPTION VALUE=\"0$i\">0$i</OPTION>\n";
		} else {
			print "<OPTION VALUE=\"$i\">$i</OPTION>\n";
		}
	}
	print "</SELECT>\n";

	# Year
	my $cur_year = 1900 + (localtime())[5];
	print 
	  "&nbsp;<INPUT TYPE=\"text\" VALUE=\"$cur_year\" ".
	  "NAME=\"year\" SIZE=\"6\">\n";

	# Hour
	print "&nbsp;&nbsp;<SELECT NAME=\"hour\" SIZE=\"1\">\n".
	  "<OPTION VALUE=0 SELECTED>00</OPTION>\n";
	for my $i (1 .. 23) {
		if ($i < 10) {
			print "<OPTION VALUE=\"0$i\">0$i</OPTION>\n";
		} else {
			print "<OPTION VALUE=\"$i\">$i</OPTION>\n";
		}
	}
	print "</SELECT>\n";

	# Min
	print ":<SELECT NAME=\"min\" SIZE=\"1\">\n".
	  "<OPTION VALUE=0 SELECTED>00</OPTION>\n";
	for my $i (1 .. 59) {
		if ($i < 10) {
			print "<OPTION VALUE=\"0$i\">0$i</OPTION>\n";
		} else {
			print "<OPTION VALUE=\"$i\">$i</OPTION>\n";
		}
	}
	print "</SELECT>\n";

	# Sec
	print ":<SELECT NAME=\"sec\" SIZE=\"1\">\n".
	  "<OPTION VALUE=0 SELECTED>00</OPTION>\n";
	for my $i (1 .. 59) {
		if ($i < 10) {
			print "<OPTION VALUE=\"0$i\">0$i</OPTION>\n";
		} else {
			print "<OPTION VALUE=\"$i\">$i</OPTION>\n";
		}
	}
	print "</SELECT>\n";

	# Type
	print "<BR><BR>Source of Event: <SELECT NAME=\"src\" SIZE=1>\n".
	  "<OPTION VALUE=\"firewall\">firewall</OPTION>\n".
	  "<OPTION VALUE=\"ids\">ids</OPTION>\n".
	  "<OPTION VALUE=\"isp\">isp</OPTION>\n".
	  "<OPTION VALUE=\"log\">log</OPTION>\n".
	  "<OPTION VALUE=\"other\" SELECTED>other</OPTION>\n".
	  "<OPTION VALUE=\"person\">person</OPTION>\n".
	  "</SELECT>\n";

	print "<P><INPUT TYPE=\"IMAGE\" SRC=\"pict/menu_b_ok.jpg\" ".
	  "ALT=\"Ok\" BORDER=\"0\">\n</FORM>\n";

	return 0;
};





#########################################################################
# 
# sorter
#

# sorter frameset
$funcs[$SORTER_MAIN] = sub {
    print_html_header_frameset("Sorter on $args{'img'}");

    print "<FRAMESET COLS=\"20%,80%\">\n";        

    # Block List
    print "<FRAME SRC=\"$PROGNAME?func=$SORTER_LIST&$baseargs\">\n";

    # Blank
    print "<FRAME SRC=\"$PROGNAME?func=$BLANK&$baseargs\" NAME=\"content\">\n".
      "</FRAMESET>\n";

    return 0;
};


# The left-hand frame for running sorter
$funcs[$SORTER_LIST] = sub {
	print_html_header("sorter menu");

	print "<P><A HREF=\"$PROGNAME?func=$SORTER_ENT&$baseargs\" ".
	  "TARGET=\"content\">Sort Files by Type</A>";

	return 0;
};


# Get the data and print the form so that sorter can be run
$funcs[$SORTER_ENT] = sub {
	print_html_header("sorter - enter data to create");

	print "<CENTER>".
	  "<H3>File Type Sortings</H3></CENTER><BR>".
	  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$SORTER_DOIT\">\n".
	  "<INPUT TYPE=\"hidden\" NAME=\"img\" VALUE=\"$args{'img'}\">\n".
	  make_hidden();

	print <<EOF1;
<P>The <B>sorter</B> tool will process an image and organize the
files based on their file type.  The files are organized into categories
that are defined in configuration files.  The categories will be saved
in the <TT>${DATADIR}</TT> directory.  
<HR>
EOF1

	my $sort_dir = get_sorter_dir();
	if (-d "$sort_dir") {
		print "WARNING: This will overwrite any existing data in:<BR>".
		"&nbsp;&nbsp;&nbsp;&nbsp;<TT>$sort_dir</TT><BR>\n";
	}


	my $tab = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";

	print <<EOF2;

<P>
<INPUT TYPE=\"checkbox\" NAME=\"sorter_cat\" VALUE=\"1\" CHECKED>
Sort files into categories by type

  <P>$tab
  <INPUT TYPE=\"checkbox\" NAME=\"sorter_unk\" VALUE=\"1\">
  Do not save data about <TT>unknown</TT> file types

  <P>$tab
  <INPUT TYPE=\"checkbox\" NAME=\"sorter_save\" VALUE=\"1\">
  Save a copy of files in category directory (may require lots of disk space)

  <P>$tab
  <INPUT TYPE=\"checkbox\" NAME=\"sorter_img\" VALUE=\"1\">
  Save ONLY graphic images and make thumbnails <BR>
  $tab (may require lots of disk space and will save to a different directory than sorting all file types)

<P>
<INPUT TYPE=\"checkbox\" NAME=\"sorter_ext\" VALUE=\"1\" CHECKED>
Extension and File Type Validation

EOF2

	if (($NSRLDB ne "") && (-e "$NSRLDB")) {
		print 
		  "<P><INPUT TYPE=\"checkbox\" NAME=\"sorter_nsrl\" VALUE=\"1\" CHECKED>".
		  "Exclude files in the <B>NIST NSRL</B>\n";
	}

	if (($alert_db ne "") && (-e "$alert_db")) {
		print 
		  "<P><INPUT TYPE=\"checkbox\" NAME=\"sorter_alert\" VALUE=\"1\" CHECKED>".
		  "Alert files that are found in the <B>Alert Hash Database</B>\n";
	}

	if (($exclude_db ne "") && (-e "$exclude_db")) {
		print 
		  "<P><INPUT TYPE=\"checkbox\" NAME=\"sorter_exclude\" VALUE=\"1\" CHECKED>".
		  "Ignore files that are found in the <B>Exclude Hash Database</B>\n";
	}

	print 
	  "<P><INPUT TYPE=\"IMAGE\" SRC=\"pict/but_ok.jpg\" ".
	  "ALT=\"Ok\" BORDER=\"0\">\n</FORM>\n";

	return;
};


# Run sorter on the image 
$funcs[$SORTER_DOIT] = sub {
	print_html_header("sorter - create");

	my $sort_args = "";
	my $ext = 0;
	my $cat = 0;

	log_host_inv ("Running 'sorter' on ($args{'img'}");

	$ext = 1 if ((exists $args{'sorter_ext'}) && ($args{'sorter_ext'} == 1));
	$cat = 1 if ((exists $args{'sorter_cat'}) && ($args{'sorter_cat'} == 1));

	if (($cat == 0) && ($ext == 0)) {
		print "At least one action must be selected\n".
		  "<P><A HREF=\"$PROGNAME?func=$SORTER_ENT&$baseargs\">".
		  "<IMG BORDER=0 SRC=\"pict/but_ok.jpg\"></A>\n";

		return;
	}

	# If both actions are wanted then no flags are needed
	$sort_args .= "-e " if (($ext == 1) && ($cat == 0));
	$sort_args .= "-i " if (($ext == 0) && ($cat == 1));

	my $sort_dir = get_sorter_dir();

	if ($cat == 1) {
		if ((exists $args{'sorter_img'}) && ($args{'sorter_img'} == 1)) {
			my $config = "${TASKDIR}/../share/sorter/images.sort";

			print_err ("images configuration file not found ($config)")
			  unless (-e "$config");

			$sort_args .= "-C $config -s -U ";

			$sort_dir = get_sorter_graphics_dir();

		} else {
			$sort_args .= "-s " 
			  if ((exists $args{'sorter_save'}) && ($args{'sorter_save'} == 1));

			$sort_args .= "-U " 
			  if ((exists $args{'sorter_unk'}) && ($args{'sorter_unk'} == 1));
		}
	}

	if ($NSRLDB ne "") {
		$sort_args .= "-n \'$NSRLDB\' "
		  if ((exists $args{'sorter_nsrl'}) && ($args{'sorter_nsrl'} == 1));
	}

	if ($alert_db ne "") {
		$sort_args .= "-a \'$alert_db\' "
		  if ((exists $args{'sorter_alert'}) && ($args{'sorter_alert'} == 1));
	}

	if ($exclude_db ne "") {
		$sort_args .= "-x \'$exclude_db\' "
		  if ((exists $args{'sorter_exclude'}) && ($args{'sorter_exclude'} == 1));
	}

	my $mnt = get_mnt();
	my $fstype = get_ftype();
	my $img = get_img('img');

	unless (-d "$sort_dir") {
    	unless (mkdir "$sort_dir", $MKDIR_MASK) {
			print_err ("Error making $sort_dir");
		}
	}
	if (-e "$sort_dir/index.html") {
		unlink ("$sort_dir/index.html");
	}

	my $exec = "-h -m \'$mnt\' -d \'$sort_dir\' -f $fstype $sort_args \'$img\'";
	print "Executing: <TT>sorter $exec</TT><P>\n";

	# Execute Sorter

	`LANG=C LC_ALL=C \'${TASKDIR}sorter\' $exec`;

	if (-e "$sort_dir/index.html") {
		print "<P>Output can be found by viewing: <TT>$sort_dir/index.html</TT><P>\n".
		  "(Future versions of Autopsy will have built-in viewing capabilities)<BR>\n";


		# Print the index.html file from the output
		print "<HR><CENTER><H3>Results Summary</H3></CENTER>\n";
		open INDEX, "<$sort_dir/index.html" 
		  or die "Can't open sorter index file ($sort_dir/index.html)";

		while (<INDEX>) {
			next if ((/^<HTML><HEAD><TITLE>/i) || 
			  (/^<BODY><CENTER><H2>/i));

			# Extract out the symlinks to the categories
			if (/^\s*<li><A HREF="\.\/[\w\.]+">([\w\s]+)<\/a> \((\d+)\)\s*$/i) {
				print "<LI>$1 ($2)\n";
			}
			# Skip the link on the thumbnails link
			elsif (/^\s*\(<A HREF=[\"\.\/\w]+>thumbnails<\/A>\)\s*$/) {
				print "(thumbnails)\n";
			}
			else {
				print "$_";
			}
		}
		close (INDEX);
	}

	return;
};


#########################################################################
# 
# Hash Databases
#
sub hash_index_md5sum {
	my $db = shift;
	my @out = `\'${TASKDIR}hfind\' -i md5sum \'$db\'`;
	foreach $_ (@out) {
		print "$_<BR>\n";
	}
};

sub hash_index_nsrl {
	my @out = `\'${TASKDIR}hfind\' -i nsrl-md5 \'$NSRLDB\'`;
	foreach $_ (@out) {
		print "$_<BR>\n";
	}
};


# Window from HOST Manager
$funcs[$HASH_MAIN] = sub {
	print_html_header("Hash Database Manager");

print <<EOF;

Hash databases allow Autopsy to quickly identify known files.  This includes
files that are known to be good and those that are known to be bad.  The
'hfind' tool is used to lookup entries in the databases and it needs an
index file for each database.  This window allows one to re-index the
database after it has been updated.  

<P>
To edit the location of the databases, you must manually edit the 
<TT>host.aut</TT> file in the host directory.  

<HR>
<CENTER>
<IMG SRC=\"pict/hashdb_h_alert.jpg\" ALT=\"Alert Database\" BORDER=\"0\">
</CENTER>
<P><B>Overview</B><BR>
These files are known to be <U>bad</U> and are the ones that you want to
know about if they are in the image you are analyzing.  For example,
this database would include hashes of known attacker tools, rootkits,
or photographs.  

EOF
	print "<P><B>Details</B><BR>\n";
	if ($alert_db eq "") {
		print "Location: <TT>Not Configured</TT><BR>\n";
	}
	elsif (-e "$alert_db") {
		print "Location: <TT>$alert_db</TT><BR>\n";
		if (-e "${alert_db}-md5.idx") {
			print "Status: MD5 Index File Exists<BR>\n";
		} else {
			print "Status: Database has not been MD5 indexed<BR>\n";
		}

		# Index Button
		print
		  "<P><A HREF=\"$PROGNAME?func=$HASH_INDEX&hash_alert=1&$baseargs\">".
		  "<IMG SRC=\"pict/but_indexdb.jpg\" ALT=\"Index DB\" BORDER=\"0\">".
		  "</A>\n";

		# Lookup Button
		if (-e "${alert_db}-md5.idx") {
			print
 	  		  "<P><B>Lookup</B><BR>".
			  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">".
			  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$HASH_LOOKUP\">\n".
			  "<INPUT TYPE=\"hidden\" NAME=\"hash_alert\" VALUE=\"1\">\n".
			  make_hidden().
	  		  "<TABLE CELLSPACING=\"10\" CELLPADDING=\"2\">\n<TR>\n".
			  "<TD ALIGN=\"LEFT\">Enter MD5 Value: ".
			  "<INPUT TYPE=\"text\" NAME=\"md5\" SIZE=40 MAXLENGTH=32></TD>\n".
			  "<TD ALIGN=\"LEFT\">".
			  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_lookup.jpg\" ALT=\"Ok\" ".
			  "BORDER=\"0\">\n".
			  "</TD></TR>\n</TABLE>\n".
			  "</FORM>";
		}
	}
	else {
		print "Location: <TT>$alert_db</TT><BR>\n".
		  "ERROR: Database not found<BR>\n";
	}


print <<EOF2;
<HR>
<CENTER>
<IMG SRC=\"pict/hashdb_h_ig.jpg\" ALT=\"Ignore Database\" BORDER=\"0\">
</CENTER>
<P><B>Overview</B><BR>
These files are known to be <U>good</U> and are the ones that you
can ignore if they are found in the image you are analyzing.  For
example, this database would include hashes of known system binaries
and other documents that you do not want to waste time on when running
'sorter' or files that you want to confirm were not modified by an 
attacker.  

EOF2

	print "<P><B>Details</B><BR>\n";
	if ($exclude_db eq "") {
		print "Location: <TT>Not Configured</TT><BR>\n";
	}
	elsif (-e "$exclude_db") {
		print "Location: <TT>$exclude_db</TT><BR>\n";
		if (-e "${exclude_db}-md5.idx") {
			print "Status: MD5 Index File Exists<BR>\n";
		} else {
			print "Status: Database has not been MD5 indexed<BR>\n";
		}

		# Index Button
		print 
		  "<P><A HREF=\"$PROGNAME?func=$HASH_INDEX&hash_exclude=1&$baseargs\">".
		  "<IMG SRC=\"pict/but_indexdb.jpg\" ALT=\"Index DB\" BORDER=\"0\">".
		  "</A>\n";

		# Lookup Button
		if (-e "${exclude_db}-md5.idx") {
			print
			  "<P><B>Lookup</B><BR>".
			  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">".
			  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$HASH_LOOKUP\">\n".
			  "<INPUT TYPE=\"hidden\" NAME=\"hash_exclude\" VALUE=\"1\">\n".
			  make_hidden().
	  		  "<TABLE CELLSPACING=\"10\" CELLPADDING=\"2\">\n<TR>\n".
			  "<TD ALIGN=\"LEFT\">Enter MD5 Value: ".
			  "<INPUT TYPE=\"text\" NAME=\"md5\" SIZE=40 MAXLENGTH=32></TD>\n".
			  "<TD ALIGN=\"LEFT\">".
			  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_lookup.jpg\" ALT=\"Ok\" ".
			  "BORDER=\"0\">\n".
			  "</TD></TR>\n</TABLE>\n".
			  "</FORM>";
		}
	}
	else {
		print "Location: <TT>$exclude_db</TT><BR>\n".
		  "ERROR: Database not found<BR>\n";
	}

print <<EOF3;
<HR>
<CENTER>
<IMG SRC=\"pict/hashdb_h_nsrl.jpg\" ALT=\"NSRL Database\" BORDER=\"0\">
</CENTER>
<P><B>Overview</B><BR>
These files are known to be <U>good</U> and are the ones that you
can ignore if they are found in the image you are analyzing.  NIST
collects these hashes from standard software.  These hashes are used
to validate the integrity of system files and to identify which files
the 'sorter' tool can ignore.  

EOF3

	print "<P><B>Details</B><BR>\n";
	if ($NSRLDB eq "") {
		print "Location: <TT>Not Configured</TT><BR>\n";
	}
	elsif (-e "$NSRLDB") {
		print "Location: <TT>$NSRLDB</TT><BR>\n";
		if (-e "${NSRLDB}-md5.idx") {
			print "Status: MD5 Index File Exists<BR>\n";
		} else {
			print "Status: Database has not been MD5 indexed<BR>\n";
		}

		# Index Button
		print 
		  "<P><A HREF=\"$PROGNAME?func=$HASH_INDEX&hash_nsrl=1&$baseargs\">".
		  "<IMG SRC=\"pict/but_indexdb.jpg\" ALT=\"Index DB\" BORDER=\"0\">".
		  "</A>\n";

		# Lookup Button
		if (-e "${NSRLDB}-md5.idx") {
			print
			  "<P><B>Lookup</B><BR>".
			  "<FORM ACTION=\"$PROGNAME\" METHOD=\"GET\">".
			  "<INPUT TYPE=\"hidden\" NAME=\"func\" VALUE=\"$HASH_LOOKUP\">\n".
			  "<INPUT TYPE=\"hidden\" NAME=\"hash_nsrl\" VALUE=\"1\">\n".
			  make_hidden().
	  		  "<TABLE CELLSPACING=\"10\" CELLPADDING=\"2\">\n<TR>\n".
			  "<TD ALIGN=\"LEFT\">Enter MD5 Value: ".
			  "<INPUT TYPE=\"text\" NAME=\"md5\" SIZE=40 MAXLENGTH=32></TD>\n".
			  "<TD ALIGN=\"LEFT\">".
			  "<INPUT TYPE=\"IMAGE\" SRC=\"pict/but_lookup.jpg\" ALT=\"Ok\" ".
			  "BORDER=\"0\">\n".
			  "</TD></TR>\n</TABLE>\n".
			  "</FORM>";
		}
	}
	else {
		print "Location: <TT>$NSRLDB</TT><BR>\n".
		  "ERROR: Database not found<BR>\n";
	}

print <<EOF4;

<HR><CENTER>
<TABLE WIDTH=600 CELLSPACING=\"0\" CELLPADDING=\"2\">
<TR>
  <TD ALIGN=CENTER>
    <A HREF=\"$PROGNAME?func=$IMG_OPEN&$baseargs\">
    <IMG SRC=\"pict/menu_b_ok.jpg\" ALT=\"Ok\" WIDTH=\"167\" BORDER=\"0\">
    </A>
  </TD>
  <TD ALIGN=CENTER>
    <A HREF=\"$HELP_URL\" TARGET=\"_blank\">
    <IMG SRC=\"pict/menu_b_help.jpg\" ALT=\"Help\" 
    WIDTH=\"167\" BORDER=0>
    </A>
  </TD>
</TR>
</TABLE>
EOF4

	return;
};

$funcs[$HASH_INDEX] = sub {
	print_html_header("Hash Database Indexing");

	if ((exists $args{'hash_exclude'}) && ($args{'hash_exclude'} == 1) && 
	  ($exclude_db ne "")) {
		log_host_info ("Exclude Database Re-Indexed");
		print "<HR><B>Exclude Database Indexing</B><P>\n";
		hash_index_md5sum($exclude_db);
	}

	if ((exists $args{'hash_alert'}) && ($args{'hash_alert'} == 1) && 
	  ($alert_db ne "")) {
		log_host_info ("Alert Database Re-Indexed");
		print "<HR><B>Alert Database Indexing</B><P>\n";
		hash_index_md5sum($alert_db);
	}

	if ((exists $args{'hash_nsrl'}) && ($args{'hash_nsrl'} == 1) && 
	  ($NSRLDB ne "")) {
		log_host_info ("NSRL Database Re-Indexed");
		print "<HR><B>NSRL Database Indexing</B><P>\n";
		hash_index_nsrl();
	}

	print "<P>Indexing Complete<BR>\n".
	  "<HR><P>\n<A HREF=\"$PROGNAME?func=$HASH_MAIN&$baseargs\">\n".
	  "<IMG SRC=\"pict/menu_b_hashdb.jpg\" WIDTH=\"167\" ".
	  "ALT=\"Hash Databases\" BORDER=\"0\"></A>\n";

	return;
};

# Lookup hashes in database
$funcs[$HASH_LOOKUP] = sub {
	print_html_header("Hash Database Lookup");

	unless ((exists $args{'md5'}) && ($args{'md5'} =~ /^$REG_MD5$/o)) {
		print_err("Invalid MD5 Argument");
	}
	
	if ((exists $args{'hash_nsrl'}) && ($args{'hash_nsrl'} == 1) && 
	  ($NSRLDB ne "")) {
		print "<HR><B>NSRL Lookup</B><P>\n";

		if (-e "$NSRLDB") {
			my @out = `\'${TASKDIR}hfind\' \'$NSRLDB\' $args{'md5'}`; 
			foreach $_ (@out) {
				print "$_<BR>\n";
			}
			log_host_inv ("NSRL Lookup ($args{'md5'})");
		}
		else {
			print "NSRL Database Missing<BR>\n";
			log_host_inv ("NSRL Lookup ($args{'md5'}) - Database Missing");
		}
	}

	if ((exists $args{'hash_exclude'}) && ($args{'hash_exclude'} == 1) && 
	  ($exclude_db ne "")) {
		print "<HR><B>Exclude Database Lookup</B><P>\n";

		if (-e "$exclude_db") {
			my @out = `\'${TASKDIR}hfind\' \'$exclude_db\' $args{'md5'}`; 
			foreach $_ (@out) {
				print "$_<BR>\n";
			}
			log_host_inv ("Exclude Database Lookup ($args{'md5'})");
		}
		else {
			print "Exclude Database Missing<BR>\n";
			log_host_inv ("Exclude Database Lookup ($args{'md5'}) - Database Missing");
		}
	}

	if ((exists $args{'hash_alert'}) && ($args{'hash_alert'} == 1) && 
	  ($alert_db ne "")) {
		print "<HR><B>Alert Database Lookup</B><P>\n";

		if (-e "$alert_db") {
			my @out = `\'${TASKDIR}hfind\' \'$alert_db\' $args{'md5'}`; 
			foreach $_ (@out) {
				print "$_<BR>\n";
			}
			log_host_inv ("Alert Database Lookup ($args{'md5'})");
		}	
		else {
			print "Alert Database Missing<BR>\n";
			log_host_inv ("Alert Database Lookup ($args{'md5'}) - Database Missing");
		}
	}

	print "<HR><P>\n".
	  "If any of the hash databases need to be re-indexed, use the ".
	  "<U>Hash Database Manager</U><P>".
	  "<A HREF=\"$PROGNAME?func=$HASH_MAIN&$baseargs\" TARGET=\"_blank\">\n".
	  "<IMG SRC=\"pict/menu_b_hashdb.jpg\" WIDTH=\"167\" ".
	  "ALT=\"Hash Databases\" BORDER=\"0\"></A>\n";

	return 0;
};


#########################################################################
# 
# CELL - Sanitized Environment
#

my $CELL_MODE_SANIT = 1;
my $CELL_MODE_NORM = 2;

$funcs[$CELL_MAIN] = sub {
	check_inode('inode'); check_dir(); 
	my $fname = "$args{'mnt'}$args{'dir'}";
    print_html_header_frameset("Autopsy Cell");

    print "<FRAMESET ROWS=\"15%,85%\">\n";        

	# if a mode was not given, then choose the Sanitized by default
	$args{'cell_mode'} = $CELL_MODE_SANIT 
	  unless ((exists $args{'cell_mode'}) && ($args{'cell_mode'} =~ /^\d$/));

	my $url = "&$baseargs&inode=$enc_args{'inode'}&dir=$enc_args{'dir'}&".
	  "cell_mode=$args{'cell_mode'}";

    print "<FRAME SRC=\"$PROGNAME?func=${CELL_MENU}${url}\">\n".
      "<FRAME SRC=\"$PROGNAME?func=${CELL_CONT}${url}\">\n".
      "</FRAMESET>\n";

    return 0;
};

# Print the menu on top.  This allows one to export the file and change modes
$funcs[$CELL_MENU] = sub {
	check_inode('inode'); check_dir(); check_cell_mode();
	print_html_header ("Cell Header");

	my $cell_mode = $args{'cell_mode'};

	my $url = "&$baseargs&inode=$enc_args{'inode'}&".
	  "dir=$enc_args{'dir'}";

	if ($cell_mode == $CELL_MODE_SANIT) {

print <<EOF1;
<CENTER>
This file is currently being viewed in a <B>sanitized environment</B><BR>
HTML files have been edited to disable scripts and links.  
Pictures have been replaced by place holders<BR>

<TABLE WIDTH=300 CELLSPACING=\"0\" CELLPADDING=\"2\">
<TR>
  <TD ALIGN=CENTER>
    <A HREF=\"$PROGNAME?func=$CELL_MAIN$url&cell_mode=$CELL_MODE_NORM\" 
      TARGET=\"_top\">
	  <IMG SRC=\"pict/sanit_b_norm.jpg\" ALT=\"Normal\" BORDER=\"0\">
	</A>
  </TD>
EOF1

	}

	elsif ($cell_mode == $CELL_MODE_NORM) {
print <<EOF2;
<CENTER>
This file is currently being viewed in a <B>normal environment</B><BR>
HTML files are being viewed without modification.<BR>

<TABLE WIDTH=300 CELLSPACING=\"0\" CELLPADDING=\"2\">
<TR>
  <TD ALIGN=CENTER>
    <A HREF=\"$PROGNAME?func=$CELL_MAIN$url&cell_mode=$CELL_MODE_SANIT\" 
      TARGET=\"_top\">
	  <IMG SRC=\"pict/sanit_b_san.jpg\" ALT=\"Sanitized\" BORDER=\"0\">
	</A>
  </TD>
EOF2
	}

	# Export the file
	print "<TD ALIGN=CENTER>\n".
	  "<A HREF=\"$PROGNAME?func=$FIL_SAVE&$url\">".
	  "<IMG SRC=\"pict/but_export.jpg\" ALT=\"export\" BORDER=\"0\">".
	  "</A></TD></TR></TABLE>";

	return;
};


# Display safe and common things in the browser (pictures, basic html)
$funcs[$CELL_CONT] = sub {
	check_inode('inode'); check_dir(); check_cell_mode();

	my $inode = get_inode('inode');
	my $img = get_img('img');
	my $ftype = get_ftype();
	my $fname = "$args{'mnt'}$args{'dir'}";

	# identify what type it is
	my $file_type = 
	  `\'${TASKDIR}icat\' -f $ftype \'$img\' $inode | \'${TASKDIR}file\' -b -`;
	if ($file_type =~ /JPEG image data/) {
		log_host_inv ("$args{'img'}: Viewing $fname ($inode) as JPEG");
		print "Content-type: image/jpeg${HTTP_NL}${HTTP_NL}";
	}
	elsif ($file_type =~ /GIF image data/) {
		log_host_inv ("$args{'img'}: Viewing $fname ($inode) as GIF");
		print "Content-type: image/gif${HTTP_NL}${HTTP_NL}";
	}
	elsif ($file_type =~ /PNG image data/) {
		log_host_inv ("$args{'img'}: Viewing $fname ($inode) as PNG");
		print "Content-type: image/png${HTTP_NL}${HTTP_NL}";
	}
	elsif ($file_type =~ /PC bitmap data/) {
		log_host_inv ("$args{'img'}: Viewing $fname ($inode) as BMP");
		print "Content-type: image/bmp${HTTP_NL}${HTTP_NL}";
	}
	elsif ($file_type =~ /HTML document text/) {
		log_host_inv ("$args{'img'}: Viewing $fname ($inode) as HTML");
		print "Content-type: text/html${HTTP_NL}${HTTP_NL}";
	}
	else {
		log_host_inv ("$args{'img'}: Unknown format of inode $inode ");
		print_html_header("");
		print "Unknown File Type for Viewing: $file_type\n";
		return 1;
	}

	my @out =`\'${TASKDIR}icat\' -f $ftype \'$img\' $inode`;

	# Parse out bad "stuff"
	if (($file_type =~ /HTML document text/) && 
	  ($args{'cell_mode'} == $CELL_MODE_SANIT)) {
		my $line;
		foreach $line (@out) {
			$line =~ s/\bSRC=/SRC=$SANITIZE_TAG\?/ig;
			$line =~ s/\bHREF=/HREF=$SANITIZE_TAG\?/ig;
			$line =~ s/<script/<$SANITIZE_TAG-script/ig;
			$line =~ s/\bBACKGROUND=/BACKGROUND=$SANITIZE_TAG\?/ig;
		}
	}
	
	print @out;

	return 0;
};


##### Begin main ############

sub autopsy_main {
	# Parse arguments
	my $args = shift;
	foreach my $nam_val (split (/&/, $args)) {
		my ($name, $value) = split (/=/, $nam_val);
		if (defined $value) {
			my $dec_name = url_decode($name);
			$enc_args{$dec_name} = $value;
			$args{$dec_name} = url_decode($value);
		}
	}

	if (exists $args{'case'}) {
		check_case();
		$case_dir = "${LOCKDIR}/".get_case()."/";

		if (exists $args{'host'}) {
			check_host();
			$host_dir = "$case_dir".get_host()."/";
			read_host_config() if ($args{'func'} != $HOST_ADD_DOIT);
		}
	}


	if (check_func()) {
		# No func value was given or an invalid one was given

		if (exists $args{'func'}) {
			print_html_header();
			print "Invalid func argument (positive numbers only)<BR>\n";
		}
		else {
			# give the main menu if no func value was given
			& {$funcs[$WELCOME]};
		}

		print "${HTTP_NL}${HTTP_NL}";
		return 0;
	}

	# These functions do not need any arguments
	if (
		($args{'func'} == $WELCOME) || 
		($args{'func'} == $BLANK) || 
		(($args{'func'} >= $CASE_LO) && ($args{'func'} <= $CASE_HI)) ) {

	}

	# need the case value
	elsif (($args{'func'} >= $HOST_LO) && ($args{'func'} <= $HOST_HI)) {
		check_case();
	}

	# need the case and host
	elsif ( (($args{'func'} >= $IMG_LO) && ($args{'func'} <= $IMG_HI)) ||
	  (($args{'func'} >= $NOTES_LO) && ($args{'func'} <= $NOTES_HI)) ||
	  (($args{'func'} >= $TL_LO) && ($args{'func'} <= $TL_HI))  ||
	  (($args{'func'} >= $HASH_LO) && ($args{'func'} <= $HASH_HI))  ||
	  ($args{'func'} == $INT_LIST)  || ($args{'func'} == $INT_LIST_FR)) {
		check_case();
		check_inv();
		check_host();
	}
	# Int doesn't need the ftype because it gets messed up with body and
	# timelines and such
	elsif(($args{'func'} >= $INT_LO) && ($args{'func'} <= $INT_HI)) {
		check_case();
		check_inv();
		check_host();
		check_img('img'); 
	}
	# FIL, BLK, SRCH, INO, FS, INT, CASE
	else {
		check_case();
		check_inv();
		check_host();
		check_img('img'); 
		check_ftype();

	}

	# special case of the strings and dls output
	if ((exists $img2ftype{$args{'img'}}) && 
	  (($img2ftype{$args{'img'}} eq "strings") || 
	  ($img2ftype{$args{'img'}} eq "dls")) ) {

		unless (
		  (($args{'func'} >= $SRCH_LO) && ($args{'func'} <= $SRCH_HI)) ||
		  (($args{'func'} >= $BLK_LO) && ($args{'func'} <= $BLK_HI)) ||
		  (($args{'func'} >= $NOTES_LO) && ($args{'func'} <= $NOTES_HI)) ||
		  (($args{'func'} >= $MAIN_LO) && ($args{'func'} <= $MAIN_HI)) ||
		  (($args{'func'} >= $IMG_LO) && ($args{'func'} <= $IMG_HI)) ||
		  ($args{'func'} == $BLANK) ||
		  (($args{'func'} >= $INT_LO) && ($args{'func'} <= $INT_HI)) ) {

			print_html_header();
			print "Error: You selected a non-file system image ".
			  "that can only be used for Searching and data unit browsing<BR>\n";
	
			make_baseargs();

			print "<BR><A HREF=\"$PROGNAME?$baseargs&func=$IMG_OPEN\"".
			  "TARGET=\"_top\">Return to Host Manager</A><BR>";

			exit 1;
		}
		$enc_args{'mnt'} = "";
	}
	elsif ((exists $img2ftype{$args{'img'}}) && 
	  (($img2ftype{$args{'img'}} eq "body") || 
	  ($img2ftype{$args{'img'}} eq "timeline")) ) {

		# this is just a dummy section to exclude the timeline files
		# from the next check of mounting point 
	}

	#  if the mounting point was not found, then look it up
	elsif ((exists $args{'img'}) && (!exists $args{'mnt'})) {
		unless (exists $img2mnt{$args{'img'}}) {
			print_html_header();
			print "Mounting point not found: $args{'img'}\n";
			exit 1;
		}
		$args{'mnt'} = $img2mnt{$args{'img'}};
		$enc_args{'mnt'} = url_encode($img2mnt{$args{'img'}});
	}

	make_baseargs();
	& {$funcs[$args{'func'}]};

	print "\n</BODY>\n" if ($is_body == 1);
	print "\n</HTML>\n" if ($is_html == 1);

	print "${HTTP_NL}${HTTP_NL}";
	return 0;
}

# This assumes that the checking of the types has been done and this just
# makes a string of the key values if they exist
#
#  case
#  host
#  img

# Must add & after
sub make_baseargs {
	$baseargs = "";

	$baseargs .= "case=$enc_args{'case'}&" 
	  if ((exists $enc_args{'case'}) && ($enc_args{'case'} ne ""));
	$baseargs .= "host=$enc_args{'host'}&" 
	  if ((exists $enc_args{'host'}) && ($enc_args{'host'} ne ""));
	$baseargs .= "inv=$enc_args{'inv'}&" 
	  if ((exists $enc_args{'inv'}) && ($enc_args{'inv'} ne ""));
	
	$baseargs_noimg = $baseargs;

	$baseargs .= "img=$enc_args{'img'}&" 
	  if ((exists $enc_args{'img'}) && ($enc_args{'img'} ne ""));
	$baseargs .= "ftype=$enc_args{'ftype'}&" 
	  if ((exists $enc_args{'ftype'}) && ($enc_args{'ftype'} ne ""));
	$baseargs .= "mnt=$enc_args{'mnt'}&" 
	  if ((exists $enc_args{'mnt'}) && ($enc_args{'mnt'} ne ""));

	# remove the final '&'
	$baseargs_noimg = $1 if ($baseargs_noimg =~ /^(.*?)&$/);
	$baseargs = $1 if ($baseargs =~ /^(.*?)&$/);

	return;
};



# Does not do mnt or img
sub make_hidden {
	my $str = "";

	$str .= "<INPUT TYPE=\"hidden\" NAME=\"host\" VALUE=\"$args{'host'}\">\n"
	  if ((exists $args{'host'}) && ($args{'host'} ne ""));

	$str .= "<INPUT TYPE=\"hidden\" NAME=\"case\" VALUE=\"$args{'case'}\">\n"
	  if ((exists $args{'case'}) && ($args{'case'} ne ""));

	$str .= "<INPUT TYPE=\"hidden\" NAME=\"inv\" VALUE=\"$args{'inv'}\">\n"
	  if ((exists $args{'inv'}) && ($args{'inv'} ne ""));

	return $str;
}


#########################################################################3
#
# Config Files
#
#

# Return a hash of the keywords and the values
sub read_case_config {
	my $case;

    if (scalar (@_) == 1) {
	    $case = shift;
	} else {
		$case = get_case();
	}

	my $fname = case_config_fname($case);

	open CONFIG, "<$fname" 
	  or die "Can't open case config file ($fname)";

	my %vals;

	while (<CONFIG>) {
        next if ((/^\#/) || (/^\s+$/));
		s/^\s+//;
		s/\s+$//;
		$vals{$1} = $2 if (/^(\S+)\s+(.*)$/);
	}
	close CONFIG;

	$vals{'desc'} = "None Provided" unless (exists $vals{'desc'});
	$vals{'created'} = "unknown" unless (exists $vals{'created'});

	$vals{'images'} = $IMGDIR unless (exists $vals{'images'});
	$vals{'data'} = $DATADIR unless (exists $vals{'data'});
	$vals{'log'} = $LOGDIR unless (exists $vals{'log'});
	$vals{'reports'} = $REPDIR unless (exists $vals{'reports'});

	return %vals;
};


# reads host config file and sets global hash values for images and other
sub read_host_config {
	my $host = get_host();

	my $cfile = host_config_fname();

	unless (open (FILE, $cfile)) { 
		print_check_err("Error opening $cfile");
	}

	%img2mnt = ();
	%img2ftype = ();
	%mod2img = ();
	%img2str = ();
	%img2dls = ();
	
	$tz = "";
	$ts = 0;
	$host_desc = "";
	$exclude_db = "";
	$alert_db = "";

	while (<FILE>) {
		next if ((/^\#/) || (/^\s+$/));

		# remove whitespace
		s/^\s+//;      
		s/\s+$//;

		# normal file system image entry
		#
		# 'image	images/hda1.dd		openbsd		/usr
		if (/^image\s+($REG_IMG)\s+([\w\-]+)\s+([\w\-\_\.\/:\\]+)$/o) {
			my $i = $1;
			my $t = $2;
			my $r = $3;

			unless (defined $root_inode{$t}) {
				print_check_err("Error: unknown type: $t in host config: $.".
				  "<BR>Edit the file and refresh your browser");
			}

			unless ((-e "${host_dir}${i}") || (-l "${host_dir}${i}")) {
				print_check_err("Error: image in ${host}.host:$. not found: ".
				  "${host_dir}${i}<BR>Edit the config file and refresh your browser".
				  "<BR>(Or your version of Perl does not support large files)");
			}

			$img2ftype{$i} = $t;

			# Add trailing / to original mount point if needed
			if (($r !~ /.*?\/$/) && ($r !~ /.*?\\$/)) {
				$r .= '/';
			}
			$img2mnt{$i} = $r;
		}
		# entry for a strings or dls file
		#
		# strings 	data/hda1.str		images/hda1.dd
		elsif (/^strings\s+($REG_IMG)\s+($REG_IMG)$/o) {
			my $i = $1;
			my $o = $2;

			unless ((-e "${host_dir}${i}") || (-l "${host_dir}${i}")) {
				print_check_err("Error: strings file not found: ".
				  "${host_dir}${i}<BR>Edit host config and refresh your browser");
			}

			unless ((-e "${host_dir}${o}") || (-l "${host_dir}${o}")) {
				print_check_err("Error: strings original not found: ".
				  "${host_dir}${o}<BR>Edit host config and refresh your browser");
			}

			$img2ftype{$i} = "strings";
			$mod2img{$i} = $o;
			$img2str{$o} = $i;
		}

		# dls entry
		# dls data/image.dls	[images/image.dd]
		elsif (/^dls\s+($REG_IMG)\s*($REG_IMG)?$/o) {
            my $dls = $1;
 
			unless ((-e "${host_dir}${dls}") || (-l "${host_dir}${dls}")) {
				print_check_err("Error: dls file not found: ".
				  "${host_dir}${dls}<BR>Edit host config and refresh your browser");
			}
     
            $img2ftype{$dls} = "dls";
    
            if (defined $2) {
                my $dd = $2;
				
				unless ((-e "${host_dir}${dd}") || (-l "${host_dir}${dd}")) {
					print_check_err("Error: dls original not found: ".
					  "${host_dir}${dd}<BR>Edit host config and refresh your browser");
				}

                $mod2img{$dls} = $dd;
				$img2dls{$dd} = $dls;
            }

		}
		# body data/body.txt
		elsif (/^body\s+($REG_IMG)$/o) {
            my $i = $1;
 
			unless ((-e "${host_dir}${i}") || (-l "${host_dir}${i}")) {
				print_check_err("Error: body file not found: ".
				  "${host_dir}${i}<BR>Edit host config and refresh your browser");
			}

			$img2ftype{$i} = "body";
		}
		# timeline data/timeline.txt
		elsif (/^timeline\s+($REG_IMG)$/o) {
            my $i = $1;

			unless ((-e "${host_dir}${i}") || (-l "${host_dir}${i}")) {
				print_check_err("Error: timeline file not found: ".
				  "${host_dir}${i}<BR>Edit host config and refresh your browser");
			}
 
			$img2ftype{$i} = "timeline";
		}
		# timezone XYZ
		elsif (/^timezone\s+($REG_ZONE1)$/o) {
			$tz = $1;	
		}
		# timeskew XYZ
		elsif (/^timeskew\s+($REG_SKEW)$/o) {
			$ts = $1;	
		}
		# desc XYZ
		elsif (/^desc\s+(.*)$/) {
			$host_desc = $1;	
		}
		# hash databases
		elsif (/^alert_db\s+'(.*)'$/) {
			$alert_db = $1;
		}
		elsif (/^exclude_db\s+'(.*)'$/) {
			$exclude_db = $1;
		}
		else {
			my $msg = "Error: invalid entry in $cfile:$.".
			  "<BR>\n".
			  "image	path	fs_type		mnt_point<BR>\n".
			  "strings	path	orig_img<BR>\n".
			  "dls		path	[orig_img]<BR>\n".
			  "body		path<BR>\n".
			  "timeline	path<BR>\n".
			  "timezone	TZ<BR>\n".
			  "desc		DESCRIPTION<BR>\n";
			print_check_err($msg);
		}
	}
	close (FILE);

	if ($tz eq "") {
		print_check_err ("Missing Timezone Variable in Host Config");
	}
}


# Remove any entries with the given image name from the host config
# and add a new one
#
# If type is "", then nothing is written, just removed
sub update_host_config {
	my $type = shift;
    my $img = shift;
    my $ref = shift;

    my $read = host_config_fname();
    my $write = $read."-".rand();

    unless (open (READ, "<$read")) {
        print "Error opening $read";
        exit (1);
    }

    unless (open (WRITE, ">$write")) {
        print "Error opening $write";
        exit (1);
    }

    while (<READ>) {
		s/^\s+//;
		s/\s+$//;
        print WRITE "$_\n" unless ((/^(\w+)\s+($REG_IMG)\s+/o) && ($2 eq $img)
          && ($1 ne 'desc') && ($1 ne 'timezone'));
    }

	if ($type ne "") {
		if (defined $ref) {
			print WRITE "$type  $img    $ref\n";
		} else {
			print WRITE "$type  $img\n";
		}
	}

    close (READ);
    close (WRITE);
    rename $write, $read;

    return;
};



# Given the image and md5, it is saved to the MD5.txt file and any other
# references to the image are removed
#
# if $md5 is "", then nothing is written
sub update_md5 {
	my $img = shift;
    my $md5 = shift;
	$md5 =~ tr/[a-f]/[A-F]/;

	(my $img_dir) = split (/\//,$img);
    my $read = "${host_dir}/$img_dir/${MD5_FILE}";
    my $write = $read."-".rand();
    
    unless (open (WRITE, ">$write")) {
        print "Error opening $write";
		exit (1);
    }

	if (-e "$read") {
		unless (open (READ, "<$read")) {
			print "Error opening $read";
			exit (1);
		}

		while (<READ>) {
			s/^\s+//;
			s/\s+$//;
			print WRITE "$_\n" unless ((/^$REG_MD5\s+($REG_IMG)/o) && ($1 eq $img));
		}
		close (READ);
	}

	print WRITE "$md5   $img\n" if ($md5 ne "");

	close (WRITE);

	rename $write, $read;
	return;
}





# Write the login name to the investigators file
sub write_invest {
	my $name = shift;
	my $fname = investig_fname();
	open INVES, ">>$fname" or die "Can't open investigators file: $fname";
	if ($name =~ /^$REG_INVESTIG$/o) {
		print INVES "$name\n";
	} else {
		print_err ("Invalid investigator: $name");
	}
	close INVES;
}


# Read the investigators file and return a sorted list
sub read_invest {
	my $fname = investig_fname();
	open INVES, "<$fname" or return;

	my @investigs;
	while (<INVES>) {
		chomp;
		s/^\s+//;
        s/\s+$//;
		push @investigs, $_
		  if (/^$REG_INVESTIG$/o);
	}
	close INVES;  
	sort {lc($a) cmp lc($b)}  @investigs;
}


#### END OF MAIN ####


# if no args are passed, return case config using args{'case'},
# else use the case value passed
#
# Case config:
# In case directory with case_name.case
sub case_config_fname {
	if (scalar (@_) == 1) {
		my $c = shift;
		return "${LOCKDIR}$c/case.aut";
	} else {
		return "${LOCKDIR}$args{'case'}/case.aut";
	}
}

# Case log
# In case directory with case_name.log
sub case_log_fname {
	return "${case_dir}/case.log";
}

# File of investigators name in list
sub investig_fname {
	return "${case_dir}/investigators.txt";
}


sub investig_notes_fname {
	return "${host_dir}/logs/".$args{'inv'}.".notes";
}

sub investig_seq_notes_fname {
	return "${host_dir}/logs/".$args{'inv'}.".seq.notes";
}

sub investig_log_fname {
	return "${host_dir}/$LOGDIR/$args{'inv'}.log";
}

sub host_log_fname {
	return "${host_dir}/$LOGDIR/host.log";
}


# if no args are passed, return host config using args{'host'},
# else use the host value passed
sub host_config_fname {
	if (scalar (@_) == 1) {
		my $h = shift;
		return "${case_dir}$h/host.aut";
	} else {
    	return "${host_dir}host.aut";
	}
}

###################### INPUT CHECKS ######################3


#
# Arguments
#
sub check_func {
	if ((!exists $args{'func'}) || ($args{'func'} !~ /^\d+$/) ||
 	  (!(defined $funcs[$args{'func'}])) )  {
		return 1;
	}
	return 0;
}

# We don't allow much for the image because this is an argument to
# the TASK programs.  We keep these files only in one
# directory and for easy/simple security only allow basic names
# Symbolic links are allowed if these simple names are not desired
#
# Allowed values are A-Za-z0-9_-.
sub check_img {
	my $img = shift;

	if (!exists $args{$img}) {
		print_check_err ("Missing image ($img) argument");
	} 
	elsif ($args{$img} =~ /^$REG_IMG$/o) {
		# Check for its actual existence

		print_check_err("Missing image in host dir ($img): $args{$img}")
		  unless ((-e "${host_dir}$args{$img}") 
		  || (-l "${host_dir}$args{$img}"));

		print_check_err("Invalid directory in image name")
		  if (($args{$img} =~ /^\//) || ($args{$img} =~ /^\.\./));
	}
	else {
		print_check_err ("Invalid image ($img) value (only letters, ".
		  "numbers,-,.,_) [$args{$img}]");
	}

	return 0;
}


# Return the full path of the image
sub get_img {
	my $img_cat = shift;
	if ($args{$img_cat} =~ /^($REG_IMG)$/o) {
		return "${host_dir}$1";
	}
	return 0;
}


# img_path is used when adding images - it is the full path to the 
# non-evidence locker copy of the image
sub check_img_path {
	if (!exists $args{'img_path'}) {
		print_check_err ("Missing image (img_path) argument");
	} 
	elsif ($args{'img_path'} =~ /^$REG_IMG_PATH$/o) {
		# Check for its actual existence

		print_check_err("Image not found at $args{'img_path'}")
		  unless ((-e "$args{'img_path'}") 
		  || (-l "$args{'img_path'}"));
	}
	else {
		print_check_err ("Invalid image path (only letters, ".
		  "numbers,-,.,_/ and start with /) [$args{'img_path'}]");
	}

	return 0;
}

sub get_img_path {
	if ($args{'img_path'} =~ /^($REG_IMG_PATH)$/o) {
		return "$1";
	}
	return 0;
}


# Case name
sub check_case {
	unless (exists $args{'case'}) {
		print_check_err ("Missing case argument");
	} 
	unless ($args{'case'} =~ /^$REG_CASE$/o) {
		print_check_err ("Invalid case value (letters, num, and symbols only");
	}
	return 0;
}

sub get_case {
	if ($args{'case'} =~ /^($REG_CASE)$/o) {
		return $1;
	}
	return 0;
}

# Host name
sub check_host {
	unless (exists $args{'host'}) {
		print_check_err ("Missing host argument");
	} 
	unless ($args{'host'} =~ /^$REG_HOST$/o) {
		print_check_err ("Invalid host value");
	}
	return 0;
}

sub get_host {
	if ($args{'host'} =~ /^($REG_HOST)$/o) {
		return $1;
	}
	return 0;
}


sub check_inv {
	unless (exists $args{'inv'}) {
		print_check_err ("Missing inv argument");
	} 
	unless ($args{'inv'} =~ /^$REG_INVESTIG$/o) {
		print_check_err ("Invalid inv value (letters, num, and symbols only");
	}
	return 0;
}

sub get_inv {
	if ($args{'inv'} =~ /^($REG_INVESTIG)$/o) {
		return $1;
	}
	return 0;
}



sub check_fname {
	unless (exists $args{'fname'}) {
		print_check_err ("Missing fname argument");
	} 
	unless ($args{'fname'} =~ /^$REG_FNAME$/o) {
		print_check_err ("Invalid fname value (only letters, ".
		  "numbers,-,., and _)");
	}
	return 0;
}

sub get_fname {
	if ($args{'fname'} =~ /^($REG_FNAME)$/o) {
		return "${host_dir}${DATADIR}/$1";
	}
	return 0;
}


# Return the relative fname
sub get_fname_rel {
	if ($args{'fname'} =~ /^($REG_FNAME)$/o) {
		return "$DATADIR/$1";
	}
	return 0;
}

sub check_body {
	unless (exists $args{'body'}) {
		print_check_err ("Missing body argument");
	} 
	unless ($args{'body'} =~ /^$REG_BODY$/o) {
		print_check_err ("Invalid body value (only letters, ".
		  "numbers,-,., and _)");
	}
	return 0;
}

sub get_body {
	if ($args{'body'} =~ /^($REG_BODY)$/o) {
		return "${host_dir}${DATADIR}/$1";
	}
	return 0;
}

sub check_tl {
	if (!exists $args{'tl'}) {
		print_check_err ("Missing timeline argument");
	} 
	elsif ($args{'tl'} =~ /^($REG_TL)$/o) {

		# Check for its actual existence
		unless ((-e "${host_dir}${DATADIR}/$1") || 
		  (-l "${host_dir}${DATADIR}/$1")) {
			print_check_err("Missing timeline: ${host_dir}${DATADIR}/$1");
		}
	}
	else {
		print_check_err ("Invalid timeline value (only letters, ".
		  "numbers,-,., and _)");
	}
	return 0;
}

sub get_tl {
	if ($args{'tl'} =~ /^($REG_TL)$/o) {
		return "${host_dir}${DATADIR}/$1";
	}
	return 0;
}

sub check_fname_mode {
	if (!exists $args{'fname_mode'}) {
		print_check_err ("Missing fname_mode argument");
	} 
	unless ($args{'fname_mode'} =~ /^\d+$/) {
		print_check_err ("invalid mode: numbers only");
	}
	return 0;
}


sub get_sorter_dir {
	if ($args{'img'} =~ /^.*?\/(.*)$/) {
		return "${host_dir}${DATADIR}/sorter-$1/";
	}
	return 0;
}

sub get_sorter_graphics_dir {
	if ($args{'img'} =~ /^.*?\/(.*)$/) {
		return "${host_dir}${DATADIR}/sorter-graphics-$1/";
	}
	return 0;
}


sub check_dir {
	if ((!exists $args{'dir'}) ||
	  ($args{'dir'} =~ /\/\.\.\//) ||
	  ($args{'dir'} =~ /\;/) ) {
		print_check_err("Invalid dir argument (valid file path only)");
	}
	return 0;
}

sub get_dir {
	if ($args{'dir'} =~ /([^;]*)/o) {
		return $1;
	}
	return 0;
}

sub check_mnt {
	if (!exists $args{'mnt'}) {
		print_check_err("Missing mount point argument");
	}
	elsif ($args{'mnt'} =~ /\/\.\.\//) {
		print_check_err("Invalid mount point argument (valid file path only)");
	}
	unless ($args{'mnt'} =~ /^$REG_MNT$/o) {
		print_check_err("Invalid mount point argument (valid file path only)");
	}
	return 0;
}

sub get_mnt {
	if ($args{'mnt'} =~ /($REG_MNT)/o) {
		return $1;
	}
	return 0;
}

sub check_inode {
	my $inode = shift;
	if ((!exists $args{$inode}) || ($args{$inode} !~ /^$REG_INODE$/o) ||
	  ($args{$inode} < 0)) {
		print_check_err("Invalid inode ($inode) argument (numbers >= 0 only)");
	}
	return 0;
}

# We can only have positive numbers
sub get_inode {
	my $inode = shift;
	if ($args{$inode} =~ /^($REG_INODE)$/o) {
		return $1;
	}
	return 0;
}

sub get_force {
	if ($args{'force'} =~ /^(\d+)$/) {
		return $1;
	}
	return 0;
}

sub check_block {
	if ((!exists $args{'block'}) || ($args{'block'} !~ /^\d+$/)) {
		print_check_err("Invalid block argument (positive numbers only)");
	}
	return 0;
}

sub get_block {
	if ($args{'block'} =~ /^(\d+)$/) {
		return $1;
	}
	return 0;
}

sub check_cell_mode {
	if ((!exists $args{'cell_mode'}) || ($args{'cell_mode'} !~ /^\d$/o)) { 
		print_check_err("Invalid cell_mode argument (numbers >= 0 only)");
	}
	return 0;
}


sub check_len {
	if ((!exists $args{'len'}) || ($args{'len'} !~ /^\d+$/)) {
		print_check_err("Invalid len argument (positive numbers only)");
	}
	return 0;
}

sub get_len  {
	if ((exists $args{'len'}) && ($args{'len'} =~ /^(\d+)$/)) {
		return $1;
	}
	# return the default len of 1 if it is not defined
	return 1;
}

sub check_sort {
	if ((!exists $args{'sort'}) || ($args{'sort'} !~ /^\d+$/)) {
		print_check_err("Invalid sort argument (positive numbers only)");
	}
	return 0;
}

sub get_sort {
	if ($args{'sort'} =~ /^(\d+)$/) {
		return $1;
	}
	return 0;
}


# ifind is optional and by default is 0 if not given
sub get_ifind {
	if (!exists $args{'ifind'}) {
		return 0;
	}
	elsif ($args{'ifind'} =~ /^(\d+)$/) {
		return $1;
	}
	return 0;
}

sub check_mode {
	if ((!exists $args{'mode'}) || ($args{'mode'} !~ /^\d+$/)) {
		print_check_err("Invalid mode argument (positive numbers only)");
	}
	return 0;
}

sub get_mode {
	if ($args{'mode'} =~ /^(\d+)$/) {
		return $1;
	}
	return 0;
}

sub check_dmode {
	if ((!exists $args{'dmode'}) || ($args{'dmode'} !~ /^\d+$/)) {
		print_check_err("Invalid dmode argument (positive numbers only)");
	}
	return 0;
}

sub get_dmode {
	if ($args{'dmode'} =~ /^(\d+)$/) {
		return $1;
	}
	return 0;
}

sub get_min {
	if ($args{'min'} =~ /^(\d+)$/) {
		return $1;
	}
	return 0;
}

sub check_htype {
	if ((!exists $args{'htype'}) || ($args{'htype'} !~ /^\d+$/)) {
		print_check_err("Invalid htype argument (positive numbers only)");
	}
	return 0;
}

sub get_htype {
	if ($args{'htype'} =~ /^(\d+)$/) {
		return $1;
	}
	return 0;
}



# This should be made more flexible
sub check_str {
	if (!exists $args{'str'}) {
		print_check_err("Missing string argument");
	}
	return 0;
}

# Get the string to search for with grep
# This should be made more flexible
sub get_str {
	if ($args{'str'} =~ /^\s*(.*)$/) {
		return $1;
	}
	return 0;
}


# Index for previous keyword search
sub check_srchidx {
	if ((!exists $args{'srchidx'}) || ($args{'srchidx'} !~ /^\d+$/)) {
		print_check_err("Invalid srchidx argument (positive numbers only)");
	}
	return 0;
}


sub check_tz {
	if ((!exists $args{'tz'}) || ($args{'tz'} !~ /^$REG_ZONE1$/o)) {
		print_check_err("Missing time zone argument");
	}
	return 0;
}

sub get_tz {
	if ($args{'tz'} =~ /^\s*($REG_ZONE1)$/o) {
		return $1;
	}
	return 0;
}

sub check_do_md5 {
	if ((!exists $args{'do_md5'}) || ($args{'do_md5'} !~ /^\d+$/)) {
		print_check_err("Missing do_md5 argument");
	}
	return 0;
}

sub get_do_md5 {
	if ($args{'do_md5'} =~ /^\s*(\d+)$/) {
		return $1;
	}
	return 0;
}

sub check_ts {
	if ((!exists $args{'ts'}) || ($args{'ts'} !~ /^$REG_SKEW$/o)) {
		print_check_err("Missing time skew argument");
	}
	return 0;
}

sub get_ts {
	if ($args{'ts'} =~ /^\s*($REG_SKEW)$/o) {
		return $1;
	}
	return 0;
}

sub check_note {
	if (!exists $args{'note'}) {
		print_check_err("Missing note argument");
	}
	return 0;
}

sub check_ftype {
	unless (((exists $img2ftype{$args{'img'}}) &&
	  ($img2ftype{$args{'img'}} =~ /^$REG_FTYPE$/o)) || 
	  ((exists $args{'ftype'}) && 
	  ($args{'ftype'} =~ /^$REG_FTYPE$/o)) ) {
		print_check_err("Missing or invalid ftype value");
	}
	return 0;
}

sub get_ftype {
	unless ((exists $args{'img'}) && (exists $img2ftype{$args{'img'}})) {
		if (exists $args{'ftype'}) {
			if ($args{'ftype'} =~ /^($REG_FTYPE)$/o) {
				return $1;
			}
			return 0;
		}
		print_check_err("Missing ftype value");
	}
	return $img2ftype{$args{'img'}};
}


sub check_st_mon {
	if ((exists $args{'st_mon'}) && ($args{'st_mon'} =~ /^(\d\d?)$/)) {
		if (($1 < 1) || ($1 > 12)) {
			print ("Invalid start month\n");
			return 1;
		}
	} else {
		print ("Invalid start month\n");
		return 1;
	}
}

sub get_st_mon {
	if ($args{'st_mon'} =~ /^(\d\d?)$/) {
		return $1;
	}
	return 0;
}


sub check_st_year {
	if ((exists $args{'st_year'}) && ($args{'st_year'} =~ /^(\d\d\d\d?)$/)) {
		if (($1 < 1970) || ($1 > 2020)) {
			print ("Invalid start year\n");
			return 1;
		}
	} else {
		print ("Invalid start year\n");
		return 1;
	}
}

sub get_st_year {
	if ($args{'st_year'} =~ /^(\d\d\d\d)$/) {
		return $1;
	}
	return 0;
}

# 
sub get_unitsize {
	my $ftype = get_ftype();
	my $dcat_out;

	if ($ftype eq 'dls') {      
		if (exists $mod2img{$args{'img'}}) {
			my $orig =  $mod2img{$args{'img'}};
			$dcat_out = `\'${TASKDIR}dcat\' -f $img2ftype{$orig} -s \'$host_dir$orig\'`;
		}
		# We don't have the original image, so just set the size to 512
		else {
			return 512;
		}
	}
	else {
		my $img = get_img('img');
       	$dcat_out = `\'${TASKDIR}dcat\' -f $ftype -s \'$img\'`;
	}
	if ($dcat_out =~ /(\d+): Size of Addressable Unit/) {
		return $1;
	}
	else {
		print "Error identifying block size (dcat -s output)<BR>\n";
		print "$dcat_out<BR>\n";
		exit(1);
	}
};


############## URL UTILITIES ##################

sub html_encode {
	my $text = shift;
	$text =~ s/&/&amp;/gs;
	$text =~ s/</&lt;/gs;
	$text =~ s/>/&gt;/gs;

	# @@@ LEADING SPACES and TABS
	# while ($text =~ s/^(&nbsp;)*\t/"$1&nbsp;&nbsp;&nbsp;&nbsp;"/eig) {}
	# while ($text =~ s/^(&nbsp;)* /"$1&nbsp;"/eig) {}
	return $text;
}

sub url_encode {
	my $text = shift;
	$text =~ s/([^a-z0-9_.!~*'() -])/sprintf "%%%02X", ord($1)/eig;
	$text =~ tr/ /+/;
	return $text;
}

sub url_decode {
	my $text = shift;
	$text =~ tr/\+/ /;
	$text =~ s/%([a-f0-9][a-f0-9])/chr( hex( $1 ) )/eig;
	return $text;
}


############ LOGGING ########################

sub log_session_info 
{
    return unless ($USE_LOG == 1);
    my $str = shift;
    chomp $str;
    my $date = localtime;

    my $lname = "autopsy.log";       
    open AUTLOG, ">>${LOCKDIR}/$lname" or die "Can't open log: $lname";
    print AUTLOG "$date: $str\n";
    close AUTLOG;

	return;
};

sub log_case_info {
	return unless ($USE_LOG == 1);
	my $str = shift;
	chomp $str;
	my $date = localtime;
	my $fname = case_log_fname();

	open CASELOG, ">>$fname" or die "Can't open log: $fname";
	print CASELOG "$date: $str\n";
	close CASELOG;

	return;
};


# log data to the general log file for the host
sub log_host_info {
	return unless ($USE_LOG == 1);
	my $str = shift;
	chomp $str;
	my $date = localtime;
	my $fname = host_log_fname();

	open HOSTLOG, ">>$fname" or die "Can't open log: $fname";
	print HOSTLOG "$date: $str\n";
	close HOSTLOG;

	return;
};


# Log data to the investigators specific log file
sub log_host_inv {
	return unless ($USE_LOG == 1);
	my $str = shift;
	chomp $str;
	my $date = localtime;
	my $fname = investig_log_fname();

	open HOSTLOG, ">>$fname" or die "Can't open log: $fname";
	print HOSTLOG "$date: $str\n";
	close HOSTLOG;

	return;
};




############ DISPLAY ########################
sub print_check_err {
	print_html_header("");
	print shift()."<BR>\n";
	sleep (1);
	exit 1;
}

sub print_err {
	print shift()."<BR>\n";
	sleep (1);
	exit 1;
}

# The page that makes the frameset does not have a body statement
# This routine is used to make the minimum required header statements
sub print_html_header_frameset {
	my $text = shift;
	print "Content-type: text/html${HTTP_NL}${HTTP_NL}";

	my $time = localtime();

print <<EOF;
<HTML>
<!-- Autopsy ver. $VER Forensic Browser -->
<!-- Page created at: $time -->
<HEAD>
  <TITLE>$text</TITLE>
</HEAD>

EOF
	$is_html = 1;
}

# Create the header information with the body tag
sub print_html_header {
	print_html_header_frameset(shift);
	print "<BODY BGCOLOR=\"$BACK_COLOR\">\n\n";
	$is_body = 1;
}

# Print the header with the margins set to 0 so that the tab buttons
# are flush with the edges of the frame
sub print_html_header_tabs {
	print_html_header_frameset(shift);
	print "<BODY MARGINHEIGHT=0 MARGINWIDTH=0 TOPMARGIN=0 ".
	  "LEFTMARGIN=0 RIGHTMARGIN=0 BOTMARGIN=0 BGCOLOR=\"$BACK_COLOR\">\n\n";
	$is_body = 1;
}


# Header for front page to warn about java script
sub print_javascript_header {
    my $text = shift;
    print "Content-type: text/html${HTTP_NL}${HTTP_NL}";

	my $time = localtime();
	# The write line has to stay on one line
print <<EOF;
<HTML>
<!-- Autopsy ver. $VER Forensic Browser -->
<!-- Page created at: $time -->
<HEAD>
  <TITLE>$text</TITLE>
  <SCRIPT language=\"JavaScript\">
  <!-- hide script from old browsers
  document.write(\'<CENTER><FONT COLOR=\"red\"><P>WARNING: Your browser currently has Java Script enabled</FONT><P>You do not need Java Script to use Autopsy and it is recommended that it be turned off for security reasons<HR></CENTER>\');
  //-->
  </SCRIPT>
</HEAD>

<BODY BGCOLOR=\"$BACK_COLOR\">

EOF

	$is_html = 1;
	$is_body = 1;
}


# For raw text outputs
# This only has ONE newline at the end so that a Content-Disposition
# can be added. A newline must be added if Disposition is not used.
sub print_text_header {
	print "Content-type: text/plain${HTTP_NL}";
}

# For forced save outputs
# This only has ONE newline at the end so that a Content-Disposition
# can be added. A newline must be added if Disposition is not used.
sub print_oct_header {
	print "Content-type: application/octet-stream${HTTP_NL}";
}

# remove control chars from printout
sub print_output {
	while (my $out = shift) {
		foreach $_ (split (//, $out)) {
			if (($_ eq "\n") || ($_ eq "\r") || ($_ eq "\f") ||
			  ($_ eq "\t") ) {
				print "$_";
			}
			elsif ((ord($_) < 0x20) || (ord($_) > 0x7e)) {
				print "^".ord($_);
			}
			else {
				print "$_";
			}
		}
	}
}
