diff --git a/NEWS.txt b/CHANGES.txt
similarity index 100%
rename from NEWS.txt
rename to CHANGES.txt
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000000000000000000000000000000000000..5b6e7c66c276e7610d4a73c70ec1a1f7c1003259
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed 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 this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/INSTALL.txt b/INSTALL.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ef406a4845b1d9bee74f914fdbd193e72b181a75
--- /dev/null
+++ b/INSTALL.txt
@@ -0,0 +1,39 @@
+                    Autopsy Forensic Browser
+                http://www.sleuthkit.org/autopsy
+
+              Brian Carrier [carrier@sleuthkit.org]
+                     Last Update: March 2010
+
+
+Installation 
+-----------------------------------------------------------------------------
+1. Install The Sleuth Kit (see README for download locations).   This
+   includes doing a 'make install' so that the executables and files
+   are installed in a single directory.  Note that this does not 
+   currently work natively on Windows.  It will work using Cygwin, but
+   you must install and build The Sleuth Kit in Cygwin and not use the
+   Win32 executables that are available on the sleuthkit.org website.
+
+2. Untar the Autopsy file. 
+
+3. Run 'make'.  It will try to locate the grep and strings utilities.
+   If any are not found, it will prompt you for the location.  It will
+   also search for the TSK installation. 
+
+4. The install script will ask if you have the NIST National Software
+   Reference Library (NSRL).  If you do, you will need to enter the
+   path of it.  The NSRL is available from www.nsrl.nist.gov.
+   
+5. You will be prompted for the Evidence Locker location.  This is the
+   base directory where all cases will be stored.  You must create this
+   directory on your own.  
+
+
+Live Analysis
+------------------------------------------------------------------------------
+Type 'make live' or run the 'make-live-cd' script to build the 'live-cd'
+directory.  The 'live-cd' directory can be burned to a CD.
+
+------------------------------------------------------------------------------
+Brian Carrier [carrier@sleuthkit.org]
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..3a6334c19601b146f1ac71a11128e37b11d821c2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,30 @@
+all:
+	@sh ./configure
+
+conf.pl:
+	@sh ./configure
+
+live: conf.pl
+	./make-live-cd
+
+indent:
+	cd lib; perltidy -b *.pm *.pl
+	cd base; perltidy -b autopsy.base
+
+clean:
+	rm -f ./autopsy
+	rm -f ./make-live-cd
+	rm -f ./conf.pl
+	rm -f ./config.tmp
+	rm -f ./config2.tmp
+	rm -rf ./live-cd/
+	rm -f ./lib/*.bak
+	rm -f ./base/*.bak
+	find . -name ".DS_Store" | xargs rm -f
+	find . -type f -perm +g+x,o+x,u+x | xargs  chmod -x
+	grep "curtskver=" ./configure
+	grep "VER" ./lib/define.pl
+	find . -name ".*" | grep -v perltidy
+
+release:
+	find . -name "CVS" | xargs rm -rf
diff --git a/README-LIVE.txt b/README-LIVE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..df1aaabdc6d0c10029458d27309cb4b345f0fb76
--- /dev/null
+++ b/README-LIVE.txt
@@ -0,0 +1,119 @@
+                     Autopsy Forensic Browser
+                 http://www.sleuthkit.org/autopsy
+
+                        Live Analysis Mode
+
+                   Last Updated:  January 2005
+
+
+What is Live Analysis?
+--------------------------------------------------------------------
+Live analysis is, in my mind, an investigation that occurs using
+the software resources of the suspect system.  An example scenario
+of this is when a suspect system is found running, a CD is placed
+into it, and commands are run.  If the suspect system is powered
+down and booted from a bootable Linux CD (or similar), then the
+investigation is a dead analysis.
+
+This is most commonly done when investigating a server or other
+computer that is suspected of being compromised, but verification
+is needed before it can be powered down.  Using The Sleuth Kit and
+Autopsy will prevent the access times on individual files from being
+updated (although the raw device's A-time will be) and can bypass
+most rootkits that hide files and directories.
+
+
+What are the Issues with Live Analysis?
+--------------------------------------------------------------------
+Live analysis is not ideal because you are relying on the suspect
+system, which can lie, cheat, and steal.  In addition to the potential
+of getting false information from the operating system you will
+also overwrite memory and maybe swap space during the investigation.
+
+If you are interested in examining the memory of the system, you
+should probably acquire that before you begin a live analysis.
+
+An issue with doing live analysis with Autopsy is that it requires
+Perl, which is a large program and will likely need to depend on
+libraries and other files on the suspect system.
+
+
+How do I make a CD with Autopsy on it?
+--------------------------------------------------------------------
+
+You will want to have a trusted CD for a live analysis, and autopsy
+makes that fairly easy.  Compile autopsy as you would for a normal
+dead analysis installation.  Then execute 'make live' in Autopsy.
+This script will make a 'live-cd' sub-directory in the autopsy directory,
+which contains a copy of autopsy and copies of TSK executables, grep,
+strings, perl etc:
+
+    # make live
+    Making base directory (./live-cd/)
+    Copying executables
+    Copying autopsy files
+    Creating configuration file using existing settings
+
+Try the 'make static' with TSK to see if you can make static
+executables for your platform.  
+
+The 'live-cd' directory has a 'bin' directory where additional
+executables can be copied to and then the whole directory can be
+burned to a CD.
+
+
+How Do I Use the CD?
+--------------------------------------------------------------------
+
+After the CD has been created and there is a system suspected of
+being compromised, then it is time to take advantage of the new
+features.  There are two scenarios for live analysis.  The first
+scenario uses a network share from a trusted system that you can
+write to.  In this case, autopsy is run as normal and you specify
+the evidence locker directory as the mounted disk.  The evidence
+locker is specified with '-d':
+
+    # ./autopsy -d /mnt/ev_lock 10.1.32.123
+
+The above would start autopsy, use '/mnt/ev_lock/' as the evidence
+locker and would allow connections from 10.1.32.123 (where the
+investigator would connect from using an HTML browser).  Remember that
+we do not want to write to the suspect system, so we should only use
+a network share and not a local directory in this scenario.
+
+The second scenario does not use an evidence locker and does not
+intentionally write any data to disk.  This scenario does not need
+the network share and each of the devices (or partitions) that will
+be analyzed are specified on the command line using the '-i' flags.
+The '-i' flag requires three arguments: the device, the file system
+type, and the mounting point.  For example, to examine the '/dev/hda5'
+and '/dev/hda8' partitions on a Linux system, the following could
+be used:
+
+    # ./autopsy -i /dev/hda5 linux-ext3 / -i /dev/hda8 linux-ext3 /usr/ \
+    10.1.32.123
+
+The file system type must be one of the types that are supported
+by TSK.  The remote IP address must also be given, otherwise you
+will have to use a browser on the suspect system and that will write
+data to the disk.
+
+When you use the '-i' flag, then autopsy will start in the 'Host
+Manager' view where you can select the image that you want to
+analyze.  You will skip the case and host configuration.  The default
+case name will be 'live', the default host name is 'local', and the
+default investigator name is 'unknown'.
+
+
+Additional Information
+--------------------------------------------------------------------
+I wrote a more detailed explanation of the live analysis mode of
+Autopsy version 2.00 in the 13th issue of The Sleuth Kit Informer.
+Some of this document is taken from the Informer issue.
+
+    http://www.sleuthkit.org/informer/sleuthkit-informer-13.html
+
+
+--------------------------------------------------------------------
+Copyright (c) 2004 by Brian Carrier.  All Rights Reserved
+Brian Carrier [carrier <at> sleuthkit <dot> org]
diff --git a/TODO.txt b/TODO.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d8a262840f382c4d9341b4bef6b27aa8dc45fe3d
--- /dev/null
+++ b/TODO.txt
@@ -0,0 +1,58 @@
+Remove HFS check in autopsy.base when HFS support is standard.
+
+Look into adding the unallocated partiion space when an image is added.
+Look into integrating clamshell or other AV
+
+There is an error when viewing the event sequencer notes about
+initialized in "ne".
+
+test date search
+
+Add SHA-1 to more places (images, lookups etc.)
+
+Get "Can't ignore signal CHLD, forcing to default." message with
+file type sorting (BUG: 919829).
+
+Figure out details around having Perl on the live analysis CD.
+(BUG: 919831)
+
+
+-------------------- FILE MODE ----------------------------
+- Make a file system depend seperator for / or \
+
+- check for tar during install
+  - List contents like HTML does now
+
+--------------------- SEARCH -----------------------------
+- new mode where searching is done on output of 'icat' of allocated
+  inodes
+
+- Bug: if the string that matches a keyword starts with spaces, then 
+  the 'index' function returns the idx to the start of the spaces and not
+  the substring.  (BUG 842858)
+
+--------------------- TIMELINE -----------------------------
+
+
+--------------------- LOGGING -----------------------------
+- New Report Creation:
+
+- Add pulldown in notes for common things:
+  - New MD5 / SHA-1
+  - Part of rootkit
+  - Suspected child porn
+  - known child porn
+
+--------------------- SORTER -----------------------------
+- Should sorter be at the host level instead of image, with output
+files appended to each other?
+
+- Allow one to browse output files
+
+--------------------- GENERAL -----------------------------
+- Add foremost
+- link in meta data to list just unallocated / used
+- Make data bases updatable in the host details view
+- Option to mount images in loopback when it is a Linux system
+- read config files in autopsy itself and not everytime ...
+- Make a way to kill intensive processes (searching, fls)
diff --git a/base/.perltidyrc b/base/.perltidyrc
new file mode 100755
index 0000000000000000000000000000000000000000..f1f2e71a01bcfcdb8bd171c25e4d7a1e1e797c93
--- /dev/null
+++ b/base/.perltidyrc
@@ -0,0 +1,5 @@
+-i=4	# indent of 4
+-pt=2	# paren tightness
+-sbt=2	# square paren tightness
+-bt=2	# curly paren tightness
+-nsfs	# no space after semi in for loop
diff --git a/base/autopsy.base b/base/autopsy.base
new file mode 100644
index 0000000000000000000000000000000000000000..3b3bbdc7f2a8bd2ae3882e51d4b8a74116278a29
--- /dev/null
+++ b/base/autopsy.base
@@ -0,0 +1,879 @@
+#
+# autopsy gui server
+# Autopsy Forensic Browser
+#
+#
+# This file requires The Sleuth Kit
+#    www.sleuthkit.org
+#
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2005 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 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.
+#
+
+#
+# refer to Security Considerations in README for a description of the
+# cookie authentication
+#
+
+require 5.008;
+
+use strict;
+use Socket;
+
+use Main;
+use Print;
+require Fs;
+require Caseman;
+
+require 'conf.pl';
+require 'lib/define.pl';
+
+# Import variables from conf.pl
+use vars '$LOCKDIR', '$INSTALLDIR', '$PICTDIR';
+use vars '$SANITIZE_TAG', '$SANITIZE_PICT';
+use vars '$USE_STIMEOUT', '$STIMEOUT', '$CTIMEOUT';
+use vars '$SAVE_COOKIE',  '$GREP_EXE', '$FILE_EXE';
+use vars '$NSRLDB';
+
+# Default port
+my $port = 9999;
+
+# Default 'remote' host
+my $rema = 'localhost';
+
+$| = 1;
+
+$::LIVE      = 0;
+$::USE_NOTES = 1;
+$::USE_LOG   = 1;
+
+sub usage {
+    print
+"\n\nusage: $0 [-c] [-C] [-d evid_locker] [-i device filesystem mnt] [-p port] [remoteaddr]\n";
+    print "  -c: force a cookie in the URL\n";
+    print "  -C: force NO cookie in the URL\n";
+    print "  -d dir: specify the evidence locker directory\n";
+    print "  -i device filesystem mnt: Specify info for live analysis\n";
+    print "  -p port: specify the server port (default: $port)\n";
+    print "  remoteaddr: specify the host with the browser (default: $rema)\n";
+    exit 1;
+}
+
+my $cook_force = 0;
+
+my $vol_cnt = 0;
+
+# Were options given?
+while ((scalar(@ARGV) > 0) && ($ARGV[0] =~ /^-/)) {
+    my $f = shift;
+
+    # Evidence Locker
+    if ($f eq '-d') {
+        if (scalar(@ARGV) == 0) {
+            print "Missing Directory\n";
+            usage();
+        }
+
+        my $d = shift;
+
+        # We need to do this for the tainting
+        # We don't need to check for special characters in this case because
+        # all commands will be run with the same permissions as the
+        # original user.  We will check for the obvious ';' though
+        if ($d =~ /;/) {
+            print "Illegal argument\n";
+            exit(1);
+        }
+
+        # If the path is relative, autopsyfunc will get screwed up when
+        # this is run from a directory other than where autopsyfunc is
+        # so force full paths
+        elsif ($d !~ /^\//) {
+            print "The evidence locker must be full path (i.e. begin with /)\n";
+            exit(1);
+        }
+        elsif ($d =~ /(.*)/) {
+            $LOCKDIR = $1;
+        }
+    }
+
+    # Force no cookie
+    elsif ($f eq '-C') {
+        $::USE_COOKIE = 0;
+        $cook_force   = 1;
+    }
+
+    # force a cookie
+    elsif ($f eq '-c') {
+        $::USE_COOKIE = 1;
+        $cook_force   = 1;
+    }
+
+    elsif ($f eq '-i') {
+        $::LIVE        = 1;
+        $::USE_LOG     = 0;
+        $::USE_NOTES   = 0;
+        $::SAVE_COOKIE = 0;
+
+        if (scalar(@ARGV) < 3) {
+            print "Missing device, file system, and mount point arguments\n";
+            usage();
+        }
+
+        my $vol = "vol" . $vol_cnt;
+        $vol_cnt++;
+
+        my $dev = shift;
+        if ($dev =~ /($::REG_IMG_PATH)/) {
+            $dev = $1;
+        }
+        else {
+            print "invalid device: $dev\n";
+            usage();
+        }
+
+        unless ((-e "$dev") || (-l "$dev")) {
+            print "Device ($dev) not found\n";
+            usage();
+        }
+
+        my $fs = shift;
+        if ($fs =~ /($::REG_FTYPE)/) {
+            $fs = $1;
+        }
+        else {
+            print "invalid file system: $fs\n";
+            usage();
+        }
+        unless ((exists $Fs::root_meta{$fs})
+            && (defined $Fs::root_meta{$fs}))
+        {
+            print "File system not supported: $fs\n";
+            usage();
+        }
+        $Caseman::vol2ftype{$vol} = "$fs";
+
+        my $mnt = shift;
+        if ($mnt =~ /($::REG_MNT)/) {
+            $mnt = $1;
+        }
+        else {
+            print "invalid mount point: $mnt\n";
+            usage();
+        }
+        $Caseman::vol2mnt{$vol}   = "$mnt";
+        $Caseman::vol2cat{$vol}   = "part";
+        $Caseman::vol2itype{$vol} = "raw";
+        $Caseman::vol2start{$vol} = 0;
+        $Caseman::vol2end{$vol}   = 0;
+
+        # This makes me nervous ...
+        $Caseman::vol2par{$vol}   = $vol;
+        $Caseman::vol2path{$vol}  = "$dev";
+        $Caseman::vol2sname{$vol} = "$dev";
+    }
+
+    # Specify a different port
+    elsif ($f eq '-p') {
+        if (scalar(@ARGV) == 0) {
+            print "Missing port argument\n";
+            usage();
+        }
+
+        my $p = shift;
+        if ($p =~ /(\d+)/) {
+            $p = $1;
+        }
+        else {
+            print "invalid port: $p\n";
+            usage();
+        }
+        if (($p < 1) || ($p > 65535)) {
+            print "invalid port: $port\n";
+            usage();
+        }
+        $port = $p;
+    }
+
+    else {
+        print "Invalid flag: $f\n";
+        usage();
+    }
+}
+
+# remote address
+if (scalar(@ARGV) > 0) {
+    $rema = shift;
+}
+
+# Get remote address
+my @acl_addr;    # Array of host addresses
+my $hn;          # Host name
+my $tmp;
+if ($rema =~ /(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/) {
+    $acl_addr[0] = pack('C4', ($1, $2, $3, $4));
+    $hn = $rema;
+}
+else {
+    ($hn, $tmp, $tmp, $tmp, @acl_addr) = gethostbyname($rema);
+    unless (defined $tmp) {
+        print "Host not found: $rema\n";
+        usage();
+    }
+}
+
+# Determine the address that will be used to access this server
+my $lclhost;
+my @ta = unpack('C4', $acl_addr[0]);
+
+my $bindaddr;
+
+# If we are being accessed by localhost, we need that and not the hostname
+if (   ($ta[0] == 127)
+    && ($ta[1] == 0)
+    && ($ta[2] == 0)
+    && ($ta[3] == 1))
+{
+    $lclhost  = "localhost";
+    $bindaddr = $acl_addr[0];
+
+    # Force no cookie to be used unless we already set this value
+    # with arguments
+    $::USE_COOKIE = 0 unless ($cook_force == 1);
+}
+else {
+    $lclhost = `/bin/hostname`;
+    chop $lclhost;
+
+    $bindaddr = INADDR_ANY;
+
+    # Force a cookie to be used unless we already set this value
+    # with arguments
+    $::USE_COOKIE = 1 unless ($cook_force == 1);
+}
+
+# Verify the variables defined in the configuration files
+check_vars();
+
+# Remove the final '/' from TSKDIR if it exists
+$::TSKDIR = $1
+  if ($::TSKDIR =~ /(.*?)\/$/);
+
+#
+# Verify that all of the required executables exist
+#
+check_tools();
+
+
+
+# Currently, HFS is in beta and not enabled by default. 
+# Autopsy has been configured for it though, so disable it if
+# the user has not compiled support into TSK.  remove this when
+# HFS support is standard.
+# This redirects stderr to stdout so we can easily capture it
+my $out = `\'$::TSKDIR/fls\' -f list 2>&1`;
+unless ($out =~ /hfs/) {
+    for (my $i = 0; $i < @Fs::types; $i++) {
+        if ($Fs::types[$i] eq "hfs") {
+            $Fs::types[$i] = "";
+            last;
+        }
+    }
+}
+
+
+
+# remove environment stuff that we don't need and that could be insecure
+# We allow basic bin directories for CYGWIN though, since they are
+# required for the CYGWIN dlls
+my $UNAME = "";
+if (-e "/bin/uname") {
+    $UNAME = "/bin/uname";
+}
+elsif (-e "/usr/bin/uname") {
+    $UNAME = "/usr/bin/uname";
+}
+
+my $ispathclear = 1;
+if (($UNAME ne "") && (`$UNAME` =~ /^CYGWIN/)) {
+    $ENV{PATH} = '/bin:/usr/bin:/usr/local/bin';
+    $ispathclear = 0;
+}
+else {
+    $ENV{PATH} = '';
+}
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
+
+my $date = localtime;
+
+if ($::LIVE == 0) {
+
+    # Remove the final '/' if it exists
+    $LOCKDIR = $1
+      if ($LOCKDIR =~ /(.*?)\/$/);
+}
+
+# Setup socket
+my $proto = getprotobyname('tcp');
+socket(Server, PF_INET, SOCK_STREAM, $proto)
+  or die "Error creating network socket: $!";
+
+setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, 1)
+  or die "Error setting network socket options (reuse): $!";
+
+setsockopt(Server, SOL_SOCKET, SO_KEEPALIVE, 1)
+  or die "Error setting network socket options (keep alive): $!";
+
+bind(Server, sockaddr_in($port, $bindaddr))
+  or die "Error binding to port $port (is Autopsy already running?): $!";
+
+listen(Server, SOMAXCONN)
+  or die "Error listening to socket for connections: $!";
+
+my $magic;    # magic authentication cookie
+my $cook_file;
+my $cookie_url = "";
+
+if ($::USE_COOKIE == 1) {
+
+    # Try for a real random device, or use rand if all else fails
+    if (-e "/dev/urandom") {
+        my $r;
+        open RAND, "</dev/urandom" or die "can not open /dev/urandom";
+        read RAND, $r, 4;
+        $magic = unpack "I", $r;
+        read RAND, $r, 4;
+        $magic .= unpack "I", $r;
+        close RAND;
+    }
+    else {
+        $magic = int(rand 0xffffffff) . int(rand 0xffffffff);
+    }
+
+    $cookie_url = "$magic/";
+
+    # Save to file in case the stdout gets overwritten
+    if ($SAVE_COOKIE == 1) {
+        $cook_file = "$LOCKDIR/.$port.cookie";
+        if (open COOK, ">$cook_file") {
+            chmod 0600, "$cook_file";
+            print COOK "$magic\n";
+            close COOK;
+        }
+        else {
+            print "WARNING: Cannot open file to save cookie in ($cook_file)";
+        }
+    }
+}
+
+print <<EOF;
+
+============================================================================
+
+                       Autopsy Forensic Browser 
+                  http://www.sleuthkit.org/autopsy/
+                             ver $::VER 
+
+============================================================================
+EOF
+
+if ($::LIVE == 0) {
+    print "Evidence Locker: $LOCKDIR\n";
+}
+else {
+    print "Live Analysis Mode\n";
+}
+if ($ispathclear == 0) {
+    print
+"\nCYGWIN Mode (Internal path contains /bin, /usr/bin, and /usr/local/bin)\n\n";
+}
+
+print <<EOF2;
+Start Time: $date
+Remote Host: $rema
+Local Port: $port
+
+Open an HTML browser on the remote host and paste this URL in it:
+
+    http://$lclhost:${port}/${cookie_url}$::PROGNAME
+
+Keep this process running and use <ctrl-c> to exit
+EOF2
+
+Print::log_session_info("Starting session on port $port and $hn\n");
+
+# Set the server alarm
+$SIG{ALRM} = \&SIG_ALARM_SERVER;
+$SIG{INT}  = \&SIG_CLOSE;
+
+# setting this to ignore will automatically wait for children
+$SIG{CHLD} = 'IGNORE';
+
+# Wait for Connections
+while (1) {
+
+    alarm($STIMEOUT) if ($USE_STIMEOUT == 1);
+
+    my $raddr = accept(CLIENT, Server);
+    next unless ($raddr);
+    my ($rport, $riaddr) = sockaddr_in($raddr);
+
+    die "Error creating child" unless (defined(my $pid = fork()));
+
+    if (0 == $pid) {
+        open(STDOUT, ">&CLIENT") or die "Can't dup client to stdout";
+
+        # open(STDERR, ">&CLIENT") or die "Can't dup client to stdout";
+        open(STDIN, "<&CLIENT") or die "Can't dup client to stdin";
+        $| = 1;
+
+        my @rip = unpack('C4', $riaddr);
+
+        # Check ACL
+        foreach $tmp (@acl_addr) {
+            if ($tmp eq $riaddr) {
+                spawn_cli($riaddr);
+                close CLIENT;
+                exit 0;
+            }
+        }
+
+        forbid("$rip[0].$rip[1].$rip[2].$rip[3]");
+        Print::log_session_info("ERROR: Unauthorized Connection from: "
+              . "$rip[0].$rip[1].$rip[2].$rip[3]\n");
+
+        close CLIENT;
+        exit 1;
+    }
+    else {
+        close CLIENT;
+    }
+}
+
+# Error messages
+sub forbid {
+    my $ip = shift;
+    $ip = "" unless defined ($ip);
+
+    print "HTTP/1.0 403 Forbidden$::HTTP_NL"
+      . "Content-type: text/html$::HTTP_NL$::HTTP_NL"
+      . "<html><center>\n"
+      . "<h2>Access Denied</h2>\n"
+      . "<h3>Your connection from: $ip has been logged</h3>\n"
+      . "</center></html>$::HTTP_NL$::HTTP_NL$::HTTP_NL";
+
+    return;
+}
+
+sub bad_req {
+    print "HTTP/1.0 404 Bad Request$::HTTP_NL"
+      . "Content-type: text/html$::HTTP_NL$::HTTP_NL"
+      . "<html><body><center>\n"
+      . "<h2>Invalid URL<br><tt>"
+      . shift()
+      . "</tt></h2>\n"
+      . "</center></body></html>"
+      . "$::HTTP_NL$::HTTP_NL$::HTTP_NL";
+
+    return;
+}
+
+# Alarm Functions
+sub SIG_ALARM_CLIENT {
+    Print::log_session_info("Connection timed out\n");
+    close CLIENT;
+    exit 1;
+}
+
+sub SIG_ALARM_SERVER {
+    print "Server Timeout ($STIMEOUT seconds), Exiting\n";
+    Print::log_session_info("Server Timeout ($STIMEOUT seconds), Exiting\n");
+    exit 0;
+}
+
+# Close the system down when Control-C is given
+sub SIG_CLOSE {
+
+    # delete the cookie file
+    if (($::USE_COOKIE == 1) && ($SAVE_COOKIE == 1)) {
+        unlink "$cook_file";
+    }
+
+    print "End Time: " . localtime() . "\n";
+    Print::log_session_info("Ending session on port $port and $hn\n");
+    exit 0;
+}
+
+# Pass the remote IP address as the argument for logging
+sub spawn_cli {
+
+    # Set timeout for 10 seconds if we dont get any input
+    alarm($CTIMEOUT);
+    $SIG{ALRM} = \&SIG_ALARM_CLIENT;
+
+    while (<STDIN>) {
+
+        last if (/^\s+$/);
+
+        if (/^GET \/+(\S*)\s?HTTP/) {
+            my $url = $1;
+            my $script;
+            my $args;
+
+            if (/\x0d\x0a$/) {
+                $::HTTP_NL = "\x0d\x0a";
+            }
+            else {
+                $::HTTP_NL = "\x0a";
+            }
+
+            # Magic Cookie
+            # If we are using cookies, then the url should be:
+            # cookie/autopsy?var=val ...
+            if ($::USE_COOKIE == 1) {
+
+                if (   ($url =~ /^(\d+)\/+([\w\.\/]+)(?:\?(.*))?$/)
+                    && ($1 == $magic))
+                {
+                    $script = $2;
+                    $args   = $3;
+                }
+                else {
+                    my @rip = unpack('C4', shift());
+                    Print::log_session_info("ERROR: Incorrect Cookie from: "
+                          . "$rip[0].$rip[1].$rip[2].$rip[3]\n");
+                    forbid("$rip[0].$rip[1].$rip[2].$rip[3]");
+                    return 1;
+                }
+            }
+
+            # if we aren't using cookies, then it should be:
+            # autopsy?var=val ...
+            else {
+                if ($url =~ /^\/?([\w\.\/]+)(?:\?(.*))?$/) {
+                    $script = $1;
+                    $args   = $2;
+                }
+                else {
+                    bad_req($url);
+                    return 1;
+                }
+            }
+
+            if ($script eq $::PROGNAME) {
+                $args = "" unless (defined $args);
+
+                # Turn timer off
+                alarm(0);
+
+                 my $has_ref = 0;
+                 while (<STDIN>) {
+                     last if (/^\s+$/);
+                     if (/^Referer: /) {
+                         $has_ref = 1;
+                         last;
+                     }
+                 }
+     
+                 if (($has_ref == 0) && ($args ne "")) {
+                     Print::log_session_info("ERROR: Missing referer value");
+                     forbid();
+                     return 1;
+                 }
+
+                # Print status
+                print "HTTP/1.0 200 OK$::HTTP_NL";
+                ::main($args);
+            }
+            elsif ($script eq "global.css") {
+                show_file($script);
+            }
+
+            # Display the sanitized picture or reference error
+            elsif ($script eq $::SANITIZE_TAG) {
+                Appview::sanitize_pict($args);
+                return 1;
+            }
+
+            # Display a picture or help file
+            elsif (($script =~ /^(pict\/[\w\.\/]+)/)
+                || ($script =~ /^(help\/[\w\.\/]+)/))
+            {
+                show_file($1);
+            }
+            elsif ($script eq 'about') {
+                about();
+            }
+
+            # I'm not sure why this is needed, but there are reqs for it
+            elsif ($script eq 'favicon.ico') {
+                show_file("pict/favicon.ico");
+            }
+            else {
+                bad_req($url);
+                Print::log_session_info("Unknown function: $script\n");
+                return 1;
+            }
+            return 0;
+        }
+    }    # end of while (<>)
+
+}    # end of spawn_cli
+
+# Print the contents of a local picture or help file
+sub show_file {
+    my $file = "$INSTALLDIR/" . shift;
+
+    if (-e "$file") {
+        print "HTTP/1.0 200 OK$::HTTP_NL";
+
+        open FILE, "<$file"
+          or die "can not open $file";
+
+        if ($file =~ /\.css$/i) {
+            print "Content-type: text/css$::HTTP_NL$::HTTP_NL";
+        }
+        elsif ($file =~ /\.jpg$/i) {
+            print "Content-type: image/jpeg$::HTTP_NL$::HTTP_NL";
+        }
+        elsif ($file =~ /\.gif$/i) {
+            print "Content-type: image/gif$::HTTP_NL$::HTTP_NL";
+        }
+        elsif ($file =~ /\.ico$/i) {
+            print "Content-type: image/ico$::HTTP_NL$::HTTP_NL";
+        }
+        elsif ($file =~ /\.html$/i) {
+            print "Content-type: text/html$::HTTP_NL$::HTTP_NL";
+        }
+        else {
+            print "HTTP/1.0 404 Bad Request$::HTTP_NL"
+              . "Content-type: text/html$::HTTP_NL$::HTTP_NL"
+              . "<html>\n"
+              . "<head><title>Error</title></head>\n"
+              . "<h2><center>Unknown Extension</h2>\n"
+              . "</center></html>$::HTTP_NL$::HTTP_NL$::HTTP_NL";
+            exit(1);
+        }
+
+        while (<FILE>) {
+            print "$_";
+        }
+        close(FILE);
+
+        print "$::HTTP_NL$::HTTP_NL";
+    }
+    else {
+        print "HTTP/1.0 404 Bad Request$::HTTP_NL"
+          . "Content-type: text/html$::HTTP_NL$::HTTP_NL"
+          . "<html>\n"
+          . "<head><title>Error</title></head>\n"
+          . "<h2><center>File Not Found</h2>"
+          . "</center></html>$::HTTP_NL$::HTTP_NL$::HTTP_NL";
+        exit(1);
+    }
+
+    return;
+}
+
+sub about {
+
+    print "HTTP/1.0 200 OK$::HTTP_NL"
+      . "Content-type: text/html$::HTTP_NL$::HTTP_NL";
+
+    my $tskver = ::get_tskver();
+
+    print <<EOF;
+
+<html>
+<head><title>About Autopsy</title></head>
+
+<body BGCOLOR=#CCCC99>
+
+<center><h2>About Autopsy</h2>
+  <br>
+  <img src=\"pict/logo.jpg\" alt=\"Logo\">
+  <br><br>
+  <b>Version</b>: $::VER
+  <br>
+  <tt><a href="http://www.sleuthkit.org/autopsy/">http://www.sleuthkit.org/autopsy/</a></tt>
+  <br>
+  <tt><a href="http://www.sleuthkit.org/informer/">http://www.sleuthkit.org/informer/</a></tt>
+</center>
+
+
+<h3>Credits</h3>
+<UL>
+  <LI>Code Development: Brian Carrier (carrier at sleuthkit dot org)
+  <LI>Interface Assistance: Samir Kapuria
+  <LI>Mascot: Hash the Hound
+</UL>
+
+<h3>Configuration</h3>
+<b>The Sleuth Kit</b>:<br> 
+&nbsp;&nbsp;URL: <a href="http://www.sleuthkit.org/sleuthkit/">
+  <tt>http://www.sleuthkit.org/sleuthkit/</tt></a><br> 
+&nbsp;&nbsp;Installation Location: <tt>$::TSKDIR</tt><br>
+&nbsp;&nbsp;Version: $tskver<br>
+<b>Evidence Locker</b>: <tt>$LOCKDIR</tt><br>
+<b>grep</b>: <tt>$GREP_EXE</tt><br>
+<b>file</b>: <tt>$FILE_EXE</tt><br>
+<b><a href="http://www.nsrl.nist.gov/">NIST NSRL</a></b>: <tt>$NSRLDB</tt><br>
+
+</body></html>
+
+EOF
+    return 0;
+}
+
+### Check that the required tools are there
+sub check_tools {
+
+    # Sleuth Kit execs
+    unless (-x $::TSKDIR . "/icat") {
+        print "ERROR: Sleuth Kit icat executable missing: $::TSKDIR\n";
+        exit(1);
+    }
+    unless (-x $::TSKDIR . "/istat") {
+        print "ERROR: Sleuth Kit istat executable missing\n";
+        exit(1);
+    }
+    unless (-x $::TSKDIR . "/ifind") {
+        print "ERROR: Sleuth Kit ifind executable missing\n";
+        exit(1);
+    }
+    unless (-x $::TSKDIR . "/ils") {
+        print "ERROR: Sleuth Kit ils executable missing\n";
+        exit(1);
+    }
+    unless (-x $::TSKDIR . "/fls") {
+        print "ERROR: Sleuth Kit fls executable missing\n";
+        exit(1);
+    }
+    unless (-x $::TSKDIR . "/ffind") {
+        print "ERROR: Sleuth Kit ffind executable missing\n";
+        exit(1);
+    }
+    unless (-x $::TSKDIR . "/blkcat") {
+        print "ERROR: Sleuth Kit blkcat executable missing\n";
+        exit(1);
+    }
+    unless (-x $::TSKDIR . "/blkcalc") {
+        print "ERROR: Sleuth Kit blkcalc executable missing\n";
+        exit(1);
+    }
+    unless (-x $::TSKDIR . "/blkls") {
+        print "ERROR: Sleuth Kit blkls executable missing\n";
+        exit(1);
+    }
+    unless (-x $::TSKDIR . "/img_stat") {
+        print "ERROR: Sleuth Kit img_stat executable missing\n";
+        exit(1);
+    }
+    unless (defined $::FILE_EXE) {
+        print "ERROR: File executable location not defined in config file\n";
+        exit(1);
+    }
+    unless (-x "$::FILE_EXE") {
+        print "ERROR: File executable ($::FILE_EXE) missing\n";
+        exit(1);
+    }
+    unless (-x $::TSKDIR . "/fsstat") {
+        print "ERROR: Sleuth Kit fsstat executable missing\n";
+        exit(1);
+    }
+    unless (defined $::MD5_EXE) {
+        print "ERROR: MD5 executable location not defined in config file\n";
+        exit(1);
+    }
+    unless (-x "$::MD5_EXE") {
+        print "ERROR: md5 executable ($::MD5_EXE) missing\n";
+        exit(1);
+    }
+    if ($::SHA1_EXE ne "") {
+        unless (-x "$::SHA1_EXE") {
+            print "ERROR: sha1 executable missing\n";
+            exit(1);
+        }
+    }
+    unless (-x $::TSKDIR . "/srch_strings") {
+        print "ERROR: Sleuth Kit srch_strings executable missing\n";
+        exit(1);
+    }
+
+    if ($::LIVE == 0) {
+        unless (-x $::TSKDIR . "/sorter") {
+            print "ERROR: Sleuth Kit sorter executable missing\n";
+            exit(1);
+        }
+        unless (-x $::TSKDIR . "/hfind") {
+            print "ERROR: Sleuth Kit hfind executable missing\n";
+            print
+              "  You likely have an old version of The Sleuth Kit or TASK\n";
+            exit(1);
+        }
+    }
+
+    unless (-x "$GREP_EXE") {
+        print "ERROR: grep executable missing\n";
+        exit(1);
+    }
+}
+
+# check values that should be defined in the configuration files
+# This will show incomplete installations
+sub check_vars {
+    unless ((defined $::TSKDIR) && ($::TSKDIR ne "")) {
+        print "ERROR: TSKDIR variable not set in configuration file\n";
+        print "  This could been caused by an incomplete installation\n";
+        exit(1);
+    }
+
+    unless (-d "$::TSKDIR") {
+        print "Invalid Sleuth Kit binary directory: $::TSKDIR\n";
+        exit(1);
+    }
+
+    return if ($::LIVE == 1);
+
+    # Verify The evidence locker directory
+    unless ((defined $LOCKDIR) && ($LOCKDIR ne "")) {
+        print "ERROR: LOCKDIR variable not set in configuration file\n";
+        print "  This could been caused by an incomplete installation\n";
+        exit(1);
+    }
+
+    unless (-d "$LOCKDIR") {
+        print "Invalid evidence locker directory: $LOCKDIR\n";
+        exit(1);
+    }
+}
diff --git a/base/make-live-cd.base b/base/make-live-cd.base
new file mode 100644
index 0000000000000000000000000000000000000000..08c66e9f373194ca13ed38ce33dd114643ef7f7a
--- /dev/null
+++ b/base/make-live-cd.base
@@ -0,0 +1,153 @@
+#
+# This makes a directory ($CD) with the needed files to burn to
+# a CD for live analysis
+#
+# Current limitations are that Perl needs to be on the suspect system and
+# that it uses the untrusted Perl files.
+
+require 'conf.pl';
+use vars '$USE_STIMEOUT', '$STIMEOUT', '$CTIMEOUT', '$SAVE_COOKIE';
+use vars '$GREP_EXE', '$TSKDIR';
+
+
+my $CD = "./live-cd/";
+
+# Make the directories
+if (-d "$CD") {
+	print "Live CD directory already exists ($CD)\n";
+	print "Plese delete and run this again\n";
+	exit (1);
+}
+
+print "Making base directory ($CD)\n";
+die "Error making Live CD directory ($CD)"
+  unless (mkdir "$CD", 0775);
+
+die "Error making Live CD binaries directory ($CD)"
+  unless (mkdir "$CD/bin/", 0775);
+
+
+print "Copying executables\n";
+
+# Copy the executables
+die "Missing grep executable ($GREP_EXE)" 
+  unless (-x "$GREP_EXE");
+`cp '$GREP_EXE' '$CD/bin/grep'`; 
+die "Error copying grep executable" 
+  unless (-x "$CD/bin/grep");
+
+
+die "Missing MD5 executable ($::MD5_EXE)"
+  unless (-x "$::MD5_EXE");
+`cp '$::MD5_EXE' '$CD/bin/md5sum'`; 
+die "Error copying MD5 executable" 
+  unless (-x "$CD/bin/md5sum");
+
+# Sleuth Kit Binaries
+die "Missing Sleuth Kit Directory ($TSKDIR)"
+  unless (-d "$TSKDIR");
+
+foreach my $exec ("blkcalc", "blkcat", "blkls", "blkstat", "ffind", "fls", "fsstat", 
+  "icat", "ifind", "ils", "istat", "srch_strings", "img_stat", "mmls") {
+
+	die "Missing Sleuth Kit executable ($exec)" 
+	  unless (-x "$TSKDIR/$exec");
+
+	`cp '$TSKDIR/$exec' '$CD/bin/$exec'`; 
+
+	die "Error copying Sleuth Kit executable ($exec)" 
+	  unless (-x "$CD/bin/$exec");
+}
+
+
+# Make a fake file
+open FILE, ">$CD/bin/file" or die ("Error creating Live CD file exec");
+print FILE "#!./bin/perl\n";
+print FILE "print STDOUT \"File Type Not Supported During Live Analysis\n\";\n";
+close FILE;
+`chmod +x "$CD/bin/file"`;
+
+
+# Copy the autopsy directories
+print "Copying autopsy files\n";
+`cp -r help "$CD"`;
+`cp -r lib "$CD"`;
+`cp -r pict "$CD"`;
+
+
+# Get the path for Perl from the current autopsy
+open AUT, "<./autopsy" or die ("Error opening normal autopsy exec");
+my $perl;
+while (<AUT>) {		
+	$perl = $_;
+	last;
+}
+close AUT;
+
+if ($perl =~ /^#!(\S+)/) { 
+	$perl = $1;
+} else {
+	die "Error parsing Perl location from autopsy"
+}
+
+
+# Copy the perl exec
+# @@@ I'm not sure if just copying the bin is enough ...
+die "Missing Perl executable ($perl)" 
+  unless (-x "$perl");
+
+`cp '$perl' '$CD/bin/perl'`; 
+
+die "Error copying perl executable" 
+  unless (-x "$CD/bin/perl");
+
+
+# Make a new autopsy 
+open AUT, ">$CD/autopsy" or die ("Error opening Live CD autopsy exec");
+
+print AUT "#!./bin/perl -wT\n";
+print AUT "use lib '.';\n";
+print AUT "use lib './lib/';\n";
+
+
+open BASE, "<./base/autopsy.base" or die ("Error opening base autopsy");
+
+print AUT $_
+  while (<BASE>);
+
+close (AUT);
+close (BASE);
+
+`chmod +x "$CD/autopsy"`;
+
+
+print "Creating configuration file using existing settings\n";
+
+# Make the configuration file
+open CONF, ">$CD/conf.pl" or die ("Error opening Live CD Config file");
+
+print CONF "# Configuration file for Live CD version of Autopsy\n";
+print CONF "# http://www.sleuthkit.org/autopsy\n";
+print CONF "# Created on ".localtime()."\n\n";
+
+# Variables
+print CONF "\$USE_STIMEOUT = $USE_STIMEOUT;\n";
+print CONF "\$STIMEOUT = $STIMEOUT;\n";
+print CONF "\$CTIMEOUT = $CTIMEOUT;\n";
+print CONF "\$SAVE_COOKIE = $SAVE_COOKIE;\n";
+
+print CONF "\n";
+print CONF "\$INSTALLDIR = './';\n";
+print CONF "\$NSRLDB = '';\n";
+print CONF "\$LOCKDIR = './read-only-live-version/';\n";
+
+print CONF "\n";
+print CONF "# System Utilities\n";
+print CONF "\$GREP_EXE = './bin/grep';\n";
+print CONF "\$FILE_EXE = './bin/file';\n";
+print CONF "\$MD5_EXE = './bin/md5sum';\n";
+print CONF "\$TSKDIR = './bin/';\n";
+
+close CONF;
+
+print "\n";
diff --git a/configure b/configure
new file mode 100755
index 0000000000000000000000000000000000000000..72d5c84f009eea439cd578d35c49db714d8e8662
--- /dev/null
+++ b/configure
@@ -0,0 +1,475 @@
+#!/bin/sh
+
+# Minimum version of TSK that is required
+minver="3.1.0";
+
+# The last released version of TSK
+curtskver="3.1.1";
+
+# Configuration script for the Autopsy Forensic Browser
+#
+# Brian Carrier [carrier@sleuthkit.org]
+#
+# Copyright (c) 2003-2008 by Brian Carrier.  All rights reserved
+#
+# Copyright (c) 2001-2003 by Brian Carrier, @stake.  All rights reserved
+#
+# 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 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.
+
+
+# Directories to search in
+dirs='/usr/local/bin/ /usr/bin/ /usr/ccs/bin/ /bin/ /usr/ucb/bin/ /sbin/ /usr/sbin/ /usr/local/sbin/'
+
+
+echo ""
+echo "   Autopsy Forensic Browser Installation"
+echo ""
+
+
+
+#############################################################################
+# create conf.pl
+#############################################################################
+
+
+conf='conf.pl'
+
+rep=""
+if (test -f $conf) then
+  echo "A configuration file already exists, overwrite? (y/n):";
+  read rep;
+else
+  rep="y"
+fi
+
+if (test "$rep" = "y") then
+
+
+# First add the variables that are static
+#
+# DEFAULT USER SETTINGS
+#
+echo '# Autopsy configuration settings' > $conf
+echo '' >> $conf
+echo '# when set to 1, the server will stop after it receives no' >> $conf
+echo '# connections for STIMEOUT seconds. ' >> $conf
+echo '$USE_STIMEOUT = 0;' >> $conf
+echo '$STIMEOUT = 3600;'>> $conf    
+
+echo '' >> $conf
+echo '# number of seconds that child waits for input from client' >> $conf
+echo '$CTIMEOUT = 15;' >> $conf
+
+echo '' >> $conf
+echo '# set to 1 to save the cookie value in a file (for scripting)' >> $conf
+echo '$SAVE_COOKIE = 1;' >> $conf
+
+
+#############################################################################
+# INSTALLATION DIRECTORY
+#############################################################################
+echo '' >> $conf;
+echo \$INSTALLDIR = \'$PWD/\'\; >> $conf; 
+
+
+# Now add the variables that need user interaction
+
+#
+# FIND THE UTILITIES
+#
+echo '' >> $conf
+echo '' >> $conf
+echo '# System Utilities' >> $conf
+
+
+
+#
+# GREP
+#
+echo ''
+echo '---------------------------------------------------------------'
+echo ''
+found=0
+for d in $dirs 
+  do if (test -x ${d}grep) then
+    echo \$GREP_EXE = \'${d}grep\'\; >> $conf; 
+    echo "grep found: ${d}grep";
+    grepexe="${d}grep";
+    found=1; 
+    break; 
+  fi;
+done
+
+# Prompt if not found
+if (test $found -eq 0) then
+  echo 'ERROR: grep utility not found';
+  echo 'Enter location of executable:';
+  while (test 1 -eq 1) 
+    do read grepexe;
+    if (test -x "$grepexe") then
+	  echo \$GREP_EXE = \'$grepexe\'\; >> $conf; 
+      break;
+    else
+      echo 'grep was not found (try again):';
+    fi;
+  done
+fi
+
+
+#
+# FILE
+#
+found=0
+for d in $dirs 
+  do if (test -x ${d}file) then
+    echo \$FILE_EXE = \'${d}file\'\; >> $conf; 
+    echo "file found: ${d}file";
+    found=1; 
+    break; 
+  fi;
+done
+
+# Prompt if not found
+if (test $found -eq 0) then
+  echo 'ERROR: file utility not found';
+  echo 'Enter location of executable:';
+  while (test 1 -eq 1) 
+    do read fileexe;
+    if (test -x "$fileexe") then
+	  echo \$FILE_EXE = \'$filexe\'\; >> $conf; 
+      break;
+    else
+      echo 'file was not found (try again):';
+    fi;
+  done
+fi
+
+#
+# MD5
+#
+found=0
+for d in $dirs 
+  do if (test -x ${d}md5) then
+    echo \$MD5_EXE = \'${d}md5\'\; >> $conf; 
+    echo "md5 found: ${d}md5";
+    found=1; 
+    break; 
+  elif (test -x ${d}md5sum) then
+    echo \$MD5_EXE = \'${d}md5sum\'\; >> $conf; 
+    echo "md5 found: ${d}md5sum";
+    found=1; 
+    break; 
+  fi;
+done
+
+# Prompt if not found
+if (test $found -eq 0) then
+  echo 'ERROR: md5/md5sum utility not found';
+  echo 'Enter location of executable:';
+  while (test 1 -eq 1) 
+    do read md5exe;
+    if (test -x "$md5exe") then
+	  echo \$MD5_EXE = \'$md5exe\'\; >> $conf; 
+      break;
+    else
+      echo 'md5 was not found (try again):';
+    fi;
+  done
+fi
+
+
+#
+# SHA-1
+#
+found=0
+for d in $dirs 
+  do if (test -x ${d}sha15) then
+    echo \$SHA1_EXE = \'${d}sha\'\; >> $conf; 
+    echo "sha1 found: ${d}sha1";
+    found=1; 
+    break; 
+  elif (test -x ${d}sha1sum) then
+    echo \$SHA1_EXE = \'${d}sha1sum\'\; >> $conf; 
+    echo "sha1 found: ${d}sha1sum";
+    found=1; 
+    break; 
+  fi;
+done
+
+if (test $found -eq 0) then
+  echo 'WARNING: sha1/sha1sum utility not found';
+  echo \$SHA1_EXE = \'\'\; >> $conf; 
+fi;
+
+
+
+#############################################################################
+# The Sleuth Kit
+#############################################################################
+
+echo '' >> $conf
+echo '' >> $conf
+echo '# Directories' >> $conf
+
+echo ''
+echo '---------------------------------------------------------------'
+echo ''
+echo 'Searching for Sleuth Kit Installation.'
+found=0
+for d in $dirs 
+  do if ((test -x ${d}fls) && (test -x ${d}ffind) && (test -x ${d}blkstat) && \
+          (test -x ${d}blkls) && (test -x ${d}blkcat) && \
+          (test -x ${d}mmls) && (test -x ${d}mmstat) && \
+          (test -x ${d}fsstat) && (test -x ${d}img_stat) && \
+          (test -x ${d}istat) && (test -x ${d}ifind) && \
+          (test -x ${d}icat) && (test -x ${d}ils) && \
+          (test -x ${d}srch_strings) && \
+          (test -x ${d}mactime) && (test -x ${d}sorter)) then
+    echo \$TSKDIR = \'${d}\'\; >> $conf;
+    tskdir=${d};
+    echo "Found in: ${d}";
+    found=1; 
+    break; 
+  fi;
+done
+
+if (test $found -eq 0) then
+  echo 'Sleuth Kit tools were not found in the standard install locations.'
+  echo 'If you have not installed them, do so now and configure autopsy again.'
+  echo 'If you have installed them in a non-standard location, then'
+  echo '  enter the "bin" directory now:'
+
+  while (test 1 -eq 1) 
+    do read tskdir;
+    if ((test -x ${tskdir}/fls) && (test -x ${tskdir}/ffind) && (test -x ${tskdir}/blkstat) && \
+          (test -x ${tskdir}/blkls) && (test -x ${tskdir}/blkcat) && \
+          (test -x ${tskdir}/mmls) && (test -x ${tskdir}/mmstat) && \
+          (test -x ${tskdir}/fsstat) && (test -x ${tskdir}/img_stat) && \
+          (test -x ${tskdir}/istat) && (test -x ${tskdir}/ifind) && \
+          (test -x ${tskdir}/icat) && (test -x ${tskdir}/ils) && \
+          (test -x ${tskdir}/srch_strings) && \
+          (test -x ${tskdir}/mactime) && (test -x ${tskdir}/sorter)) then
+      echo \$TSKDIR = \'${tskdir}\'\; >> $conf;
+      break;
+    else
+      echo 'TSK tools were not found or incomplete (try again):';
+    fi;
+  done
+fi;
+
+# Test for latest version
+ver=`"${tskdir}/fls" -V | awk '/The Sleuth Kit ver / {print $5}'`;
+echo "  Version $ver found";
+
+
+if (test "$ver" '<' "$minver") then 
+  echo "Your version of The Sleuth Kit is not current enough - $minver is needed";
+  if (test "$ver" '>' "0.0.0") then 
+    exit 1;
+  fi;
+elif (test "$ver" '<' "$curtskver") then 
+	echo '';
+    echo "*** NOTE: A more recent version ($curtskver) of The Sleuth Kit Exists ***"
+	echo "  [Press Enter to Continue]";
+	read foo;
+
+else
+	echo '  Required version found';
+fi
+
+
+
+# NSRL
+echo ''
+echo '---------------------------------------------------------------'
+echo ''
+echo 'The NIST National Software Reference Library (NSRL) contains'
+echo 'hash values of known good and bad files.'
+echo '         http://www.nsrl.nist.gov'
+echo ''
+echo 'Have you purchased or downloaded a copy of the NSRL (y/n) [n]'
+read rep;
+if (test "$rep" = "y") then
+
+  echo 'Enter the directory where you installed it:'
+  while (test 1 -eq 1) 
+    do read nsrldir;
+    if (test "$nsrldir" = "cancel") then
+        echo \$NSRLDB = \'\'\; >> $conf;
+		break;
+	fi;
+    if (test -f "${nsrldir}/NSRLFile.txt") then
+      echo '  NSRL database was found (NSRLFile.txt)';
+      echo \$NSRLDB = \'${nsrldir}/NSRLFile.txt\'\; >> $conf;
+
+	  if (test -f "${nsrldir}/NSRLFile.txt-md5.idx") then
+		echo '  NSRL Index file found (NSRLFile.txt-md5.idx)';
+      else
+        echo '  NSRL Index file not found, do you want it created? (y/n) [n]:'
+        read rep;
+        if (test "$rep" = "y") then
+          echo ''
+          echo '-------------- begin hfind output --------------'
+          "${tskdir}/hfind" -i nsrl-md5 "${nsrldir}/NSRLFile.txt";
+          echo '--------------- end hfind output ---------------'
+          echo ''
+		fi;
+	  fi;
+      break;
+    else
+      echo 'The NSRL was not found (the directory should have NSRLFile.txt in it)';
+	  echo 'Enter a new directory (or cancel to stop):';
+    fi;
+  done
+else
+  echo \$NSRLDB = \'\'\; >> $conf;
+fi;
+
+#############################################################################
+# EVIDENCE LOCKER
+#############################################################################
+mdone=0
+echo ''
+echo '---------------------------------------------------------------'
+echo ''
+echo 'Autopsy saves configuration files, audit logs, and output to the'
+echo 'Evidence Locker directory.'
+echo ''
+echo 'Enter the directory that you want to use for the Evidence Locker:';
+read locker;
+if (test -d "${locker}") then
+  echo "  $locker already exists"
+else
+  echo '';
+  echo "WARNING: $locker does not exist"
+  mdone=1
+fi
+
+echo \$LOCKDIR = \'${locker}\'\; >> $conf;
+
+fi
+
+# Start of non-conf.pl file configuration
+
+#############################################################################
+# Setup Perl locations
+#############################################################################
+found=0;
+
+for d in $dirs
+  do if (test -x ${d}perl) then
+    if (test -n "`${d}perl -v 2> /dev/null | awk '/This is perl/ {print $0}'`") then
+      ver=`${d}perl -e 'print $];'`;
+      if (`${d}perl -e 'exit( $] >= 5.008);'`) then 
+        echo "old version of perl found: ${d}perl (version $ver) -- continuing";
+      else      
+        echo "perl found: ${d}perl (version $ver)";
+        echo "#!${d}perl -wT" > ./config.tmp;
+        echo "#!${d}perl" > ./config2.tmp;
+        perlexe="${d}perl";
+        found=1; 
+        break; 
+      fi;
+    fi;
+  fi;
+done
+
+# If it wasn't found, then prompt for it.
+if (test $found -eq 0) then
+  echo 'ERROR: perl not found or the incorrect version found';
+  while (test 1 -eq 1) 
+    do echo 'Enter location of perl executable:';
+    read perlexe;
+    if (test -x "$perlexe") then
+      if (test -n "`$perlexe -v 2> /dev/null | awk '/This is perl/ {print $0}'`")       then
+        ver=`$perlexe -e 'print $];'`;
+        if (`$perlexe -e 'exit( $] >= 5.008);'`) then 
+          echo "This version of Perl is too old, 5.8.0 or older needed";
+        else      
+          echo "Correct version found";
+          echo "#!${perlexe} -wT" > ./config.tmp;
+          echo "#!${perlexe}" > ./config2.tmp;
+          found=1; 
+          break; 
+        fi;
+      else
+        echo "Perl found, but is not working.  Try another";
+      fi;
+    else
+      echo "file not found";
+    fi
+  done
+fi
+
+# Check if this version of Perl supports large files
+if (test -z "`$perlexe -V 2> /dev/null | awk '/USE_LARGE_FILES/ {print $0}'`") then
+  echo ''
+  echo '    NOTE: It appears that your Perl does not support large files.';
+  echo '    You therefore will not be able to analyze images larger than 2GB.';
+  echo '    Download the source version from www.cpan.org and compile a new version.';
+  echo "  [Press Enter to Continue]";
+  read foo;
+  echo ''
+fi;
+
+# Get current working directory for lib
+echo "use lib '$PWD/';" >> ./config.tmp
+echo "use lib '$PWD/lib/';" >> ./config.tmp
+
+if (test -f ./autopsy) then
+  echo "autopsy already exists, overwrite? (y/n):";
+  read rep;
+  if (test "$rep" = "y") then
+    cat ./config.tmp base/autopsy.base > ./autopsy
+    cat ./config2.tmp base/make-live-cd.base > ./make-live-cd
+  else 
+    echo '  original version was kept';
+  fi
+else
+  cat ./config.tmp base/autopsy.base > ./autopsy
+  cat ./config2.tmp base/make-live-cd.base > ./make-live-cd
+fi
+chmod 0755 ./autopsy
+chmod 0755 ./make-live-cd
+
+# cleanup
+rm -f ./config.tmp
+rm -f ./config2.tmp
+
+
+#############################################################################
+# CLEANUP
+#############################################################################
+echo ''
+echo '---------------------------------------------------------------'
+echo ''
+echo "Execute the './autopsy' command to start with default settings."
+echo ''
+
diff --git a/docs/sleuthkit-informer-13.txt b/docs/sleuthkit-informer-13.txt
new file mode 100644
index 0000000000000000000000000000000000000000..24d55bb371a330bb63fa5c4142ab9abfe996677d
--- /dev/null
+++ b/docs/sleuthkit-informer-13.txt
@@ -0,0 +1,410 @@
+                        The Sleuth Kit Informer
+
+                    http://www.sleuthkit.org/informer
+                http://sleuthkit.sourceforge.net/informer
+
+                             Brian Carrier
+                      carrier at sleuthkit dot org
+
+                               Issue #13
+                             March 15, 2004
+
+
+
+CONTENTS
+--------------------------------------------------------------------
+- Introduction
+- What's New?
+- Call For Papers
+- Did You Know?
+- UNIX Incident Verification With Autopsy 
+
+
+
+INTRODUCTION
+--------------------------------------------------------------------
+
+I'm almost done!  Releasing version 2.00 of Autopsy that is.  I'm
+polishing up the final changes and documentation and it will be
+released later this week.  March 19 is the birthday of Autopsy and
+The Sleuth Kit's predecessor, TCTutils, also the goal release date
+for version 2.00.
+
+This issue of the Informer will focus on the new live analysis
+feature of (the unreleased) Autopsy.  This issue also has a lot
+entries in the "What's New?" category because we are on a bimonthly
+schedule.   If you missed getting the February issue of The Informer
+and have lessons to share with people then make sure you read the
+Call For Papers section so that you can learn how to submit articles
+of your own.
+
+
+
+WHAT'S NEW?
+--------------------------------------------------------------------
+A new version (1.68) of The Sleuth Kit was released.  It contains
+a couple of bug fixes.  There have been discussions on the
+sleuthkit-developers list about what new functions should be added
+to the next big version 2.00 release.  Michael Cohen has been looking
+into support for disk images, split images, RAID images, and other
+non-raw formats.  David Collett has been looking into output formats
+for TSK tools so that they can be imported into databases.
+
+Version 2.00 of Autopsy will be released later this week.  I'm
+adding the final touches and documentation and the goal is to release
+it on March 19, which is the 3 year anniversary of the first release
+of Autopsy and TCTutils.   Version 2.00 has a new internal design
+and has live analysis features (see below article).  If you can't
+wait for a few days and want one of the beta copies, let me know.
+
+Guido Metzner has been translating The Sleuth Kit Informer into
+German.  If anyone else is translating this, let me know and I'll
+add a link.
+
+    http://www.guframe.de/sleuthkit.html
+
+
+I started to provide a GPG signature of the source code as it is
+released.  I have meant to do this for ages.  This can help to
+ensure that the code being downloaded has not been modified by an
+attacker.
+
+
+
+CALL FOR PAPERS
+--------------------------------------------------------------------
+
+I posted a call for papers on the website in late  January for
+people that are interested in writing articles for the Informer.
+Here is the relevant section:
+
+The Sleuth Kit Informer is looking for articles on open source tools
+and techniques for digital investigations (computer / digital
+forensics) and incident response. Articles that discuss The Sleuth
+Kit and Autopsy are appreciated, but not required. Example topics
+include (but are not limited to):
+
+- Tutorials on open source tools
+- User experiences and reviews of open source tools
+- New investigation techniques using open source tools
+- Open source tool testing results 
+
+http://www.sleuthkit.org/informer/cfp.html
+
+
+Writing these articles takes away from my development time of new
+tool features, so any help is appreciated.  To keep with the incident
+verification theme, any articles on the basics of using 'netstat',
+'lsof', etc. to look for signs of an intrusion are also welcome for
+the next few issues.  If we get enough interest, I'll consider going
+back to a monthly schedule.
+
+
+
+DID YOU KNOW?
+--------------------------------------------------------------------
+
+Have you ever noticed that the number of occurrences and locations
+of keywords for regular expressions in Autopsy are not always
+accurate?  This came up on one of the mailing lists this past month
+and I'll explain it again here.
+
+Previous issues of The Informer have covered keyword searching, but
+the general idea in Autopsy is that it runs the 'strings' command
+on the image file and then uses 'grep' to find the keyword.  The
+'strings' command returns a long ASCII string that grep examines.
+If the keyword is found in the string, then grep fill flag the
+string and autopsy will search the string to find the exact location
+of the keyword.
+
+This is easy if a non-regular expression is used, but much more
+difficult with regular expressions because 'grep' regular expressions
+are different from Perl regular expressions.  I do not have a way
+to convert the grep regular expression to Perl and therefore I only
+return the number of big strings that have the keyword and the
+location of the start of the big string.  There could be more than
+one keyword in the string, in which case the total occurrences value
+is too small.  The location will also be off because it points to
+the start of the large string and not the specific keyword.
+
+If anyone knows of, or wants to write, a grep to perl regular
+expression converter, let me know so that we can update this.
+
+
+
+UNIX INCIDENT VERIFICATION WITH AUTOPSY
+--------------------------------------------------------------------
+
+INTRODUCTION
+
+For a couple of years, I have been saying that Autopsy can be used
+to analyze a live system, but it has taken me a while to make it
+EASY to use to analyze a live system.  When version 2.0 of Autopsy
+is released later this week, you will find that it is much easier
+to configure so that it runs on a CD-ROM so that you can examine a
+system that is suspected of being compromised.  This will allow you
+to view files that are hidden by rootkits and will not change the
+access times on files that are viewed.
+
+This article will give an overview of how to use the new features
+and what features are available for dead analysis are not for live
+analysis.  I will also show the future work for Autopsy.  This
+article uses many of the same concepts as the "UNIX Incident
+Verification with The Sleuth Kit" article in issue #10 of the
+Informer.
+
+MOTIVATION
+
+Some may be asking "why would I want a live analysis feature?".
+The primary motivation is for a more automated Incident Verification
+procedure.  We saw in issue #10 of the Informer, that The Sleuth
+Kit can be used to verify an incident because it can show files
+that are hidden by rootkits and will not update the access times
+on files when they are read.  Executing a bunch of command line
+tools is tedious though and Autopsy can provide a more automated
+investigation procedure.
+
+The basic scenario is that Autopsy and The Sleuth Kit will be burned
+to a CD and inserted into a suspect computer.  An investigator will
+connect to Autopsy on the suspect UNIX computer with her HTML browser
+on a trusted laptop and remotely examine the hard disk contents.
+If the computer is found to have been compromised, then it can be
+taken offline and acquired using normal procedures.
+
+Recall from issue #10 that I used two guidelines for incident
+verification:
+
+  1.  Minimize the amount of trust that you place in the system so
+  that more accurate information is collected.
+
+  2. Minimize the amount of data that you change on the system so
+  that evidence is preserved.
+
+
+CREATING THE CD
+
+To satisfy guideline #1 from above, we want to minimize the amount
+of trust that we place in the system, so we use our own executables.
+At a minimum, we need The Sleuth Kit and Autopsy on the CD and you
+will probably have additional tools to examine open network ports
+and running processes.  This has been the most difficult part of
+using Autopsy for live analysis because Autopsy relies on a given
+directory structure and locations that it can write to.
+
+It is now very easy with v2.  With v2, you compile TSK and Autopsy
+on a similar system to the one that will be investigated just like
+you do for a dead analysis.  Try the 'make static' with TSK to see
+if you can make static executables for your platform.  After both
+Autopsy and TSK have been compiled, you execute the 'make-live-cd'
+command in Autopsy.  This script will make a 'live-cd' sub-directory
+in the autopsy directory, which contains a copy of autopsy and
+copies of TSK executables, grep, strings, perl etc:
+
+    # ./make-live-cd 
+    Making base directory (./live-cd/)
+    Copying executables
+    Copying autopsy files
+    Creating configuration file using existing settings
+
+
+The 'live-cd' directory has a 'bin' directory where additional
+executables can be copied to and then the whole directory can be
+burned to a CD.
+
+
+BASIC USAGE
+
+After the CD has been created and there is a system suspected of
+being compromised, then it is time to take advantage of the new
+features.  There are two scenarios for live analysis.  The first
+scenario uses a network share from a trusted system that you can
+write to.  In this case, autopsy is run as normal and you specify
+the evidence locker directory as the mounted disk.  The evidence
+locker is specified with '-d':
+
+    # ./autopsy -d /mnt/ev_lock 10.1.32.123
+
+The above would start autopsy, use '/mnt/ev_lock/' as the evidence
+locker and would allow connections from 10.1.32.123 (where the
+investigator would connect from using an HTML browser).  Remember that
+we do not want to write to the suspect system, so we should only use
+a network share and not a local directory in this scenario.
+
+The second scenario does not use an evidence locker and does not
+intentionally write any data to disk.  This scenario does not need
+the network share and each of the devices (or partitions) that will
+be analyzed are specified on the command line using the '-i' flags.
+The '-i' flag requires three arguments: the device, the file system
+type, and the mounting point.  For example, to examine the '/dev/hda5'
+and '/dev/hda8' partitions on a Linux system, the following could
+be used:
+
+    # ./autopsy -i /dev/hda5 linux-ext3 / -i /dev/hda8 linux-ext3 /usr/ \
+    10.1.32.123
+
+The file system type must be one of the types that are supported
+by TSK.  The remote IP address must also be given, otherwise you
+will have to use a browser on the suspect system and that will write
+data to the disk.
+
+When you use the '-i' flag, then autopsy will start in the 'Host
+Manager' view where you can select the image that you want to
+analyze.  You will skip the case and host configuration.  The default
+case name will be 'live', the default host name is 'local', and the
+default investigator name is 'unknown'.
+
+
+DIFFERENCES WITH DEAD ANALYSIS
+
+There are some features that are not available for live analysis
+because they write files to the disk.  In this section, I am using
+the term live analysis for the scenario where there is not a mounted
+network share and there is not evidence locker.
+
+No auditing is performed during a live analysis because there is
+no where to write the logs.  In the future, if this is needed, then
+a method of writing logs to a floppy disk could be configured.
+Timelines of file activity cannot be created because they need to
+create files.  Hash databases are also not currently used, although
+they could in the future.  It may be difficult to maintain the
+latest hash database on the same CD as the latest autopsy and TSK
+version though.  Notes and event sequencer notes cannot be created.
+
+Keyword searches can be performed, but the strings file and unallocated
+only search cannot be performed because they both require a file
+to be created.  The search results are also not cached.  You can
+also not sort files by their type (all executables, all pictures
+etc.).  In many cases, you would not want to do many of these
+operations because they are time intensive and you are generally
+looking for obvious and quick evidence during the incident verification.
+If you need theses features, then you can use the network share
+scenario.
+
+
+SIMILARITIES WITH DEAD ANALYSIS
+
+Now that we know what is different, I'll cover what is the same.
+All of the file mode analysis is the same, except that you cannot
+get the file type.  The method that is used to compile 'file' in
+TSK does not allow autopsy to easily move it around.  This behavior
+may change in the future.  Meta data, data unit, and file system
+mode all work as usual.
+
+You can still export file contents to your trusted laptop because
+it uses the HTTP to save the file.  So, you can select the export
+button on a log file to save a copy.  You can also generate ASCII
+reports and save them to your local analysis station.
+
+
+GUIDELINE COMPLIANCE
+
+All of these features may sound great, but lets examine how well
+the new Autopsy satisfies the two guidelines.  I think it is always
+important to compare a new tool or technique against generic
+guidelines.
+
+The first guideline was about not trusting the local system.  No
+software-based live analysis tool can be 100% independent from the
+local system because it always needs to request service from the
+operating system.  With Autopsy, we use our own copies of the Autopsy
+perl code, TSK executables, grep, and strings.
+
+There is one large problem with the current Autopsy model and it
+is because of Perl.   Perl is a beast and contains many modules and
+libraries.  When the 'make-live-cd' script is run, a copy of the
+'perl' executable is copied to the 'live-cd' directory, but that
+is it.  The executable will still need the modules and libraries
+on the local system.  Solving this may require building a special
+version of Perl that is more static.  I need to investigate this
+more.
+
+Another method of getting around this limitation is to use the
+'perl2exe' program that converts a Perl script to a dynamic executable.
+The resulting executable will still rely on dynamic libraries on
+the suspect system, but  it seems a little cleaner.  The perl2exe
+program is a commercial tool.
+
+One of the benefits of the Autopsy design, is that Autopsy did not
+exist on the system when it was suspected of being compromised.
+Therefore, the attacker will not know that Autopsy will be used to
+investigate the system and therefore will be less likely to tamper
+with its dependencies.  If the investigation tools are running on
+the system during the attack, then I would guess that the attacker
+will be more likely to tamper with them.
+
+The second guideline was about modifying data on the system.  I
+described the features that were removed in the previous section.
+This was easy to do because there were functions that write the
+logs or notes.  Each of those starts with a check to see if logging
+is enabled.  Timelines and file type sorting were also disabled
+because it required writing to disk.
+
+I can never guarantee that no data will be written from a live
+analysis.  Memory will be overwritten when the software is loaded
+and the access times on dynamic libraries will updated.  Running
+the tools may require the operating system to write memory to the
+page file, which may overwrite data from the attacker.
+
+This is a shameless plug, but for those that are interested in live
+analysis, then you may want to check out a paper that a colleague,
+Joe Grand (author of pdd), and I wrote about a hardware device to
+acquire memory from a live system.  It does not overwrite memory
+because there is no process to load and it access the physical
+memory directly so it does not rely on the local operating system.
+It was recently published in the new Journal of Digital Investigation
+(reference is below and that issue of the journal is currently free
+to view).
+
+
+
+FUTURE WORK
+
+There is always more to do, and I'll cover that here.  
+
+I would like to also include other system utilities, such as 'ps' or
+'netstat' on the CD and allow the Autopsy user to run the commands
+from within autopsy.  This should be fairly easy, but the difficult
+part is that many of the operating systems use different flags for
+different tools.
+
+I would like to start incorporating scripts into the tool (for both dead
+and live analysis).  This will allow you to more easily detect rootkits
+or other signatures.   
+
+The biggest thing that needs future work is using Perl.  Autopsy
+still relies on the version of Perl on the suspect system and that
+could run into problems if an attacker modifies it.  Using the 
+perl2exe tool can reduce the risk, but it is a commercial tool.
+
+
+CONCLUSION
+
+The live analysis mode of Autopsy allows you to more easily analyze
+a system that is suspected of being compromised.  It can also be
+used to examine a honeypot.  Live analysis is not ideal because you
+are stilly relying on the suspect operating system for data, but
+it is required in some situations.  More work needs to be done with
+Autopsy so that it depends less on the local system.  
+
+
+
+REFERENCES
+Autopsy
+    http://www.sleuthkit.org/autopsy/ 
+
+perl2exe
+    http://www.indigostar.com/perl2exe.htm
+
+Sleuth Kit
+    http://www.sleuthkit.org/sleuthkit 
+
+Sleuth Kit Informer #10
+    http://www.sleuthkit.org/informer/sleuthkit-informer-10.html
+
+A hardware-based memory acquisition procedure for digital investigations
+    Brian D. Carrier and Joe Grand
+	Volume 1, Issue 1 - Journal of Digital Investigations
+    http://www.sciencedirect.com/science/journal/17422876
+
+--------------------------------------------------------------------
+Copyright (c) 2004 by Brian Carrier.  All Rights Reserved
diff --git a/global.css b/global.css
new file mode 100644
index 0000000000000000000000000000000000000000..d44dcca67316383527c078fff37768e0ee044b73
--- /dev/null
+++ b/global.css
@@ -0,0 +1,19 @@
+h3 {
+	font-size: 18px;
+	color: #000000;
+}
+h2 {
+	font-size: 20px;
+	color: #000000;
+}
+h1 {
+	font-size: 24px;
+	color: #000000;
+}
+body {
+	font-family: Helvetica, Geneva, Arial, sans-serif;
+	font-size: 14px;
+	color: #000000;
+	#background-color: #dedede;
+}
+
diff --git a/help/blank.html b/help/blank.html
new file mode 100644
index 0000000000000000000000000000000000000000..3e40eb24cf48c53e5da913ddad3895ec6ef249e3
--- /dev/null
+++ b/help/blank.html
@@ -0,0 +1,25 @@
+<HTML>
+<HEAD><TITLE>Blank Page</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+  &nbsp;
+  <p>
+  &nbsp;
+  <p>
+  &nbsp;
+  <p>
+  <center>
+  <h3>HELP!</h3> 
+  Here are the help files for using Autopsy.
+
+  <p>In addition to these files, the <tt>Sleuth Kit Informer</tt>
+  newsletter could be useful.<br>
+  The Informer typically goes into more technical details than what
+  is provided here.</p>
+  
+  <p><a href="http://www.sleuthkit.org/informer/" target=\"_blank\">
+  http://www.sleuthkit.org/informer/</a></p>
+
+  <p>Send documentation updates to &lt;doc-updates at sleuthkit dot org&gt;</p>
+
+</BODY>
+</HTML>
diff --git a/help/caseman.html b/help/caseman.html
new file mode 100644
index 0000000000000000000000000000000000000000..ee4fc315b86143faf05256139ada72f69a1b043d
--- /dev/null
+++ b/help/caseman.html
@@ -0,0 +1,161 @@
+<HTML>
+<HEAD><TITLE>Autopsy Case Management Help</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+
+<CENTER><H2>Case Management</H2></CENTER>
+<P> 
+<H3>Overview</H3>
+Autopsy organizes images based on the case and host that they came
+from.  A case contains one or more hosts (a new case should be
+created for each investigation).  Each host can contain one or more
+images, which correspond to disks or partitions on the host.
+
+
+<P>
+<H3>Creating a New Case</H3>
+From the Main Menu (at startup) select <U>New Case</U>.  You will
+have to enter the case name and an optional short description.
+The case name must be a valid directory name (no spaces - no
+symbols).  A list of investigators will also be requested.  These
+will be used for the audit logs, not for authentication.  A directory
+with the same name as the case will be created in the Evidence
+Locker.  To later rename the case, simply rename the directory.
+
+<P>
+For example:
+<TABLE CELLSPACING=8>
+<TR>
+  <TD>Case Name:</TD><TD><TT>bankofmars</TT></TD>
+</TR>
+<TR>
+  <TD>Case Description:</TD><TD><TT>Theft of $1,000,000,000.01 from The Bank of Mars</TT></TD>
+</TR>
+<TR>
+  <TD>Investigators:</TD><TD><TT>gadget</TT></TD>
+</TR>
+</TABLE>
+
+<P>
+<H3>Adding a New Host</H3>
+A Host must then be created in the Case.  Select the Case that was
+just created from the Case Gallery and enter the Host Gallery.
+Select <U>Add Host</U> and enter the host name, a short description,
+and time information such as time zone and clock skew.  The clock
+skew is how many seconds the system was off from a synchronized
+clock.  Adding a host will create a directory in the case directory
+and subdirectories in the host for the images, output data, logs,
+and reports.   If you do not add a time zone, then it will default to
+the time zone of your analysis system.  A list of time zones can be
+found <a href="timezones.html">here</a>.
+
+<P>
+You can optionally add the path to <A HREF="hash_db.html">hash databases</A>.
+
+<P>
+For example, the 'Bank of Mars' incident could have two hosts
+involved:
+
+<TABLE CELLSPACING=8>
+<TR>
+  <TD>Host Name:</TD><TD><TT>db_server</TT></TD>
+</TR>
+<TR>
+  <TD>Host Description:</TD><TD><TT>Main Database Server - Solaris</TT></TD>
+</TR>
+<TR>
+  <TD>Timezone:</TD><TD><TT>EST5EDT</TT></TD>
+</TR>
+<TR>
+  <TD>Timeskew:</TD><TD><TT>-100</TT></TD>
+</TR>
+<TR>
+  <TD>Known Good Database:</TD><TD><TT>none</TT></TD>
+</TR>
+<TR>
+  <TD>Known Bad Database:</TD><TD><TT>none</TT></TD>
+</TR>
+</TABLE>
+
+<P>
+<TABLE CELLSPACING=8>
+<TR>
+  <TD>Host Name:</TD><TD><TT>file_server</TT></TD>
+</TR>
+<TR>
+  <TD>Host Description:</TD><TD><TT>Windows File Server - Win 2k</TT></TD>
+</TR>
+<TR>
+  <TD>Timezone:</TD><TD><TT>CST6CDT</TT></TD>
+</TR>
+<TR>
+  <TD>Timeskew:</TD><TD><TT>0</TT></TD>
+</TR>
+<TR>
+  <TD>Known Good Database:</TD><TD><TT>/usr/local/forensics/hash/win2k.txt</TT></TD>
+</TR>
+<TR>
+  <TD>Known Bad Database:</TD><TD><TT>/usr/local/forensics/hash/win_hack.txt</TT></TD>
+</TR>
+</TABLE>
+
+<P>
+<H3>Adding a New Image</H3>
+Next, images must be added to the host.  Select the host that was
+just added from the Host Gallery and enter the Host Manager.  Select
+<U>Add Image File</U> and a new form is shown.  The first text box in
+the form is for the path of the image file.  If you are importing a
+split image, then the extension must be ordered based on the file order.
+Supply a '*' in the file name extension where the numbers or letters are.
+(i.e. .../image.*).  The image file can be
+of a full disk or of an individual partition.  You must select which
+it is though.  Before they can analyzed, the images will have to
+be located in the evidence locker.  You are given a choice to either
+create a symbolic link from the current location, to copy the file,
+or to move the file from its current location to the host directory.
+Select the desired import method.  For example:
+
+<TABLE CELLSPACING=8>
+<tr><td>Image Path:</TD><TD><TT>/mnt/sys1/disk2.*</TT></TD></TR>
+<tr><td>Type:</td><td><tt>Disk</tt></td></tr>
+<tr><td>Import Action:</TD><TD><TT>symlink</TT></TD></TR>
+</table>
+
+<p>
+If you are importing a split image, then the next window will confirm the
+order of the images.  After that, the next window will allow you to specify
+or calculate the MD5 for the file.  This should be of the full file and if you
+are importing a split image then it should be for all files combined.  
+If you are importing a volume image, then Autopsy will try to determine the
+file system type.  You will also need to specify the mounting point.  This is used for cosmetic purposes only when printing the full path of files.
+
+<p>
+If the image file is a disk image then Autopsy will list all of the partitions and try to determine the file system in each one.  You have the option to not import a partition and to change the file system type. 
+
+<P>
+<H3>MD5 Values</H3>
+Each host has an <TT>md5.txt</TT> file that contains
+the MD5 value for files in that directory.  Autopsy  uses that file
+to validate the integrity of files.   By default, when a file is
+imported into Autopsy, its MD5 will be calculated.  If it is already
+known, then it can be entered in the 'Add Images' window.
+
+
+<P>
+<H3>Host Subdirectories</H3>
+Each host has an <TT>images</TT> directory and an <TT>output</TT>
+directory.  All data generated by Autopsy is saved to the <TT>output</TT>
+directory.  The theory behind this design, was to allow the <TT>images</TT>
+directory to have strict permissions to prevent accidently modifying
+the images.  Therefore, the <TT>images</TT> directory can have its write
+bits removed to prevent modifications.
+
+<p>
+<h3>References</h3>
+Issue 2 of <a href="http://www.sleuthkit.org/informer/"  target=\"_blank\">The Sleuth Kit Informer</a> discusses case management and how to break a disk image into file system images.
+
+
+
+<P><HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/data_mode.html b/help/data_mode.html
new file mode 100644
index 0000000000000000000000000000000000000000..db2d20eafd32959ad8fbd18349940d7e55f03a16
--- /dev/null
+++ b/help/data_mode.html
@@ -0,0 +1,97 @@
+<HTML>
+<HEAD><TITLE>Autopsy Data Unit Analysis Help</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+<CENTER><H2>Data Unit Analysis</H2></CENTER>
+
+
+<H3>Overview</H3>
+<P>
+The Data Analysis Mode allows an investigator to view the contents
+of an individual data unit.  Data units is a generic term used to
+describe the areas on the disk that are used to store data.  Each
+file system calls the data unit a different thing (i.e.  Fragments
+or Clusters).  This mode is most useful when recovering and analyzing
+deleted data.
+
+<H3>Input</H3>
+<P>
+To view the contents of a specific address, enter it into the text
+box on the left-hand side.  By default, only one data unit will be
+displayed.  To view more than one consecutive unit, enter the
+number in the text box below. 
+
+<P>
+It is common to extract the unallocated space from a file system
+image and analyze it for deleted material.  The 'blkls' tool in The
+Sleuth Kit allows one to extract the data.  If interesting data is
+found in the 'blkls' file, the next step could be to find its location
+in the original image and examine the surrounding data.  To do
+this, simply calculate which data unit the data was found in (by
+dividing the byte offset of the interesting data by the data unit
+size (which can be found in <U>Image Details</U>)).  Enter that
+address into the original text box and select the <U>Unallocated</U>
+type.  This will find the original location and display it for you.
+
+<P>
+If Autopsy knows about the 'blkls' image, then it can be loaded at any
+time by selecting the <U>Load Unallocated</U> button.  Then, any
+data unit in that file can be examined.  
+
+
+<P>
+The <B>Lazarus</B> tool was part of <TT>TCT</TT>.  It analyzes a chunk
+of data and identifies what file type it is and tries to group 
+consecutive types together.  Lazarus numbers its output though starting
+with 1.  Therefore, instead of subtracting 1 every time you want to view
+a data unit identified by Lazarus, simply select the check box.  
+
+<P>
+Press the <U>Ok</U> button to display the contents of the address on
+the right-hand side of the window.  
+
+<P>
+The <U>Allocation List</U> link displays the allocation status of  
+addresses in intervals of 500.  
+
+
+<H3>Viewing</H3>
+<P>
+After the unit address has been entered, the contents are displayed
+in the right-hand side.  Filters can be used to view the data in the
+desired format (strings, hexdump, ASCII).
+
+<P>
+A report can be generated so that the contents and meta-data about
+it will be saved on record.  To save the contents locally, press the
+<U>Export Contents</U> button.  The <U>Add Note</U> button will allow
+one to add a comment about the given data unit so that it can be
+easily recalled later.  
+
+<P>
+The file type is also displayed.  This is identified by running
+the output through the 'file' command in The Sleuth Kit.
+
+
+
+<P>
+Autopsy will try to find the meta-data structure that allocated
+the unit and display both its address and a file name.  This process
+is very slow for FAT file systems, so this process is not done by
+default during analysis.
+
+<H3>FAT Notes</H3>
+<P>
+The Sleuth Kit and Autopsy do not use clusters when dealing with a FAT image.
+Only sectors are used.  The reason is because FAT does not start
+addressing clusters until many sectors into the file system.  If
+clusters were used to address data units, then there would be no
+way to address the sectors in the FAT and secondary FAT.  Therefore,
+sectors are used for all addresses.  NTFS changed the way clusters
+were addressed and do not have this problem.  See the documentation
+in The Sleuth Kit for more details.
+
+
+<P>
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/file_category.html b/help/file_category.html
new file mode 100644
index 0000000000000000000000000000000000000000..6665c90b684738933673cbf7568e3526c3cb8abd
--- /dev/null
+++ b/help/file_category.html
@@ -0,0 +1,99 @@
+<HTML>
+<HEAD><TITLE>Autopsy File Category Help</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+<CENTER><H2>File Category Type Analysis Help</H2></CENTER>
+
+<H3>Overview</H3>
+Analyzing large file system images can be very daunting.  One way 
+of identifying files that should be examined is to sort the files based
+on file type.  This mode of Autopsy will allow one to sort the files
+in an image based on type and to exclude known files (i.e. data 
+reduction).  It also allows one to flag files that are known to be bad.
+
+<H3>Procedure</H3>
+The <TT>sorter</TT> document in the <TT>docs</TT> directory of The
+Sleuth Kit has more details on the details, but this will provide
+an overview of the interface given by Autopsy.
+
+<P>
+The first step is to <U>Sort</U> the image.  There are several
+options to choose when doing this.  The <TT>sorter</TT> tool from
+The Sleuth Kit will perform the sorting.  There are two major
+actions that <TT>sorter</TT> can do:  sort files by type and validate
+extensions.
+
+<P>
+By default, Autopsy will perform both actions.  If you do not want
+it to do a given action, deselect it.   
+
+
+<P>Within sorting, there are two options:
+
+<UL>
+<LI> The first is to save the output.  By default,
+details about each file will be added to a category file.  For
+example, a JPEG image will have the meta data address and image
+name saved to the <TT>images</TT> file.  By selecting the <U>Save</U>
+option, a directory will be created for each category and a copy
+of the files will be saved.  This could require lots of disk space
+(as much as the original image size).
+
+<LI> The second option is to save unknown file types.  There are
+configuration files that contain rules about common data types.  If
+a file is encountered that does not have a rule, it is added to an
+<TT>unknown</TT> file.  If this is not desired, select the <U>Do Not
+Save Unknown</U> option.  
+</UL>
+
+<P>
+During the sorting process, the <TT>sorter</TT> tool will also examine
+the extension of the file.  If the file type is known, it has known
+extensions, and the file does not have one of those extensions, it will
+be added to a <TT>mismatch</TT> file.  This can be deselected if it is
+not wanted.  
+
+
+<H3>Hash Databases</H3>
+One easy way of data reduction is to use hash databases.  The <TT>sorter</TT>
+tool can use three different hash databases.  Each can be configured
+within Autopsy and used in other screens.  
+
+<UL>
+  <LI><B>NIST NSRL</B>: The NIST NSRL contains hashes of trusted operating
+  systems and programs.  This is used to ignore known files.  Files found
+  in the NSRL will not be included in the file categories (to save time
+  when reviewing the files).  If the file is in the NSRL and has an
+  extension mismatch, it will be noted in a special file.  
+
+  <LI><B>Ignore Database</B>: This database must be created by the user
+  and added to the host.  It is similar to the NSRL in that it contains 
+  hashes of known good files.  They will be ignored in the same way that
+  those from NSRL are.  
+
+  <LI><B>Alert Database</B>: This database must also be created by the
+  user and added to the  host.  It contains hashes of files that are
+  known to be bad and should identified if found in the image.  This would
+  include known rootkits or photographs.  Hits from this databases are
+  found in the <TT>alert</TT> file.
+</UL>
+
+<P>
+More details can be found in the <A HREF="hash_db.html">Hash
+Database</A> Help.
+
+<H3>Output</H3>
+Currently, there is no way to view the output from within Autopsy.
+All data can be found in the <TT>output</TT> directory of the host.
+A directory is created for the <TT>sorter</TT> output.  View the
+<TT>index.html</TT> file and it contains links to the other files.
+
+<p>
+<h3>References</h3>
+Issues 3, 4, and 5 of <a href="http://www.sleuthkit.org/informer/"  target=\"_blank\">The
+Sleuth Kit Informer</a> discussed using the 'sorter' tool.
+
+
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/file_mode.html b/help/file_mode.html
new file mode 100644
index 0000000000000000000000000000000000000000..ca39d1d342f0cfca44fd377ec0547e21105a28c3
--- /dev/null
+++ b/help/file_mode.html
@@ -0,0 +1,221 @@
+<HTML>
+<HEAD><TITLE>Autopsy File Analysis Help</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+<CENTER><H2>File Analysis</H2></CENTER>
+<H3>Overview</H3>
+The File Analysis mode allows one to analyze an image from the file
+and directory perspective.  This provides the same interface that users
+typically use with a normal computer.  This mode will also display 
+information about deleted files though.  
+
+<P>
+This mode will allow one to examine the contents of files and directories
+for evidence.  It even allows one to perform basic binary analysis by
+extracting the ASCII strings from a binary file.  The files can also
+be sorted by any field.  
+
+
+<H3>Directory List</H3>
+<P>
+The left-hand side window has four main options:
+<UL>
+  <li>Directory Seek
+  <li>File Name Search
+  <LI>Hide / Expand Directories
+  <LI>Show All Deleted Files
+</UL>
+
+<P>
+By default, the directory listing is not shown when this mode is
+first entered.  By select the <U>Expand Directories</U> button,
+the full list of directories will be shown.  The number of '+'
+symbols represent the depth of the directory.   As this is an HTML
+interface and there is no state management occurring (no cookies
+or session id), it would be difficult to have an interface where
+one or more directories are expanded yet the rest are collapsed.
+
+<P>
+Selecting the <U>All Deleted Files</U> link will display all of the deleted
+files in the image on the right-hand side.
+
+<P>
+There is a text box where a directory (or file) name can be
+entered and it will be displayed on the right-hand side.  This
+makes it easy to jump to a directory without going through the
+directory listings.  For example, to seek to the 'windows\system32'
+folder, you can enter that string into the box instead of scrolling
+through the directories.
+
+<p>
+There is also a text box where a pattern of a file name can be
+entered and all files that match that pattern will be displayed on
+the right-hand side.  The search pattern is a Perl regular expression,
+so some values, such as '.' or '*' will need to be escaped.  The
+search is done case insensitive.  To find all files that have a JPG
+extension, the following could be used "\.jpg".  Or to find all files
+that begin with a dot, then we could use "^\.".  
+
+
+<H3>Directory Contents</H3>
+<P>
+The window in the upper right-hand side contains the directory
+contents.  In a file system, a directory allocates data units on
+the disk and fills the data units with structures that contain the
+name of the file and the address of the meta data structure.  This
+view parses the file name structures in the directory.  It is filled
+by either selecting a directory from the left-hand side directory
+list or a directory from within the same window.  The entries can
+be resorted by clicking on any of the header values.
+
+<P>
+The column headers have the following definitions:
+<UL>
+  <LI><B>del</B>: A check in this column represents a deleted file.
+  See below for a discussion on the different color types of deleted files.
+
+  <LI><B>Type</B>: This column contains the "type" that the file or
+  directory is. There are two values.  The first (<TT>dir</TT>) is the
+  type according to the directory entry structure.  The directory entry
+  is where the file name is located.  The second value (<TT>in</TT>) is
+  the type according to the meta data structure.
+  These should be the same except
+  for deleted files.  They are both given to help the investigator
+  identify if a deleted file has been reallocated or not.  For example,
+  if the meta data structure type is different than the file name
+  type, then it is likely that one of the structures was reallocated for
+  a new file.  
+
+  <LI><B>Name</B>: The name of the file or directory.  Clicking on the
+  name displays file contents in the bottom window or directory contents
+  in the same window.  For deleted files, no link will exist if the meta
+  data structure address 
+  has been cleared (which many OS do).  To identify the destination of 
+  a UNIX symbolic link,
+  click on the address at the end of the row.  Note that the name
+  will not be a link if the size of the file is 0 or if the meta data
+  structure is unknown.  
+
+  <LI><B>Modified Time</B>: This column exists for UNIX and NTFS file 
+  systems.  It shows the last time that the file data was last modified.
+  In other words, when was data last written to the data units allocated
+  by the file.  In UNIX, the <TT>utimes()</TT> function can modify this
+  value vary easily.  
+
+  <LI><B>Written Time</B>: This column exists for FAT file systems and
+  is the time when the file was last written to.  Of the three times,
+  this is the only value that is required by the FAT specification.  
+
+  <LI><B>Accessed Time</B>: This column contains the last accessed time of
+  the file data.  On a FAT image, this value is optional and is only
+  accurate to the day (not hours or seconds).  This value can be 
+  modified by the utimes() function in UNIX.
+
+  <LI><B>Changed Time</B>: This column exists for UNIX and NTFS file
+  systems.  It is the last time that the file status (or meta data) was
+  changed.  This is different than the Modified time because modified
+  deals with the file data and this deals with the descriptive data
+  in the inode or MFT entry.    This value cannot be changed by the
+  <TT>utimes()</TT> function in UNIX.  
+
+  <LI><B>Created Time</B>: This column exists for NTFS and FAT file systems.  It
+  is the time when the file was created.  According to the FAT spec,
+  it is an optional time.  
+
+  <LI><B>Size</B>: The size of the file.  Note that if the size of the
+  file is 0, no link will be shown with the name.  
+
+  <LI><B>UID</B>: The User ID of the file owner.
+
+  <LI><B>GID</B>: The Group ID of the file owner.
+
+  <LI><B>Meta Data</B>: The file name structures contain a pointer to
+  the meta data structure that describes the file.  This column contains
+  the address of the structure.  Selecting this value
+  will display the details in the bottom window.
+  If the value is invalid, then a link will not exist.  If it is for
+  a deleted file name that has a meta data structure with an allocated
+  status, a "realloc" string will 
+  exist to identify this.  
+
+</UL>
+The <U>Add Note</U> link allows you to make a comment about this directory and 
+have it saved in your personal notes file.  
+
+<P>
+The <U>Generate MD5 List</U>
+link will generate the MD5 value for every file in the directory and
+allow you to save it as a text file.  Using fingerprint data bases,
+This makes it easy to check for files that were modified by an attacker.
+
+<P>
+The path on top of the window has hyperlinks in it that allow the
+user to easily change to a previous directory.  
+
+<P>
+There are two different colors used for deleted files.  The difference
+is based on the status of the data structures in the file.  A <FONT
+COLOR="red">bright red</FONT> entry means that the file
+name data structure is not allocated and the meta data structure
+that it points to is also not allocated.  This is what we would
+expect of a recently deleted file.  This means that we can trust
+the data we are seeing as long as the meta data structure was not
+allocated and unallocated since the deletion.  If it is <FONT
+COLOR="#800000">darker red</FONT>, then the meta data
+structure has been reallocated and the data is most likely not
+accurate.
+
+
+<P>
+The file size reported by the meta data structure is very important
+with The Sleuth Kit.  The Sleuth Kit uses this value to identify
+how many data units to display.  If this size is 0, but the meta
+data structure points to data blocks still, they will not be shown.
+You can force Autopsy to display the values by selecting the meta
+data address and using the 'force' option.
+
+<P>
+To look a file up in one of the <A HREF="./hash_db.html">Hash
+Databases</A>, then select the meta data address.  That view will
+provide an interface to the databases.
+
+<H3>File Contents</H3>
+<P>
+The lower right-hand side window displays the contents of a specified
+file.  The contents can be viewed in either the raw format (which your
+browser will not likely display much of if the file is non-ASCII) or
+through 'strings'.  The strings option is helpful for a quick analysis
+of a binary file.
+
+<P>
+Also shown is the file type.  This is determined by running the 'file' 
+command on the output.  It uses the magic header and footer values to
+guess the file type.  If the file type is an image or HTML, an option
+will exist to <U>View</U> the data in its interpreted form (i.e. as
+a picture or as a web page instead of the raw data).  Note that
+any HTML that is viewed will be processed in a sanitized environment 
+that does not load pictures and will not allow one to connect to a 
+remote site.  To view the native picture, select 'Export' and open
+the HTML document in another browser.  Refer to issue #1 of The Sleuth
+Kit Informer for more details on the sanitizing.  
+
+<P>
+The <U>Report</U> options create ASCII reports that contain the file 
+contents as well as data such as MD5 values and dates.  
+
+<P>
+The <U>Export</U> button extracts the file out of the image so you can save it
+locally and use other tools on it. 
+
+<P>
+The <U>Add Note</U> button adds a personal note to the investigator log for
+future reference.
+
+<p>
+<h3>References</h3>
+Issue 1 of <a href="http://www.sleuthkit.org/informer/"  target=\"_blank\">The Sleuth
+Kit Informer</a>.
+
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/fs_mode.html b/help/fs_mode.html
new file mode 100644
index 0000000000000000000000000000000000000000..ef8ec4d76073b827e23432def0ec25004a1ff862
--- /dev/null
+++ b/help/fs_mode.html
@@ -0,0 +1,46 @@
+<HTML>
+<HEAD><TITLE>Autopsy Image Details Help</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+<CENTER><H2>Image Details</H2></CENTER>
+
+<P>
+<H3>Overview</H3>
+Sometimes there are details about an image that do not correspond to
+any file in particular.  Those details can likely be found in this
+mode.  This mode gives the general details of the image and therefore
+the contents will vary depending on the file system type.  
+
+<P>
+<H3>FFS & EXT2FS</H3>
+For the UNIX file systems, this mode will contain the details from
+the super block.  This generally includes times that the file system
+was last mounted and any special flags.  It also has the range of
+inode addresses and fragment addresses.   For advanced file recovery,
+you can also identify the group layout and on-disk structure details.
+These could be useful for restricting where you search for data.
+Files will allocate blocks and fragments in the same Cylinder or
+Block group as their inode is in, so your attention can be restricted
+to that area.
+
+
+<P>
+<H3>FAT</H3>
+For FAT file systems, this mode will contain the File Allocation
+Table.  It will have the cluster runs, which can be selected to
+view their contents in <A HREF="data_mode.html">data unit</A>
+analysis mode.  Or, if the file is fragmented, the pointer can
+be selected and the screen will link to the next cluster chain.  
+
+
+<P>
+<H3>NTFS</H3>
+The unique information for an NTFS image is the numerical type
+associated with attributes.  These values can be dynamic and this
+area will identify what they are for that file system.  
+
+
+<P>
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/general.html b/help/general.html
new file mode 100644
index 0000000000000000000000000000000000000000..5d20c6bbdecbea7906ffbafc2a04ac6889d277c5
--- /dev/null
+++ b/help/general.html
@@ -0,0 +1,103 @@
+<HTML>
+<HEAD><TITLE>General Autopsy Help</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+<CENTER><H2>General Autopsy Help</H2></CENTER>
+<P>
+The Autopsy Forensic Browser is a graphical interface to command
+line forensics tools and standard UNIX utilities.   It allows
+you to perform volume and file system analysis on UNIX and Windows systems.
+
+<P>
+All data are saved in a directory in the Evidence Locker, which
+was specified at install time or at run time.  See 
+<A HREF="caseman.html">Case Management</A> 
+for more information.  In the normal mode, Autopsy imports an
+image file from a disk or partition.  In the live mode, Autopsy
+can analyze a running system and does not save any data to the 
+local disk. 
+
+
+<P>
+The browser has the following modes: 
+<UL>
+
+<LI>
+<B><A HREF="file_mode.html">Files</A></B>:
+Allows you to browse the image file as a file system and view the
+contents of files and directories.   This mode even shows deleted
+file names and Alternate Data Streams in NTFS images.  You can sort
+the files and directories on meta data.
+
+<LI><B><A HREF="meta_mode.html">
+Meta Data</A></B>:
+Allows you to analyze the image file by examining the meta data structures.
+The address of a structure is entered and the details are shown.
+This mode is useful for examining unallocated structures and getting
+all details about allocated files (including all data units and
+other information such as MD5 value).
+
+
+<LI><B><A HREF="data_mode.html">
+Data Unit</A></B>:
+Allows browsing by block number.  This is most useful when used
+with searching or meta data browsing.  The contents of the block
+can be displayed in ASCII, hex dump, or through <I>strings(1)</I>.
+The meta data structure that has allocated the block will be
+displayed (if any) along with the file name (if any).
+
+
+<LI><B><A HREF="srch_mode.html">
+Keyword Search </A></B>:
+Search an image file using <I>grep(1)</I> for a given string or regular
+expression.  The result will be a list of data units that have the
+string.  Each data unit can be selected to view the contents.
+
+
+<LI><B><A HREF="fs_mode.html">
+Image Details</A></B>:
+List the details about the file or volume system.  The output of
+this mode depends on the file system.  Examples of the file system
+data include the last mount time, the last mount location, and a
+detailed break down of block group information or File Allocation
+Table contents.
+
+<LI><B><A HREF="int_mode.html">
+Image Integrity</A></B>:
+The integrity of the data can be validated at any
+point by selecting this mode.  It uses the values in <TT>md5.txt</TT> to
+identify if any data have been modified in the analysis process.
+
+<LI><B><A HREF="tl.html">
+File Activity Timelines</A></B>:
+Autopsy can create timelines of file activity based on the Modified,
+Access, and Change (Create in FAT/NTFS) times (MAC).  The timeline
+will contain details about deleted and allocated content.  The
+resulting timeline can be either viewed within Autopsy or using
+other text viewing tools (WARNING: many HTML browsers do not handle
+large tables like a timeline very well so using a text editor is 
+recommended).
+
+<LI><B><A HREF="file_category.html">
+File Type Categories</A></B>:
+Autopsy can sort the files in an image file based on their file type.
+For example, all JPEG and GIF files would be identified as images
+and all executable files would be identified.  This mode will also
+ignore files that are found in hash databases of known good files,
+identify files that are found in a hash database of known bad files,
+and identify files that have an extension that is not consistent
+with their file type.
+
+
+<LI><B>Report Generation</B>:  
+Each of the above browsing techniques allows a report to be generated.
+This report lists the date, md5 value, investigator, and other
+context information in a text format.  This can be used for record
+keeping when deleted blocks of data have been found.
+
+</UL>
+
+
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/grep.html b/help/grep.html
new file mode 100644
index 0000000000000000000000000000000000000000..1db60600755c994e752f3d742feff4ab1d716b08
--- /dev/null
+++ b/help/grep.html
@@ -0,0 +1,70 @@
+<HTML>
+<HEAD><TITLE>Autopsy grep Cheat Sheet</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+<CENTER><H2>grep Cheat Sheet</H2></CENTER>
+
+<H3>Escaped Values</H3>
+Autopsy uses the <TT>grep</TT> utility to search an image.  grep requires
+that some values be "escaped" if they are searched for.  Autopsy
+will automatically escape those values if the serach is being done for
+a <U>non-regular expression</U>.  The escaped values include:
+<UL>
+  <LI>\
+  <LI>.
+  <LI>[
+  <LI>^
+  <LI>$
+  <LI>'
+  <LI>*
+  <LI>initial -
+</UL>
+
+
+<H3>Regular Expressions</H3>
+Refer to the man page for 'grep' for more details of creating regular
+expressions.  Autopsy uses the '-E' flag with 'grep' to specify 
+extended regular expressions.  The following have special meaning
+with grep:
+
+<UL>
+  <LI><B>[A-Za-z]</B>: Any lower and upper case letter
+  <LI><B>[:alpha:]</B>: same as above
+  <LI><B>[0-9]</B>: Any number
+  <LI><B>[:digit:]</B>: same as above
+  <LI><B>[0-9A-Za-z]</B>: Any lower and upper case letter or digit
+  <LI><B>[:alnum:]</B>: same as above
+  <LI><B>[:space:]</B>: Any white space
+</UL>
+
+
+<P>
+To specify how many times something can occur, the following are used:
+<UL>
+  <LI><B>?</B>: Optional and can only occur once
+  <LI><B>*</B>: Optional and can occur more than once
+  <LI><B>+</B>: Required and can occur more than once
+</UL>
+
+<P>
+To specify more than one string to match, use the <B>|</B> operator.
+
+<H3>Examples</H3>
+
+<P>
+To search for 'Jane Smith' or 'Jack Smith': (Jane)|(Jack) Smith
+
+<P>
+To ensure it matches if a tab is between the first and last name:
+(Jane)|(Jack)[:space:]Smith
+
+<P>
+To search for 'Jane Smith' or 'Jane Anne Smith':
+Jane( Anne)? Smith
+
+<P>
+or: Jane([:space:]Anne)?[:space:]Smith
+
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/grep_lim.html b/help/grep_lim.html
new file mode 100644
index 0000000000000000000000000000000000000000..d8a29d27e5b272afed6ceffaadbc7fb5d40a1c02
--- /dev/null
+++ b/help/grep_lim.html
@@ -0,0 +1,75 @@
+<HTML>
+<HEAD><TITLE>Autopsy grep Search Limitations</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+<CENTER><H2><TT>grep</TT> Search Limitations</H2></CENTER>
+
+<H3>Overview</H3>
+<P>
+Keyword searches are very basic in Autopsy.  Autopsy uses the
+<TT>strings</TT> and <TT>grep</TT> tools on the image and when a
+hit is found, it uses <TT>ifind</TT> and <TT>ffind</TT> to identify
+the file that has allocated the string.  This is a very simple and
+basic method of searching and is not ideal.  This will cause false
+positives and will miss data that crosses a fragmented part of a file.
+The limitations are outlined in this file.
+
+<H3>What Will Be Found</H3>
+<TT>strings</TT> is first run on the image and the data is passed
+to <TT>grep</TT> to do the actual search.  This process will find
+ASCII and UNICODE strings that are consecutive anywhere in the file.   This is
+frequently referred to as the physical layout.  For example, it
+will find strings in the middle of an allocated sector, in an
+unallocated sector, in slack space, and in meta data strutures.
+This will find a string that crosses sectors, which is good if the
+two sectors are for the same file.
+
+<P>
+This technique leads to several types of false positives.  For example,
+a string that crosses from the allocated space of a file into the slack
+space would be found by <TT>grep</TT>.  A string that starts in the slack space
+and ends in the allocated space of a file will also be found.  A string 
+that crosses sectors of two different allocated files will also be found.  The
+user must identify if the hit is an actual hit or a false positive.  
+
+<h3>What Will Be Found, but May Be Confusing</h3>
+<p>
+If you are searching with regular expressions, then the exact
+location and number of hits may not be correctly reported.  If the
+count is incorrect, then it will be too small.  If the location
+is incorrect, then it will be too early (and could even be in the
+next data unit).  The reason that this is in accurate is because
+the <tt>grep</tt> tool will return a long string to Autopsy that
+will contain one or more occurances of the keyword.  Autopsy can
+not search the long string to find the exact number and location
+of the regular expression keywords like it can for non-regular
+expression keywords, so it returns only the starting location of
+the long string.
+
+<H3>What Will NOT Be Found</H3>
+The biggest category of 'hits' that will not occur using this technique
+is strings in a file that cross fragmented data units.  For example, consider
+a file that has two clusters allocated, cluster 100 and cluster 150.  A 
+string "mississippi" could have "missi" in the final 5 bytes of cluster 100
+and "ssippi" in the initial 6 bytes of cluster 150.  The string exists from
+the logial level, but not at the physical level.  Therefore, the <TT>grep</TT>
+search would not find the string.  
+
+<P>
+Although not because of <TT>grep</TT>, Autopsy will also not find
+data in the slack space during an unallocated-only search.  The
+extraction tool for The Sleuth Kit (<TT>blkls</TT>) differentiates
+between unallocated sectors in FAT and NTFS and slack space.  There
+is currently no way in Autopsy to extract the slack space and search
+it.  Autopsy currently only extracts the unallocated sectors and not
+the allocated sectors that may have deleted data in them.
+
+
+<H3>Conclusion</H3>
+Autopsy has basic keyword search functionality.  Future versions may provide
+more features and better search results.  In the mean time, it is important
+that users understand the abilities and limitations of the tool so that they
+can be taken into account during the investigation.  
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/hash_db.html b/help/hash_db.html
new file mode 100644
index 0000000000000000000000000000000000000000..cddb793866172c100d016ab4af401dfa0ec063fa
--- /dev/null
+++ b/help/hash_db.html
@@ -0,0 +1,141 @@
+<HTML>
+<HEAD><TITLE>Autopsy Hash Database Help</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+<CENTER><H2>Hash Database Help</H2></CENTER>          
+
+<H3>Overview</H3>
+Hash databases are used to quickly identify known good and known
+bad files using the MD5 or SHA-1 checksum value.  Autopsy uses
+three types of hash databases to help the investigator reduce the
+number of files that they have to look at.
+
+<P>
+The <B>NIST National Software Reference Library (NSRL)</B> contains
+hashes of files that are found in operating systems and software
+distributions.  These files are <I>known to be good</I> in that they came
+from trusted sources and are typically on authorized systems.  When
+processing files in the image, this database can be used to ignore
+files because they are assumed to be known and therefore uninteresting.
+The location of this database is configured when Autopsy is installed.
+The NSRL must be obtained from NIST at <TT>www.nsrl.nist.gov</TT>.
+
+<P>
+The <B>Ignore Database</B> is a database that the investigator must
+create.  It is similar to the NIST NSRL in that it contains files
+that are <I>known to be good</I> and can be ignored if the user
+chooses to do so (only applicable when in <A HREF="file_category.html">File
+Type Category Analysis</A>).  Examples of files in this category include
+system binaries for standard builds.  See <A HREF="#db_create">Database
+Creation</A> for information on creating this database.  Its location
+is configured when the host is created and can be edited in the
+host configuration file.
+
+<P>
+The <B>Alert Database</B> is a database that the investigator must
+create.  It contains hashes of <I>known bad</I> files.  These are
+the files that an investigator wants to know about if they exist
+on the system.  Examples of this include rootkits or unauthorized
+photographs.
+When using the <A HREF="file_category.html">File Type Category
+Analysis</A>, these files will be saved in a special file.  See <A
+HREF="#db_create">Database Creation</A> for information on creating
+this database.  Its location is configured when the host is created
+and can be edited in the host configuration file.
+
+
+<H3>Database Uses</H3>
+Autopsy uses the hash databases in three ways.  
+
+<UL>
+  <LI><B><A HREF="file_category.html">File Type Category Analysis</A></B>: The
+  hash databases are used to identify the <I>known bad</I> files and
+  ignore the <I>known good</I> files.  
+
+  <LI><B><A HREF="meta_mode.html">Meta Data Analysis</A></B>: The hash
+  databases can be used to identify a file from the meta data view.  If
+  the databases are configured, the hash from a given file can be looked
+  up by pressing the 'lookup' button.    
+  All three databases can be used in this view.  This view can be found
+  from the File Analysis mode by selecting the meta data address in
+  the directory listing window.
+
+  <LI><B>Hash Database Manager</B>: From the Host Gallery view, 
+  the Hash Database Manager can be entered.  This is where one can
+  re-index the databases and perform single lookups in any of the
+  databases.  
+</UL>
+
+
+<A NAME="db_create">
+<H3>Database Creation</H3>
+Currently, Autopsy will only allows one to look entries up in a 
+hash database.  It does not allow one to easily create a database,
+but this will describe the process (it is quite simple).  
+
+<P>
+Autopsy uses the <TT>hfind</TT> tool from The Sleuth Kit to do the
+lookups.  This tool requires the database to be indexed so that it
+can perform a fast lookup using a binary search algorithm (instead
+of a slower sequential search that a tool like grep would do).
+When ever a hash database is updated (or created), it must be
+indexed.  This can be done in Autopsy in the Hash Database Manager
+(Note that the database must already be configured though).
+
+<P>
+The NIST NSRL obviously does not have to be created, but it does have
+to be indexed before it is used.
+
+<P>
+To make a hash database, we will create a file with the same format
+as the <TT>md5sum</TT> command uses.  This is just the MD5 hash,
+some white space, and the file name.  For example:<BR>
+
+&nbsp;&nbsp;&nbsp;&nbsp;<TT>c4a6761b486de3c6abf7cf2c554289e5
+&nbsp;&nbsp;&nbsp;&nbsp;/bin/ps</TT><P>
+
+Make a file with this format for every line (it does not have to
+be sorted).  For example, if you have a trusted system then you can make
+a hash database of its system binaries using the following:<BR>
+
+&nbsp;&nbsp;&nbsp;&nbsp;<TT># md5sum /bin/* /sbin/* > bin-md5.db</TT><P>
+
+After creation, hash databases must be indexed and sorted (this
+includes the NSRL).  Databases will be indexed by using the
+<TT>hfind</TT> tool.  The NSRL database would be indexed with:<BR>
+
+&nbsp;&nbsp;&nbsp;&nbsp;<TT># hfind -i nsrl-md5  PATH_TO_NSRL/NSRLFile.txt</TT><P>
+
+A database made by <TT>md5sum</TT> would be indexed with:<BR>
+
+&nbsp;&nbsp;&nbsp;&nbsp;<TT># hfind -i md5sum  bin-md5.db</TT><P>
+
+Or, if Autopsy has this file configured from when the host was added,
+then it can be re-indexed from the Hash Database Manager.
+
+<H3>Autopsy Configuration</H3>
+The alert and ignore databases are stored in the host configuration file
+with the headers of 'exclude_db' and 'alert_db'.  For example:<BR>
+
+&nbsp;&nbsp;&nbsp;&nbsp;<TT>alert_db&nbsp;&nbsp;&nbsp;&nbsp;'/usr/local/hash/bad.db'</TT><P>
+These entries can be edited at any time.  
+
+<P>
+The NSRL database is configured in the <TT>conf.pl</TT> file in the
+directory where Autopsy was installed.  It has the $NSRLDB variable.  
+For example:<BR>
+
+&nbsp;&nbsp;&nbsp;&nbsp;<TT>$NSRLDB = '/usr/local/hash/nsrl/NSRLFile.txt';</TT><P>
+
+It can be edited, added, and removed at any time (but you must restart
+Autopsy).  
+
+
+<p>
+<h3>References</h3>
+Issues 6 and 7 of <a href="http://www.sleuthkit.org/informer/"  target=\"_blank\">The
+Sleuth Kit Informer</a> discussed hash databases.
+
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/index.html b/help/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..c7c46aec4f12d9142090b5a6ab225f51e5596474
--- /dev/null
+++ b/help/index.html
@@ -0,0 +1,11 @@
+<HTML>
+<HEAD><TITLE>Autopsy Help</TITLE></HEAD>
+<LINK REL="SHORTCUT ICON" HREF="../pict/favicon.ico">
+<FRAMESET COLS="20%,*">
+
+	<FRAME SRC="menu.html">
+	<FRAME SRC="blank.html" NAME="cont">
+
+</FRAMESET>
+
+</HTML>
diff --git a/help/int_mode.html b/help/int_mode.html
new file mode 100644
index 0000000000000000000000000000000000000000..5152b95ad0c2f06368e21ca11b9f2c3b9d05022d
--- /dev/null
+++ b/help/int_mode.html
@@ -0,0 +1,29 @@
+<HTML>
+<HEAD><TITLE>Autopsy Integrity Check Help</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+<CENTER><H2>Integrity Check</H2></CENTER>
+
+<H3>Overview</H3>
+It is always important to validate the integrity of images during
+an analysis.  Autopsy uses the MD5 algorithm to validate images
+and other files that are created by Autopsy.  
+
+<P>
+The <TT>md5.txt</TT> files contain the MD5 values for files in that
+directory.  Values are added to it when file system images are 
+imported into the system or when Autopsy creates the file.  This mode
+allows one to calculate the MD5 value if it was not created before 
+and to validate the integrity.
+
+<P>
+When the <U>Image Integrity</U> button is selected from the <U>Host
+Manager</U> window, all files will be shown with their MD5 value
+if known.  Here any image can have its value verified or a new one
+created.
+
+
+<P>
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/menu.html b/help/menu.html
new file mode 100644
index 0000000000000000000000000000000000000000..8b74a8659454df8443946991561ccef5a26252d2
--- /dev/null
+++ b/help/menu.html
@@ -0,0 +1,37 @@
+<HTML>
+<HEAD><TITLE>Autopsy Help Topics</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+<P><A HREF="general.html" TARGET="cont">General Information</A>
+
+<P><A HREF="caseman.html" TARGET="cont">Case Management</A>
+
+<HR>
+
+<P><A HREF="file_mode.html" TARGET="cont">File Analysis</A>
+
+<P><A HREF="meta_mode.html" TARGET="cont">Meta Data Analysis</A>
+
+<P><A HREF="data_mode.html" TARGET="cont">Data Unit Analysis</A>
+
+<P><A HREF="fs_mode.html" TARGET="cont">Image Details</A>
+
+<P><A HREF="srch_mode.html" TARGET="cont">Keyword Searching</A>
+
+<P><A HREF="grep.html" TARGET="cont">grep Cheat Sheet</A>
+
+<P><A HREF="grep_lim.html" TARGET="cont">grep Search Limitations</A>
+
+<P><A HREF="tl.html" TARGET="cont">Timelines</A>
+
+<P><A HREF="sequencer.html" TARGET="cont">Event Sequencer</A>
+
+<P><A HREF="file_category.html" TARGET="cont">File Type Categories</A>
+
+<P><A HREF="hash_db.html" TARGET="cont">Hash Databases</A>
+
+<P><A HREF="int_mode.html" TARGET="cont">Image Integrity</A>
+
+<P><A HREF="timezones.html" TARGET="cont">Time Zones</A>
+
+</BODY></HTML>
diff --git a/help/meta_mode.html b/help/meta_mode.html
new file mode 100644
index 0000000000000000000000000000000000000000..3a7475f713bc42ba7e39b7eef519b06de039a277
--- /dev/null
+++ b/help/meta_mode.html
@@ -0,0 +1,93 @@
+<HTML>
+<HEAD><TITLE>Autopsy Metadata Analysis Help</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+<CENTER><H2>Metadata Analysis</H2></CENTER>
+<H3>Overview</H3>
+The Metadata Analysis mode allows the investigator to view the
+details of metadata structures.  The metadata structures on the
+on-disk structures that contain the details of a file, such as
+times and pointers to the allocated data units.  FFS and EXT2FS
+file systems call them inode structures, NTFS file systems call
+them Master File Table (MFT) entries (or File Entries), and the
+FAT file system calls them directory entries.  This mode is useful
+for recovering data and getting a detailed look at a file. 
+
+<H3>Input</H3>
+To view the contents of a structure, enter the address in the text
+box on the left and select <U>Display</U>.
+
+<P>
+The <U>Allocation List</U> button can also be used to view the
+allocation status of metadata structures in groups of 500.
+
+<H3>Viewing</H3>
+The structure details are displayed on the right-hand side.
+Typically, the metadata structure does not have the name of the
+file that uses that structure, so Autopsy will try to locate the
+file name.  This process is slow with a FAT file system, so it is
+not done by default.
+
+<P>
+The <U>File Type</U> is given, which is the output of the 'file'
+tool.  This tool uses any header information in the file to
+guess what its type is.  The MD5 value of the file is also given.
+
+<P>
+If Autopsy has been configured to use hash databases, then one can
+select which databases to look for the file in.  See 
+<A HREF="hash_db.html">Hash Databases</A> for more details.  
+
+<P>
+The rest of the information will vary depending on the file
+system type.  In general, the allocation status will be given as
+well as the size and each data unit that it has allocated.  A
+link will exist for each data unit that will show its contents.  
+
+<P>
+The <U>Report</U> option generates an ASCII report with the structure
+details, MD5 values, and dates in it.  The <U>View Contents</U> option
+displays the allocated data contents as one large file.  The <U>Export</U>
+option allows one to save the data contents to a file.  The
+<U>Add Note</U> button allows one to add a comment about this structure so
+that it can be later recalled. 
+
+<H3>NTFS Notes</H3>
+<P>
+NTFS is a much different design than UNIX file systems and the meta
+data structures are addressed differently.  They typically have
+the form of <TT>A-B-C</TT>, <TT>88-128-3</TT> for example.  The
+<TT>A</TT> value is the address of the file in the Master File
+Table, 88 for example. This is similar to the inode value in UNIX.
+Each file has several attributes, including at least one in files
+for the data.  The <TT>B</TT> value is the type of attribute.  In
+most cases, the data attribute has a type of 128 so this is commonly
+seen.  But, if you want to see the file name attribute, you could
+specify that type and see the contents if you like (it is fairly
+boring).  The final value, <TT>C</TT>, is the id.  Every attribute
+has a unique id value.  So, if there are multiple attributes with
+the same type, you can specify the type.
+
+<H3>FAT Notes</H3>
+<P>
+FAT does not give addresses to the directory entry structures.  in
+FAT, directory entries can be stored anywhere on the disk.  They
+are stored in the clusters allocated to the parent directory.  This
+is unlike NTFS or UNIX where the structures are in a large table
+that does not move.  get around that,
+
+
+<P>
+The addressing issue was solved by providing an address to every
+32-byte area in the Data Area.  Whether that data was currently a
+directory entry or not.  This makes it easy to find a given address
+and scale when new files are created.  The downside is that not
+every address is possible, so it is likely that you will see jumps
+in the address values.  See the documentation in The Sleuth Kit
+for more details.
+
+
+<P>
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/sequencer.html b/help/sequencer.html
new file mode 100644
index 0000000000000000000000000000000000000000..6afb01e3e74277b06deddbe3897d2ad74face4ce
--- /dev/null
+++ b/help/sequencer.html
@@ -0,0 +1,49 @@
+<HTML>
+<HEAD><TITLE>Autopsy Event Sequencer Help</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+<CENTER><H2>Event Sequencer</H2></CENTER>
+
+<H3>Overview</H3>
+<P>
+In many investigations, evidence is not found in the order that it was
+created during the incident.  The notes feature in Autopsy allows one to
+make notes about certain files, but it does not help one to put a 
+series of events in order.  
+
+<P>
+The Event Sequencer allows the investigator to make notes and comments
+about pieces of evidence.   Each note must have a time associated with
+it.  For files and meta data, the times can be one or more of the
+MAC times.  Other notes can have times entered manually.  The sequencer
+will sort the events after each is entered so that the investigator can
+quickly identify where there are gaps in the findings. 
+
+<H3>Adding an Event</H3>
+<P>
+To add an event for a file, directory, or meta data structure, select
+the <U>Add Note</U> button.  At the bottom will be check boxes that allow
+an event to be generated for each of the file's times.  The "standard"
+note does not have to be generated if it is not needed.  
+
+<P>
+To add an event from a different source, go to the Event Sequencer from
+the Host Gallery (where the images are listed).  At the bottom of
+the window will be an area where the new event can be added.  The
+<B>Source</B> of the event will be shown where the file name of
+a file event is normally shown.  Examples of this type include 
+entries from firewall logs or reports from the help desk. 
+
+<H3>Viewing the Sequence Events</H3>
+<P>
+The <U>Event Sequencer</U> button can be found in the Host Gallery.  
+This window shows the events that are sorted by the time.  Events that
+correspond to a file, directory, or meta data structure will have either
+[M-Time], [A-Time], or [C-Time] in the note that shows what time this 
+event was generated from.  Clicking on the name will show the contents of 
+the file or directory.  
+
+
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/srch_mode.html b/help/srch_mode.html
new file mode 100644
index 0000000000000000000000000000000000000000..43b65791be28ca0292483d84e3e612783f17a15c
--- /dev/null
+++ b/help/srch_mode.html
@@ -0,0 +1,68 @@
+<HTML>
+<HEAD><TITLE>Autopsy Keyword Search Help</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+
+<CENTER><H2>Keyword Search</H2></CENTER>
+<H3>Overview</H3>
+<P>
+This mode searches an image for a given string.  This is most useful
+when searching for deleted content.  To decrease the time required
+for a search, a "strings" file can serve as an index.  This file
+will contain only the ASCII strings in the image.  
+
+<P>
+Autopsy will also prompt you to create a file of unallocated data if one
+does not exist.  This obviously is useful for recovering deleted data. 
+If a string is found in this file, Autopsy will also report the location
+in the original image.  
+
+<H3>Entering the String</H3>
+
+Enter the string or regular expression into the text box.  Autopsy
+allows you to search for a either a specific string or using 'grep'
+style regular expressions.  A case insensitive search will occur
+if the appropriate box is checked, otherwise it is case sensitive.
+You will also have the option of searching for the string as an
+ASCII or a Unicode string.  Unicode is much more common in Windows
+systems than Unix systems.  If both types are selected, then two
+searches will be done.
+
+<P>
+If you have not generated a strings file or unallocated data file yet,
+that option will exist.
+
+<P>
+The <U>Load Unallocated Image</U> or <U>Load Allocated Image</U> button
+exists to switch between the two file types if they have both been
+generated.  
+
+<P>
+Autopsy also has the ability to perform pre-configured searches.  They
+are shown in the "Predefined Searches" section.  
+
+<H3>Viewing the Results</H3>
+After the image has been searched, a list of "hits" will appear on the
+left-hand side.  Each data unit that contains the string is listed with
+the offset of each occurrence.  If a regular expression is used, then the
+exact location is not given.  
+
+<P>
+If the search was done on an unallocated data file, then an option will
+exist next to each address to also view the original.  Doing so could
+reveal the inode that allocated it.
+
+<H3>Previous Searches</H3>
+The search results are saved to a file so it is easy to recall the
+results with out having to perform the search again.  
+
+<H3>Regular Expressions</H3>
+You can use grep regular expressions in the search
+(refer to the 'grep' <A HREF="grep.html">
+help page</A> and man page for more details).   To search for
+a couple of different words you would use: <TT>(foo) | (bar)</TT>.
+
+
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/temp.html b/help/temp.html
new file mode 100644
index 0000000000000000000000000000000000000000..c3a4b95ee9d59917f09893d38bb8e66335bc88fe
--- /dev/null
+++ b/help/temp.html
@@ -0,0 +1,10 @@
+<HTML>
+<HEAD><TITLE>Autopsy File Analysis Help</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+
+
+
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/timezones.html b/help/timezones.html
new file mode 100644
index 0000000000000000000000000000000000000000..6fa95b7c2151798e543c22b1bf30b57d288f0ed9
--- /dev/null
+++ b/help/timezones.html
@@ -0,0 +1,508 @@
+<HTML>
+<HEAD><TITLE>Autopsy File Analysis Help - Time zone</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+<p>
+
+When creating a host, you can specify a time zone.  If you do not, it will default to the time zone to which your system is set.  If the system being investigated came from a different time zone, then you need to figure out what it was called.  Below are a list of time zones that are known by most computers. 
+
+<p><br>
+This list was copied from this site:  
+<tt>http://showtunepink.com/ical/TIMEZONES</tt>
+
+<pre>
+
+Africa/Addis_Ababa
+Africa/Algiers
+Africa/Asmera
+Africa/Bangui
+Africa/Blantyre
+Africa/Brazzaville
+Africa/Bujumbura
+Africa/Cairo
+Africa/Ceuta
+Africa/Dar_es_Salaam
+Africa/Djibouti
+Africa/Douala
+Africa/Gaborone
+Africa/Harare
+Africa/Johannesburg
+Africa/Kampala
+Africa/Khartoum
+Africa/Kigali
+Africa/Kinshasa
+Africa/Lagos
+Africa/Libreville
+Africa/Luanda
+Africa/Lubumbashi
+Africa/Lusaka
+Africa/Malabo
+Africa/Maputo
+Africa/Maseru
+Africa/Mbabane
+Africa/Mogadishu
+Africa/Nairobi
+Africa/Ndjamena
+Africa/Niamey
+Africa/Porto-Novo
+Africa/Tripoli
+Africa/Tunis
+Africa/Windhoek
+America/Adak
+America/Anchorage
+America/Anguilla
+America/Antigua
+America/Araguaina
+America/Aruba
+America/Asuncion
+America/Atka
+America/Barbados
+America/Belem
+America/Belize
+America/Boa_Vista
+America/Bogota
+America/Boise
+America/Buenos_Aires
+America/Cambridge_Bay
+America/Cancun
+America/Caracas
+America/Catamarca
+America/Cayenne
+America/Cayman
+America/Chicago
+America/Chihuahua
+America/Cordoba
+America/Costa_Rica
+America/Cuiaba
+America/Curacao
+America/Dawson
+America/Dawson_Creek
+America/Denver
+America/Detroit
+America/Dominica
+America/Edmonton
+America/Eirunepe
+America/El_Salvador
+America/Ensenada
+America/Fort_Wayne
+America/Fortaleza
+America/Glace_Bay
+America/Godthab
+America/Goose_Bay
+America/Grand_Turk
+America/Grenada
+America/Guadeloupe
+America/Guatemala
+America/Guayaquil
+America/Guyana
+America/Halifax
+America/Havana
+America/Hermosillo
+America/Indiana/Indianapolis
+America/Indiana/Knox
+America/Indiana/Marengo
+America/Indiana/Vevay
+America/Indianapolis
+America/Inuvik
+America/Iqaluit
+America/Jamaica
+America/Jujuy
+America/Juneau
+America/Kentucky/Louisville
+America/Kentucky/Monticello
+America/Knox_IN
+America/La_Paz
+America/Lima
+America/Los_Angeles
+America/Louisville
+America/Maceio
+America/Managua
+America/Manaus
+America/Martinique
+America/Mazatlan
+America/Mendoza
+America/Menominee
+America/Merida
+America/Mexico_City
+America/Miquelon
+America/Monterrey
+America/Montevideo
+America/Montreal
+America/Montserrat
+America/Nassau
+America/New_York
+America/Nipigon
+America/Nome
+America/Noronha
+America/Panama
+America/Pangnirtung
+America/Paramaribo
+America/Phoenix
+America/Port-au-Prince
+America/Port_of_Spain
+America/Porto_Acre
+America/Porto_Velho
+America/Puerto_Rico
+America/Rainy_River
+America/Rankin_Inlet
+America/Recife
+America/Regina
+America/Rio_Branco
+America/Rosario
+America/Santiago
+America/Santo_Domingo
+America/Sao_Paulo
+America/Scoresbysund
+America/Shiprock
+America/St_Johns
+America/St_Kitts
+America/St_Lucia
+America/St_Thomas
+America/St_Vincent
+America/Swift_Current
+America/Tegucigalpa
+America/Thule
+America/Thunder_Bay
+America/Tijuana
+America/Tortola
+America/Vancouver
+America/Virgin
+America/Whitehorse
+America/Winnipeg
+America/Yakutat
+America/Yellowknife
+Antarctica/Casey
+Antarctica/Davis
+Antarctica/DumontDUrville
+Antarctica/Mawson
+Antarctica/McMurdo
+Antarctica/Palmer
+Antarctica/South_Pole
+Antarctica/Syowa
+Antarctica/Vostok
+Arctic/Longyearbyen
+Asia/Aden
+Asia/Almaty
+Asia/Amman
+Asia/Anadyr
+Asia/Aqtau
+Asia/Aqtobe
+Asia/Ashgabat
+Asia/Ashkhabad
+Asia/Baghdad
+Asia/Bahrain
+Asia/Baku
+Asia/Bangkok
+Asia/Beirut
+Asia/Bishkek
+Asia/Brunei
+Asia/Calcutta
+Asia/Chungking
+Asia/Colombo
+Asia/Dacca
+Asia/Damascus
+Asia/Dhaka
+Asia/Dili
+Asia/Dubai
+Asia/Dushanbe
+Asia/Gaza
+Asia/Harbin
+Asia/Hong_Kong
+Asia/Hovd
+Asia/Irkutsk
+Asia/Istanbul
+Asia/Jakarta
+Asia/Jayapura
+Asia/Jerusalem
+Asia/Kabul
+Asia/Kamchatka
+Asia/Karachi
+Asia/Kashgar
+Asia/Katmandu
+Asia/Krasnoyarsk
+Asia/Kuala_Lumpur
+Asia/Kuching
+Asia/Kuwait
+Asia/Macao
+Asia/Magadan
+Asia/Manila
+Asia/Muscat
+Asia/Nicosia
+Asia/Novosibirsk
+Asia/Omsk
+Asia/Phnom_Penh
+Asia/Pyongyang
+Asia/Qatar
+Asia/Rangoon
+Asia/Riyadh
+Asia/Riyadh87
+Asia/Riyadh88
+Asia/Riyadh89
+Asia/Saigon
+Asia/Samarkand
+Asia/Seoul
+Asia/Shanghai
+Asia/Singapore
+Asia/Taipei
+Asia/Tashkent
+Asia/Tbilisi
+Asia/Tehran
+Asia/Tel_Aviv
+Asia/Thimbu
+Asia/Thimphu
+Asia/Tokyo
+Asia/Ujung_Pandang
+Asia/Ulaanbaatar
+Asia/Ulan_Bator
+Asia/Urumqi
+Asia/Vientiane
+Asia/Vladivostok
+Asia/Yakutsk
+Asia/Yekaterinburg
+Asia/Yerevan
+Atlantic/Azores
+Atlantic/Bermuda
+Atlantic/Canary
+Atlantic/Cape_Verde
+Atlantic/Faeroe
+Atlantic/Jan_Mayen
+Atlantic/Madeira
+Atlantic/South_Georgia
+Atlantic/Stanley
+Australia/ACT
+Australia/Adelaide
+Australia/Brisbane
+Australia/Broken_Hill
+Australia/Canberra
+Australia/Darwin
+Australia/Hobart
+Australia/LHI
+Australia/Lindeman
+Australia/Lord_Howe
+Australia/Melbourne
+Australia/NSW
+Australia/North
+Australia/Perth
+Australia/Queensland
+Australia/South
+Australia/Sydney
+Australia/Tasmania
+Australia/Victoria
+Australia/West
+Australia/Yancowinna
+Brazil/Acre
+Brazil/DeNoronha
+Brazil/East
+Brazil/West
+CET
+CST6CDT
+Canada/Atlantic
+Canada/Central
+Canada/East-Saskatchewan
+Canada/Eastern
+Canada/Mountain
+Canada/Newfoundland
+Canada/Pacific
+Canada/Saskatchewan
+Canada/Yukon
+Chile/Continental
+Chile/EasterIsland
+Cuba
+EET
+EST
+EST5EDT
+Egypt
+Eire
+Etc/GMT+1
+Etc/GMT+10
+Etc/GMT+11
+Etc/GMT+12
+Etc/GMT+2
+Etc/GMT+3
+Etc/GMT+4
+Etc/GMT+5
+Etc/GMT+6
+Etc/GMT+7
+Etc/GMT+8
+Etc/GMT+9
+Etc/GMT-1
+Etc/GMT-10
+Etc/GMT-11
+Etc/GMT-12
+Etc/GMT-13
+Etc/GMT-14
+Etc/GMT-2
+Etc/GMT-3
+Etc/GMT-4
+Etc/GMT-5
+Etc/GMT-6
+Etc/GMT-7
+Etc/GMT-8
+Etc/GMT-9
+Europe/Amsterdam
+Europe/Andorra
+Europe/Athens
+Europe/Belfast
+Europe/Belgrade
+Europe/Berlin
+Europe/Bratislava
+Europe/Brussels
+Europe/Bucharest
+Europe/Budapest
+Europe/Chisinau
+Europe/Copenhagen
+Europe/Dublin
+Europe/Gibraltar
+Europe/Helsinki
+Europe/Istanbul
+Europe/Kaliningrad
+Europe/Kiev
+Europe/Lisbon
+Europe/Ljubljana
+Europe/London
+Europe/Luxembourg
+Europe/Madrid
+Europe/Malta
+Europe/Minsk
+Europe/Monaco
+Europe/Moscow
+Europe/Nicosia
+Europe/Oslo
+Europe/Paris
+Europe/Prague
+Europe/Riga
+Europe/Rome
+Europe/Samara
+Europe/San_Marino
+Europe/Sarajevo
+Europe/Simferopol
+Europe/Skopje
+Europe/Sofia
+Europe/Stockholm
+Europe/Tallinn
+Europe/Tirane
+Europe/Tiraspol
+Europe/Uzhgorod
+Europe/Vaduz
+Europe/Vatican
+Europe/Vienna
+Europe/Vilnius
+Europe/Warsaw
+Europe/Zagreb
+Europe/Zaporozhye
+Europe/Zurich
+GB
+GB-Eire
+GMT
+HST
+Hongkong
+Indian/Antananarivo
+Indian/Chagos
+Indian/Christmas
+Indian/Cocos
+Indian/Comoro
+Indian/Kerguelen
+Indian/Mahe
+Indian/Maldives
+Indian/Mauritius
+Indian/Mayotte
+Indian/Reunion
+Iran
+Israel
+Jamaica
+Japan
+Kwajalein
+Libya
+MET
+MST
+MST7MDT
+Mexico/BajaNorte
+Mexico/BajaSur
+Mexico/General
+Mideast/Riyadh87
+Mideast/Riyadh88
+Mideast/Riyadh89
+NZ
+NZ-CHAT
+Navajo
+PRC
+PST8PDT
+Pacific/Apia
+Pacific/Auckland
+Pacific/Chatham
+Pacific/Easter
+Pacific/Efate
+Pacific/Enderbury
+Pacific/Fakaofo
+Pacific/Fiji
+Pacific/Funafuti
+Pacific/Galapagos
+Pacific/Gambier
+Pacific/Guadalcanal
+Pacific/Guam
+Pacific/Honolulu
+Pacific/Johnston
+Pacific/Kiritimati
+Pacific/Kosrae
+Pacific/Kwajalein
+Pacific/Majuro
+Pacific/Marquesas
+Pacific/Midway
+Pacific/Nauru
+Pacific/Niue
+Pacific/Norfolk
+Pacific/Noumea
+Pacific/Pago_Pago
+Pacific/Palau
+Pacific/Pitcairn
+Pacific/Ponape
+Pacific/Port_Moresby
+Pacific/Rarotonga
+Pacific/Saipan
+Pacific/Samoa
+Pacific/Tahiti
+Pacific/Tarawa
+Pacific/Tongatapu
+Pacific/Truk
+Pacific/Wake
+Pacific/Wallis
+Pacific/Yap
+Poland
+Portugal
+ROC
+ROK
+Singapore
+SystemV/AST4
+SystemV/AST4ADT
+SystemV/CST6
+SystemV/CST6CDT
+SystemV/EST5
+SystemV/EST5EDT
+SystemV/HST10
+SystemV/MST7
+SystemV/MST7MDT
+SystemV/PST8
+SystemV/PST8PDT
+SystemV/YST9
+SystemV/YST9YDT
+Turkey
+US/Alaska
+US/Aleutian
+US/Arizona
+US/Central
+US/East-Indiana
+US/Eastern
+US/Hawaii
+US/Indiana-Starke
+US/Michigan
+US/Mountain
+US/Pacific
+US/Samoa
+W-SU
+WET
+
+</pre>
+
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/help/tl.html b/help/tl.html
new file mode 100644
index 0000000000000000000000000000000000000000..621165414bbfbf4a52c7c2e5ea8982b2488b2822
--- /dev/null
+++ b/help/tl.html
@@ -0,0 +1,183 @@
+<HTML>
+<HEAD><TITLE>Autopsy Timeline Analysis Help</TITLE></HEAD>
+<BODY BGCOLOR=#CCCC99>
+
+<CENTER><H2>Timeline Mode</H2></CENTER>
+<H3>Overview</H3>
+<P>
+For some investigations, creating a timeline of activity can be 
+useful to identify places where the analysis should begin.   Of
+course file times can be easily modified by an attacker, so they
+can not be 100% trusted.  But, Autopsy can create timelines of
+file activity.  
+
+<P>
+Files have at least three times associated with them.  The details of
+each time varies with the file system type.  
+
+<P>
+The following times exist for UNIX file systems (EXT2FS & FFS): 
+
+<UL>
+  <LI><B>Modified</B>: When the file data was last 
+  modified.  This time can be modified using the utimes()
+  function.  This time is preserved in a 'tar' archive, so it is
+  possible to have M-times of files prior to when they were introduced
+  to the system.  
+
+  <LI><B>Accessed</B>: When the file data was last
+  accessed.  This time can be modified using the utimes() function.
+
+  <LI><B>Changed</B>: When the file status (inode data)
+  was last changed.  This time can not be set using the utimes()
+  function in UNIX (but it will be set when utimes() is used to modify
+  other values).
+</UL>
+
+The EXT2FS file system also has a Deleted time, but it is not displayed
+in the timeline.
+
+<P>
+A FAT File system has the following times:
+<UL>
+  <LI><B>Written</B>: When the file was last written to.
+  It is the ONLY required time in the FAT file system.
+
+  <LI><B>Accessed</B>: When the file was last accessed.  In
+  FAT, it is only accurate to the day (not minute).  It is an optional
+  value, so some Operating Systems may not update it.
+
+  <LI><B>Created</B>: When the file was created.  It is 
+  also optional, so some Operating Systems may not update it.  In fact,
+  many Windows installations have a C-Time of 0 for directories such as
+  <TT>C:\\Windows</TT> and <TT>C:\\Program Files</TT>.  
+</UL>
+
+<P>
+The NTFS File system has several times, four of which are
+used in the timeline.  These times are gathered from the
+<TT>\$STANDARD_INFORMATION</TT> attribute. 
+<UL>
+  <LI><B>Written</B>: When the file was last written to.
+
+  <LI><B>Accessed</B>: When the file was last accessed.  
+
+  <LI><B>Changed</B>: When the MFT entry was last modified.
+
+  <LI><B>Created</B>: When the file was created.
+</UL>
+
+
+<H3>How to Create a Timeline</H3>
+Creating a timeline takes two steps.  The first step extracts and
+saves the needed data from each file system images.  This step
+stores the data from each specific file system in a generic format.
+Historically (from TCT), this file was called the <TT>body</TT>
+file.  The second step takes the <TT>body</TT> file as input and
+generates an ASCII timeline of file activity between two specified
+dates.  The resulting timeline can be viewed in Autopsy or using
+a text editor.
+
+
+<H3>Creating the Body File</H3>
+The file meta-data must be extracted from the file system images and saved
+to the <TT>body</TT> file.  There are three major types of files that data 
+can be extracted for:  
+<UL>
+  <LI><B>Allocated Files</B>:
+Files that are seen when doing an 'ls' or 'dir' in a directory.  In
+other words, these are the files that have an allocated file name 
+structure.  
+
+  <LI><B>Unallocated Files</B>:
+Files that have been deleted, but that TSK can still access. 
+Files in this category include orphan files, which are files that
+no longer have a name, but whose metadata still exists. 
+If a deleted file name points to an allocated metadata structure, 
+then the name will say (realloc) next to it.
+
+</UL>
+
+<P>
+To create the <TT>body</TT> file, select the images to analyze from
+the list on top.  Next, select which types of data that you want to
+extract.  By default all types are extracted.  Lastly, identify the 
+name of the body file to create.  The file will be created in the
+<TT>output</TT> directory and an entry will be added to the host config
+file.   You will be given the option to calculate the MD5 value of
+the new file.
+
+
+<H3>Creating the Timeline</H3>
+The next window allows one to create a timeline based on the newly
+created <TT>body</TT> file.  Or, one can select the option from
+the left-hand side menu.  The range of dates must be selected as
+well as the name of the timeline file.  The resulting timeline will
+use the time zone for the host. 
+
+<P>
+If the images are from a
+UNIX file system, then the password and group files can be used to
+change the UID and GID to actual names.  If the partition from the
+root directory exists in the host, select it from the pull down
+list and Autopsy will find the <TT>/etc/passwd</TT> and
+<TT>/etc/group</TT> file contents.
+
+<P>
+The timeline  will be created in the <TT>output</TT> directory.
+You will be given the option to calculate the MD5 hash value of
+the new file.
+
+<H3>Viewing the Timeline</H3>
+The timeline can be viewed in Autopsy.  Timelines tend to be very
+large though and have thousands of lines.  HTML browsers can not
+handle tables of this size very well and typically have trouble
+processing it.  Therefore, Autopsy only allows you to view the
+timeline one month at a time.  It will likely be easier to open a
+shell and examine the timeline in a text editor or pager such as
+'less' or 'more'.
+
+<P>
+The 'summary' link will show a page that contains a monthly summary
+of activity.  It shows how many many events occured in that month
+and links to the details.  This allows one to get a high level 
+view of when a lot of activity last occured.  
+
+<P>
+The following columns are in the timeline (in order):
+<UL>
+  <LI><B>Date and time</B>of the activity.  If no date is given,
+  then the activity occured at the same time as the previous entry
+  with a time.
+
+  <LI><B>Size</B>.  The size of the file.
+
+  <LI><B>Entry Type</B>.  The 'm', 'a', 'c', and 'b' letters will exist to 
+  identify which of the activity types this entry corresponds to.  'm' is
+  for modified times, 'a' is for access times, 'c' is for change times, and
+  'b' is for created (or born) times.
+
+  <LI><B>Mode</B.  The UNIX mode is shown.
+
+  <LI><B>UID</B>.  The User Id or User name is shown.  If a password
+  file was provided when the timeline was created, then the colunn should
+  only have names.  
+
+  <LI><B>GID</B>.  The Group Id or Group name is shown.  If a group
+  file was provided when the timeline was created, then the colunn should
+  only have names.  
+
+  <LI><B>Meta Data Address</B>.  The inode or MFT entry address for the 
+  associated file.  
+
+  <LI><B>File Name</B>.  The name of the file and the destination of a 
+  symbolic link.  Deleted entries will have '(deleted)' at the end and 
+  deleted entries that point to an allocated meta data structure will
+  have '(realloc)'.  
+
+
+</UL>
+
+<HR>
+<FONT SIZE=0>Brian Carrier</FONT>
+</BODY></HTML>
diff --git a/lib/.perltidyrc b/lib/.perltidyrc
new file mode 100755
index 0000000000000000000000000000000000000000..f1f2e71a01bcfcdb8bd171c25e4d7a1e1e797c93
--- /dev/null
+++ b/lib/.perltidyrc
@@ -0,0 +1,5 @@
+-i=4	# indent of 4
+-pt=2	# paren tightness
+-sbt=2	# square paren tightness
+-bt=2	# curly paren tightness
+-nsfs	# no space after semi in for loop
diff --git a/lib/Appsort.pm b/lib/Appsort.pm
new file mode 100644
index 0000000000000000000000000000000000000000..bdf82bfad6e334f104a1b96bc93e50180f5cf451
--- /dev/null
+++ b/lib/Appsort.pm
@@ -0,0 +1,399 @@
+#
+# Sort files based on their application type (content)
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2008 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 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.
+
+package Appsort;
+
+$Appsort::FRAME = 1;
+$Appsort::MENU  = 2;
+$Appsort::ENTER = 3;
+$Appsort::RUN   = 4;
+$Appsort::VIEW  = 5;
+$Appsort::BLANK = 6;
+
+sub main {
+
+    if ($::LIVE == 1) {
+        Print::print_html_header("Unsupported for Live Analysis");
+        print
+"<center><h2>This feature is not available during a live analysis</h2></center>";
+        Print::print_html_footer();
+        return 0;
+    }
+
+    # By default, show the main frame
+    $Args::args{'view'} = $Args::enc_args{'view'} = $Appsort::FRAME
+      unless (exists $Args::args{'view'});
+
+    Args::check_view();
+    my $view = Args::get_view();
+
+    if ($view == $Appsort::BLANK) {
+        return blank();
+    }
+
+    # Check Basic Args
+    Args::check_vol('vol');
+
+    # These windows don't need the meta data address
+    if ($view == $Appsort::FRAME) {
+        return frame();
+    }
+    elsif ($view == $Appsort::ENTER) {
+        return enter();
+    }
+    elsif ($view == $Appsort::MENU) {
+        return menu();
+    }
+    elsif ($view == $Appsort::RUN) {
+        return run();
+    }
+    elsif ($view == $Appsort::VIEW) {
+        return view();
+    }
+    else {
+        Print::print_check_err("Invalid Application Sorting View");
+    }
+}
+
+sub get_sorter_dir {
+    if ($Args::args{'vol'} =~ /^($::REG_VNAME)$/) {
+        return "$::host_dir" . "$::DATADIR/sorter-$1/";
+    }
+    Print::print_err("Invalid Sorter Directory");
+}
+
+sub get_sorter_graphics_dir {
+    if ($Args::args{'vol'} =~ /^($::REG_VNAME)$/) {
+        return "$::host_dir" . "$::DATADIR/sorter-graphics-$1/";
+    }
+    Print::print_err("Invalid Sorter Graphics Directory");
+}
+
+# sorter frameset
+sub frame {
+    Print::print_html_header_frameset("Sorter on $Args::args{'vol'}");
+
+    print "<frameset cols=\"20%,80%\">\n";
+
+    # Block List
+    print "<frame src=\"$::PROGNAME?mod=$::MOD_APPSORT&view=$Appsort::MENU&"
+      . "$Args::baseargs\">\n";
+
+    # Blank
+    print "<frame src=\"$::PROGNAME?mod=$::MOD_APPSORT&view=$Appsort::BLANK&"
+      . "$Args::baseargs\" name=\"content\">\n"
+      . "</frameset>\n";
+
+    Print::print_html_footer_frameset();
+    return 0;
+}
+
+# The left-hand frame for running sorter
+sub menu {
+    Print::print_html_header("sorter menu");
+
+    print "<p><a href=\"$::PROGNAME?mod=$::MOD_APPSORT&view=$Appsort::ENTER&"
+      . "$Args::baseargs\" "
+      . "target=\"content\">Sort Files by Type</a>";
+
+    print "<p><a href=\"$::PROGNAME?mod=$::MOD_APPSORT&view=$Appsort::VIEW&"
+      . "$Args::baseargs\" "
+      . "target=\"content\">View Sorted Files</a>";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# Get the data and print the form so that sorter can be run
+sub enter {
+    Print::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=\"mod\" value=\"$::MOD_APPSORT\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Appsort::RUN\">\n"
+      . "<input type=\"hidden\" name=\"vol\" value=\"$Args::args{'vol'}\">\n"
+      . Args::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")) {
+
+        # NSRL
+        print
+"<p><input type=\"checkbox\" name=\"sorter_nsrl\" value=\"1\" CHECKED>"
+          . "Exclude files in the <b>NIST NSRL</b>\n";
+    }
+
+    if (($Caseman::alert_db ne "") && (-e "$Caseman::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 (($Caseman::exclude_db ne "") && (-e "$Caseman::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\" "
+      . "width=43 height=20 alt=\"Ok\" border=\"0\">\n</form>\n";
+
+    Print::print_html_footer();
+    return;
+}
+
+# Run sorter on the image
+sub run {
+    Print::print_html_header("sorter - create");
+
+    my $sort_args = "";
+    my $ext       = 0;
+    my $cat       = 0;
+
+    my $vol = Args::get_vol('vol');
+    my $mnt = $Caseman::vol2mnt{$vol};
+
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    Print::log_host_inv("Running 'sorter' on ($Caseman::vol2sname{$vol}");
+
+    $ext = 1
+      if ( (exists $Args::args{'sorter_ext'})
+        && ($Args::args{'sorter_ext'} == 1));
+    $cat = 1
+      if ( (exists $Args::args{'sorter_cat'})
+        && ($Args::args{'sorter_cat'} == 1));
+
+    if (($cat == 0) && ($ext == 0)) {
+        print "At least one action must be selected\n"
+          . "<p><a href=\"$::PROGNAME?mod=$::MOD_APPSORT&"
+          . "view=$Appsort::ENTER&$Args::baseargs\">"
+          . "<img border=0 src=\"pict/but_ok.jpg\" alt=\"Ok\" "
+          . "width=43 height=20></a>\n";
+
+        return;
+    }
+
+    # If both actions are wanted then no flags are needed
+    $sort_args .= "-e " if (($ext == 1) && ($cat == 0));
+    $sort_args .= "-E " if (($ext == 0) && ($cat == 1));
+
+    my $sort_dir = get_sorter_dir();
+
+    if ($cat == 1) {
+        if (   (exists $Args::args{'sorter_img'})
+            && ($Args::args{'sorter_img'} == 1))
+        {
+            my $config = "$::TSKDIR/../share/tsk3/sorter/images.sort";
+
+            Print::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::args{'sorter_save'})
+                && ($Args::args{'sorter_save'} == 1));
+
+            $sort_args .= "-U "
+              if ( (exists $Args::args{'sorter_unk'})
+                && ($Args::args{'sorter_unk'} == 1));
+        }
+    }
+
+    if ($::NSRLDB ne "") {
+        $sort_args .= "-n \'$::NSRLDB\' "
+          if ( (exists $Args::args{'sorter_nsrl'})
+            && ($Args::args{'sorter_nsrl'} == 1));
+    }
+
+    if ($Caseman::alert_db ne "") {
+        $sort_args .= "-a \'$Caseman::alert_db\' "
+          if ( (exists $Args::args{'sorter_alert'})
+            && ($Args::args{'sorter_alert'} == 1));
+    }
+
+    if ($Caseman::exclude_db ne "") {
+        $sort_args .= "-x \'$Caseman::exclude_db\' "
+          if ( (exists $Args::args{'sorter_exclude'})
+            && ($Args::args{'sorter_exclude'} == 1));
+    }
+
+    unless (-d "$sort_dir") {
+        unless (mkdir "$sort_dir", $::MKDIR_MASK) {
+            Print::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' -o $offset -i $imgtype -f $ftype $sort_args $img";
+
+    # print "Executing: <tt>sorter $exec</tt><p>\n";
+
+    # Execute Sorter
+    my $hit_cnt = 0;
+    $SIG{ALRM} = sub {
+        if (($hit_cnt++ % 5) == 0) {
+            print "+";
+        }
+        else {
+            print "-";
+        }
+        alarm(5);
+    };
+    alarm(5);
+
+    local *OUT;
+    Exec::exec_pipe(*OUT, "LANG=C LC_ALL=C '$::TSKDIR/sorter' $exec");
+    alarm(0);
+    $SIG{ALRM} = 'DEFAULT';
+
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        print "$_<br>\n";
+        $hit_cnt = 0;
+    }
+
+    close(OUT);
+
+    if (-e "$sort_dir/index.html") {
+        print "<p>Output can be found by viewing:<br>"
+          . "&nbsp;&nbsp;<tt>$sort_dir/index.html</tt><p>\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);
+    }
+
+    Print::print_html_footer();
+    return;
+}
+
+# View Page
+sub view {
+    Print::print_html_header("");
+    print "<center><h3>File Type Sorting</h3>\n"
+      . "Autopsy does not currently support viewing the sorted files.<br>\n"
+      . "After sorting, you can view the results by opening the following file:<p>\n";
+    print "<tt>" . get_sorter_dir() . "index.html</tt>";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# Blank Page
+sub blank {
+    Print::print_html_header("");
+    print "<center><h3>File Type Sorting</h3>\n"
+      . "In this mode, Autopsy will examine allocated and unallocated files<br> and "
+      . "sort them into categories and verify the extension.<p>This allows you to find a file based on"
+      . "its type and find \"hidden\" files.<p>\n"
+      .
+
+      "WARNING: This can be a time intensive process.<br>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
diff --git a/lib/Appview.pm b/lib/Appview.pm
new file mode 100644
index 0000000000000000000000000000000000000000..3a407fa2e1a081471ff5286534c3cef7e6d6ac9d
--- /dev/null
+++ b/lib/Appview.pm
@@ -0,0 +1,291 @@
+#
+# View the application layer (HTML, picutures etc.)
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2005 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 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.
+
+# Updated 1/15
+
+package Appview;
+
+$Appview::CELL_FRAME = 1;
+$Appview::CELL_MENU  = 2;
+$Appview::CELL_CONT  = 3;
+
+sub main {
+
+    # By default, show the main frame
+    $Args::args{'view'} = $Args::enc_args{'view'} = $Appview::CELL_FRAME
+      unless (exists $Args::args{'view'});
+
+    Args::check_view();
+    my $view = Args::get_view();
+
+    # Check Basic Args
+    Args::check_vol('vol');
+    Args::check_meta('meta');
+    Args::check_dir();
+    Args::check_recmode();
+
+    if ($view == $Appview::CELL_FRAME) {
+        return cell_frame();
+    }
+    elsif ($view == $Appview::CELL_CONT) {
+        return cell_content();
+    }
+    elsif ($view == $Appview::CELL_MENU) {
+        return cell_menu();
+    }
+    else {
+        Print::print_check_err("Invalid Application Viewing View");
+    }
+}
+
+#########################################################################
+#
+# CELL - Sanitized Environment
+#
+
+my $CELL_MODE_SANIT = 1;
+my $CELL_MODE_NORM  = 2;
+
+sub cell_frame {
+    Print::print_html_header_frameset("Autopsy Cell");
+    my $vol = Args::get_vol('vol');
+    my $mnt = $Caseman::vol2mnt{$vol};
+
+    my $fname = "$mnt$Args::args{'dir'}";
+
+    print "<frameset rows=\"15%,85%\">\n";
+
+    # if a mode was not given, then choose the Sanitized by default
+    $Args::args{'cell_mode'} = $CELL_MODE_SANIT
+      unless ((exists $Args::args{'cell_mode'})
+        && ($Args::args{'cell_mode'} =~ /^\d$/));
+
+    my $url =
+        "&$Args::baseargs&meta=$Args::enc_args{'meta'}"
+      . "&dir=$Args::enc_args{'dir'}&"
+      . "cell_mode=$Args::args{'cell_mode'}&recmode=$Args::args{'recmode'}";
+
+    print
+"<frame src=\"$::PROGNAME?mod=$::MOD_APPVIEW&view=$Appview::CELL_MENU${url}\">\n"
+      . "<frame src=\"$::PROGNAME?mod=$::MOD_APPVIEW&view=$Appview::CELL_CONT${url}\">\n"
+      . "</frameset>\n";
+
+    Print::print_html_footer_frameset();
+    return 0;
+}
+
+# Print the menu on top.  This allows one to export the file and change modes
+sub cell_menu {
+    Args::check_cell_mode();
+
+    Print::print_html_header("Cell Header");
+
+    my $cell_mode = $Args::args{'cell_mode'};
+
+    my $url =
+        "&$Args::baseargs&meta=$Args::enc_args{'meta'}&"
+      . "dir=$Args::enc_args{'dir'}&recmode=$Args::enc_args{'recmode'}";
+
+    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. 
+The script contents will be shown as text.<br>
+Pictures have been replaced by place holders<br>
+
+<table width=300 cellspacing=\"0\" cellpadding=\"2\">
+<tr>
+  <td align=center>
+    <a href=\"$::PROGNAME?mod=$::MOD_APPVIEW&view=$Appview::CELL_FRAME$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?mod=$::MOD_APPVIEW&view=$Appview::CELL_FRAME&$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?mod=$::MOD_FILE&view=$File::EXPORT&$url\">"
+      . "<img src=\"pict/but_export.jpg\" alt=\"export\" border=\"0\" "
+      . "width=123 height=20>"
+      . "</a></td></tr>\n";
+
+    print "<tr><td colspan=\"2\" align=\"center\">"
+      . "Deleted File Recovery Mode</td></tr>\n"
+      if ($Args::enc_args{'recmode'} == $File::REC_YES);
+
+    print "</table>";
+
+    Print::print_html_footer();
+    return;
+}
+
+# Display safe and common things in the browser (pictures, basic html)
+sub cell_content {
+    Args::check_meta('meta');
+    Args::check_dir();
+    Args::check_cell_mode();
+
+    my $meta = Args::get_meta('meta');
+    my $vol  = Args::get_vol('vol');
+    my $mnt  = $Caseman::vol2mnt{$vol};
+
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $fname = "$mnt$Args::args{'dir'}";
+
+    my $recflag = "";
+
+    $recflag = " -r "
+      if (Args::get_recmode() == $File::REC_YES);
+
+    # identify what type it is
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype $recflag  -o $offset -i $imgtype $img $meta | '$::FILE_EXE' -z -b -"
+    );
+    my $file_type = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $file_type = "Error getting file type"
+      if ((!defined $file_type) || ($file_type eq ""));
+
+    if ($file_type =~ /JPEG image data/) {
+        Print::log_host_inv("$vol: Viewing $fname ($meta) as JPEG");
+        print "Content-type: image/jpeg$::HTTP_NL$::HTTP_NL";
+    }
+    elsif ($file_type =~ /GIF image data/) {
+        Print::log_host_inv("$vol: Viewing $fname ($meta) as GIF");
+        print "Content-type: image/gif$::HTTP_NL$::HTTP_NL";
+    }
+    elsif ($file_type =~ /PNG image data/) {
+        Print::log_host_inv("$vol: Viewing $fname ($meta) as PNG");
+        print "Content-type: image/png$::HTTP_NL$::HTTP_NL";
+    }
+    elsif ($file_type =~ /PC bitmap data/) {
+        Print::log_host_inv("$vol: Viewing $fname ($meta) as BMP");
+        print "Content-type: image/bmp$::HTTP_NL$::HTTP_NL";
+    }
+    elsif ($file_type =~ /HTML document text/) {
+        Print::log_host_inv("$vol: Viewing $fname ($meta) as HTML");
+        print "Content-type: text/html$::HTTP_NL$::HTTP_NL";
+    }
+    else {
+        Print::log_host_inv("$vol: Unknown format of meta $meta ");
+        Print::print_check_err("Unknown File Type for Viewing: $file_type");
+    }
+
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+        "'$::TSKDIR/icat' -f $ftype $recflag  -o $offset -i $imgtype $img $meta"
+    );
+
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+
+        # Parse out bad "stuff"
+        if (   ($file_type =~ /HTML document text/)
+            && ($Args::args{'cell_mode'} == $CELL_MODE_SANIT))
+        {
+            $_ =~ s/\bsrc=/src=$::SANITIZE_TAG\?/ig;
+            $_ =~ s/\bhref=/href=$::SANITIZE_TAG\?/ig;
+            $_ =~ s/<script/<$::SANITIZE_TAG-script/ig;
+            $_ =~ s/\bbackground=/background=$::SANITIZE_TAG\?/ig;
+        }
+        print "$_";
+    }
+    print "$::HTTP_NL$::HTTP_NL";
+    close(OUT);
+    return 0;
+}
+
+sub sanitize_pict {
+    my $url  = shift();
+    my $lurl = $url;
+    $lurl =~ tr/[A-Z]/[a-z]/;
+
+    print "HTTP/1.0 200 OK$::HTTP_NL";
+    if (   ($lurl =~ /.jpg/i)
+        || ($lurl =~ /.jpeg/i)
+        || ($lurl =~ /.gif/i)
+        || ($lurl =~ /.png/i)
+        || ($lurl =~ /.bmp/i))
+    {
+
+        open PICT, "<$::PICTDIR/$::SANITIZE_PICT"
+          or die "can not open $::PICTDIR/$::SANITIZE_PICT";
+
+        print "Content-type: image/jpeg$::HTTP_NL$::HTTP_NL";
+        while (<PICT>) {
+            print "$_";
+        }
+        close(PICT);
+        print "$::HTTP_NL$::HTTP_NL";
+    }
+    else {
+        $url =~ tr/\+/ /;
+        $url =~ s/%([a-f0-9][a-f0-9])/chr( hex( $1 ) )/eig;
+
+        Print::print_html_header("Denied");
+        print "<h1><center>Unable to Complete Request</h1><br>\n"
+          . "<tt>Autopsy</tt> will not follow links from "
+          . "untrusted HTML pages:<br><tt>$url</tt><br>\n";
+        Print::print_html_footer();
+    }
+
+    exit(0);
+}
+
diff --git a/lib/Args.pm b/lib/Args.pm
new file mode 100644
index 0000000000000000000000000000000000000000..705cc89a39a2a67d32cae6da4bbce8660656b718
--- /dev/null
+++ b/lib/Args.pm
@@ -0,0 +1,927 @@
+#
+# Functions to check and get the arguments from URL
+#
+# ver 2.00+
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2003-2004 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 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.
+
+package Args;
+
+# Parse the argument string into the args hash
+sub parse_args {
+    my $lcl_args = shift;
+    foreach my $nam_val (split(/&/, $lcl_args)) {
+        my ($name, $value) = split(/=/, $nam_val);
+        if (defined $value) {
+            my $dec_name = url_decode($name);
+            $Args::enc_args{$dec_name} = $value;
+            $Args::args{$dec_name}     = url_decode($value);
+        }
+    }
+}
+
+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;
+}
+
+# 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 {
+    $Args::baseargs = "";
+
+    # The standard case, host, and investigator
+    $Args::baseargs .= "case=$Args::enc_args{'case'}&"
+      if ((exists $Args::enc_args{'case'}) && ($Args::enc_args{'case'} ne ""));
+    $Args::baseargs .= "host=$Args::enc_args{'host'}&"
+      if ((exists $Args::enc_args{'host'}) && ($Args::enc_args{'host'} ne ""));
+    $Args::baseargs .= "inv=$Args::enc_args{'inv'}&"
+      if ((exists $Args::enc_args{'inv'}) && ($Args::enc_args{'inv'} ne ""));
+
+    $Args::baseargs_novol = $Args::baseargs;
+
+    # Add the image, file system type, and mount point
+    $Args::baseargs .= "vol=$Args::enc_args{'vol'}&"
+      if ((exists $Args::enc_args{'vol'}) && ($Args::enc_args{'vol'} ne ""));
+
+    # remove the final '&'
+    $Args::baseargs_novol = $1 if ($Args::baseargs_novol =~ /^(.*?)&$/);
+    $Args::baseargs       = $1 if ($Args::baseargs       =~ /^(.*?)&$/);
+
+    return;
+}
+
+# Does not do mnt or img
+sub make_hidden {
+    my $str = "";
+
+    $str .=
+      "<input type=\"hidden\" name=\"host\" value=\"$Args::args{'host'}\">\n"
+      if ((exists $Args::args{'host'}) && ($Args::args{'host'} ne ""));
+
+    $str .=
+      "<input type=\"hidden\" name=\"case\" value=\"$Args::args{'case'}\">\n"
+      if ((exists $Args::args{'case'}) && ($Args::args{'case'} ne ""));
+
+    $str .=
+      "<input type=\"hidden\" name=\"inv\" value=\"$Args::args{'inv'}\">\n"
+      if ((exists $Args::args{'inv'}) && ($Args::args{'inv'} ne ""));
+
+    return $str;
+}
+
+###############################
+# block
+###############################
+sub check_block {
+    if ((!exists $Args::args{'block'}) || ($Args::args{'block'} !~ /^\d+$/)) {
+        Print::print_check_err(
+            "Invalid block argument (positive numbers only)");
+    }
+    return 0;
+}
+
+sub get_block {
+    if ($Args::args{'block'} =~ /^(\d+)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid Block");
+}
+
+###############################
+# body
+###############################
+
+sub check_body {
+    unless (exists $Args::args{'body'}) {
+        Print::print_check_err("Missing body argument");
+    }
+    unless ($Args::args{'body'} =~ /^$::REG_VNAME$/o) {
+        Print::print_check_err(
+            "Invalid body value (only letters, " . "numbers,-,., and _)");
+    }
+    return 0;
+}
+
+sub get_body {
+    if ($Args::args{'body'} =~ /^($::REG_VNAME)$/o) {
+        return $1;
+    }
+    Print::print_err("Invalid Body");
+}
+
+################################
+# Case name
+################################
+
+sub check_case {
+    unless (exists $Args::args{'case'}) {
+        Print::print_check_err("Missing case argument");
+    }
+    unless ($Args::args{'case'} =~ /^$::REG_CASE$/o) {
+        Print::print_check_err(
+            "Invalid case value (letters, num, and symbols only");
+    }
+    return 0;
+}
+
+sub get_case {
+    if ($Args::args{'case'} =~ /^($::REG_CASE)$/o) {
+        return $1;
+    }
+    Print::print_err("Invalid Case Name");
+}
+
+###############################
+# cell_mode
+###############################
+sub check_cell_mode {
+    if (   (!exists $Args::args{'cell_mode'})
+        || ($Args::args{'cell_mode'} !~ /^\d$/o))
+    {
+        Print::print_check_err(
+            "Invalid cell_mode argument (numbers >= 0 only)");
+    }
+    return 0;
+}
+
+################################
+# dir
+################################
+sub check_dir {
+    if (   (!exists $Args::args{'dir'})
+        || ($Args::args{'dir'} =~ /\/\.\.\//)
+        || ($Args::args{'dir'} =~ /\;/))
+    {
+        Print::print_check_err("Invalid dir argument (valid file path only)");
+    }
+    return 0;
+}
+
+sub get_dir {
+    if ($Args::args{'dir'} =~ /([^;]*)/o) {
+        my $d = $1;
+
+        # Remove double slashes
+        $d =~ s/\/\//\//g;
+        return $d;
+    }
+    Print::print_err("Invalid Directory");
+}
+
+###############################
+# dirmode
+###############################
+sub check_dirmode {
+    if ((!exists $Args::args{'dirmode'}) || ($Args::args{'dirmode'} !~ /^\d+$/))
+    {
+        Print::print_check_err(
+            "Invalid dirmode argument (positive numbers only)");
+    }
+    return 0;
+}
+
+sub get_dirmode {
+    if ($Args::args{'dirmode'} =~ /^(\d+)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid dirmode");
+}
+
+################################
+# do_md5
+################################
+sub check_do_md5 {
+    if ((!exists $Args::args{'do_md5'}) || ($Args::args{'do_md5'} !~ /^\d+$/)) {
+        Print::print_check_err("Missing do_md5 argument");
+    }
+    return 0;
+}
+
+sub get_do_md5 {
+    if ($Args::args{'do_md5'} =~ /^\s*(\d+)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid MD5 Flag");
+}
+
+################################
+# fname
+################################
+
+sub check_fname {
+    unless (exists $Args::args{'fname'}) {
+        Print::print_check_err("Missing fname argument");
+    }
+    unless ($Args::args{'fname'} =~ /^$::REG_FNAME$/o) {
+        Print::print_check_err(
+            "Invalid fname value (only letters, " . "numbers,-,., and _)");
+    }
+    return 0;
+}
+
+sub get_fname {
+    if ($Args::args{'fname'} =~ /^($::REG_FNAME)$/o) {
+        return "$::host_dir" . "$::DATADIR/$1";
+    }
+    Print::print_err("Invalid File Name");
+}
+
+################################
+# fname_mode
+################################
+sub check_fname_mode {
+    if (!exists $Args::args{'fname_mode'}) {
+        Print::print_check_err("Missing fname_mode argument");
+    }
+    unless ($Args::args{'fname_mode'} =~ /^\d+$/) {
+        Print::print_check_err("invalid mode: numbers only");
+    }
+    return 0;
+}
+
+################################
+# fname_rel
+# Return the relative fname
+################################
+sub get_fname_rel {
+    if ($Args::args{'fname'} =~ /^($::REG_FNAME)$/o) {
+        return "$::DATADIR/$1";
+    }
+    Print::print_err("Invalid Relative File Name");
+}
+
+###############################
+# force
+###############################
+sub get_force {
+    if ($Args::args{'force'} =~ /^(\d+)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid Force Flag");
+}
+
+################################
+# ftype
+################################
+sub get_ftype_blah {
+    if (exists $Args::args{'ftype'}) {
+        if ($Args::args{'ftype'} =~ /^($::REG_FTYPE)$/o) {
+            return $1;
+        }
+    }
+    if (   (exists $Args::args{'img'})
+        && (exists $Caseman::vol2ftype{$Args::args{'img'}}))
+    {
+        return $Caseman::vol2ftype{$Args::args{'img'}};
+    }
+    Print::print_err("Missing ftype value");
+}
+
+sub check_ftype_blah {
+    unless (
+        (
+               (exists $Args::args{'img'})
+            && (exists $Caseman::vol2ftype{$Args::args{'img'}})
+            && ($Caseman::vol2ftype{$Args::args{'img'}} =~ /^$::REG_FTYPE$/o)
+        )
+        || (   (exists $Args::args{'ftype'})
+            && ($Args::args{'ftype'} =~ /^$::REG_FTYPE$/o))
+      )
+    {
+        Print::print_check_err("Missing or invalid ftype value");
+    }
+    return 0;
+}
+
+################################
+# host
+# Host for the case
+################################
+
+sub check_host {
+    unless (exists $Args::args{'host'}) {
+        Print::print_check_err("Missing host argument");
+    }
+    unless ($Args::args{'host'} =~ /^$::REG_HOST$/o) {
+        Print::print_check_err("Invalid host value");
+    }
+    return 0;
+}
+
+sub get_host {
+    if ($Args::args{'host'} =~ /^($::REG_HOST)$/o) {
+        return $1;
+    }
+    Print::print_err("Invalid Host");
+}
+
+################################
+# htype
+################################
+sub check_htype {
+    if ((!exists $Args::args{'htype'}) || ($Args::args{'htype'} !~ /^\d+$/)) {
+        Print::print_check_err(
+            "Invalid htype argument (positive numbers only)");
+    }
+    return 0;
+}
+
+sub get_htype {
+    if ($Args::args{'htype'} =~ /^(\d+)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid htype");
+}
+
+###############################
+# ifind
+# ifind is optional and by default is 0 if not given
+###############################
+sub get_ifind {
+    if (!exists $Args::args{'ifind'}) {
+        return 0;
+    }
+    elsif ($Args::args{'ifind'} =~ /^(\d+)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid ifind flag");
+}
+
+###############################
+# 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::args{'img_path'}) {
+        Print::print_check_err("Missing image (img_path) argument");
+    }
+    elsif ($Args::args{'img_path'} =~ /^$::REG_IMG_PATH$/o) {
+
+        # Check for its actual existence
+
+        Print::print_check_err("Image not found at $Args::args{'img_path'}")
+          unless (
+            (-e "$Args::args{'img_path'}")
+            || (   (-l "$Args::args{'img_path'}")
+                && (-e readlink "$::host_dir" . "$Args::args{$img}"))
+          );
+    }
+    else {
+        Print::print_check_err("Invalid image path (only letters, "
+              . "numbers,-,.,_/ and start with /) [$Args::args{'img_path'}]");
+    }
+
+    return 0;
+}
+
+sub get_img_path {
+    if ($Args::args{'img_path'} =~ /^($::REG_IMG_PATH)$/o) {
+        return "$1";
+    }
+    Print::print_err("Invalid Image Path");
+}
+
+sub check_img_path_wild {
+    if (!exists $Args::args{'img_path'}) {
+        Print::print_check_err("Missing  wild image (img_path) argument");
+    }
+    elsif ($Args::args{'img_path'} !~ /^$::REG_IMG_PATH_WILD$/o) {
+
+        # IF there is extra white space then remove it and move on
+        if ($Args::args{'img_path'} =~ /^\s*($::REG_IMG_PATH_WILD)\s*$/o) {
+            $Args::args{'img_path'} = $1;
+            return 0;
+        }
+        else {
+            Print::print_check_err("Invalid wild image (img_path) argument");
+        }
+    }
+
+    return 0;
+}
+
+sub get_img_path_wild {
+    if ($Args::args{'img_path'} =~ /^($::REG_IMG_PATH_WILD)$/o) {
+        return "$1";
+    }
+    Print::print_err("Invalid Image Path");
+}
+
+###############################
+# meta
+###############################
+
+sub check_meta {
+    my $meta = shift;
+    if (   (!exists $Args::args{$meta})
+        || ($Args::args{$meta} !~ /^$::REG_META$/o))
+    {
+        Print::print_check_err(
+            "Invalid meta address ($meta) argument (numbers >= 0 only)");
+    }
+    return 0;
+}
+
+sub get_meta {
+    my $meta = shift;
+    if ($Args::args{$meta} =~ /^($::REG_META)$/o) {
+        return $1;
+    }
+    Print::print_err("Invalid Meta Address");
+}
+
+################################
+# inv
+# Investigator
+################################
+
+sub check_inv {
+    unless (exists $Args::args{'inv'}) {
+        Print::print_check_err("Missing inv argument");
+    }
+    unless ($Args::args{'inv'} =~ /^$::REG_INVESTIG$/o) {
+        Print::print_check_err(
+            "Invalid inv value (letters, num, and symbols only");
+    }
+    return 0;
+}
+
+sub get_inv {
+    if ($Args::args{'inv'} =~ /^($::REG_INVESTIG)$/o) {
+        return $1;
+    }
+    Print::print_err("Invalid Investigator");
+}
+
+###############################
+# len
+###############################
+sub check_len {
+    if (   (!exists $Args::args{'len'})
+        || ($Args::args{'len'} !~ /^\d+$/)
+        || ($Args::args{'len'} == 0))
+    {
+        Print::print_check_err("Invalid len argument (positive numbers only)");
+    }
+    return 0;
+}
+
+sub get_len {
+    if ((exists $Args::args{'len'}) && ($Args::args{'len'} =~ /^(\d+)$/)) {
+        return $1;
+    }
+
+    # return the default len of 1 if it is not defined
+    return 1;
+}
+
+###############################
+# min
+###############################
+sub get_min {
+    if ($Args::args{'min'} =~ /^(\d+)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid Minute");
+}
+
+################################
+# module
+################################
+sub check_mod {
+    if ((!exists $Args::args{'mod'}) || ($Args::args{'mod'} !~ /^\d+$/)) {
+        Print::print_check_err(
+            "Invalid Module argument (positive numbers only)");
+    }
+    return 0;
+}
+
+sub get_mod {
+    if ($Args::args{'mod'} =~ /^(\d+)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid Module");
+}
+
+################################
+# mnt
+###############################
+
+sub check_mnt {
+    my $ftype = Args::get_ftype();
+    if (($ftype eq "blkls") || ($ftype eq "swap") || ($ftype eq "raw")) {
+        $Args::args{'mnt'}     = $ftype;
+        $Args::enc_args{'mnt'} = $ftype;
+    }
+    elsif (!exists $Args::args{'mnt'}) {
+
+        # Look it up if it is not found
+        if (exists $Args::args{'img'}) {
+            unless (exists $Caseman::vol2mnt{$Args::args{'img'}}) {
+                Print::print_check_err(
+                    "Mounting point not found: $Args::args{'img'}");
+            }
+            my $mnt = $Caseman::vol2mnt{$Args::args{'img'}};
+            $Args::args{'mnt'}     = $mnt;
+            $Args::enc_args{'mnt'} = Args::url_encode($mnt);
+        }
+        else {
+            Print::print_check_err("Mounting point not found");
+        }
+    }
+    if ($Args::args{'mnt'} =~ /\/\.\.\//) {
+        Print::print_check_err(
+            "Invalid mount point argument (valid file path only)");
+    }
+    unless ($Args::args{'mnt'} =~ /^$::REG_MNT$/o) {
+        Print::print_check_err(
+            "Invalid mount point argument (valid file path only)");
+    }
+    return 0;
+}
+
+sub get_mnt {
+    if ((exists $Args::args{'mnt'}) && ($Args::args{'mnt'} =~ /($::REG_MNT)/o))
+    {
+        return $1;
+    }
+    Print::print_err("Invalid Mounting Point");
+}
+
+################################
+# note
+################################
+sub check_note {
+    if (!exists $Args::args{'note'}) {
+        Print::print_check_err("Missing note argument");
+    }
+    return 0;
+}
+
+#################
+# num_img - adding disk images
+
+sub check_num_img {
+    if ((!exists $Args::args{'num_img'}) || ($Args::args{'num_img'} !~ /^\d+$/))
+    {
+        Print::print_check_err(
+            "Invalid num_img argument (positive numbers only)");
+    }
+    return 0;
+}
+
+sub get_num_img {
+    if ($Args::args{'num_img'} =~ /^(\d+)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid num_img");
+}
+
+###############################
+# recmode
+###############################
+sub check_recmode {
+    if ((!exists $Args::args{'recmode'}) || ($Args::args{'recmode'} !~ /^\d+$/))
+    {
+        Print::print_check_err(
+            "Invalid recmode argument (positive numbers only)");
+    }
+    return 0;
+}
+
+sub get_recmode {
+    if ($Args::args{'recmode'} =~ /^(\d+)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid recmode");
+}
+
+################################
+# srchidx
+#
+# Index for previous keyword search
+###############################
+sub check_srchidx {
+    if ((!exists $Args::args{'srchidx'}) || ($Args::args{'srchidx'} !~ /^\d+$/))
+    {
+        Print::print_check_err(
+            "Invalid srchidx argument (positive numbers only)");
+    }
+    return 0;
+}
+
+###############################
+# sort
+###############################
+sub check_sort {
+    if ((!exists $Args::args{'sort'}) || ($Args::args{'sort'} !~ /^\d+$/)) {
+        Print::print_check_err("Invalid sort argument (positive numbers only)");
+    }
+    return 0;
+}
+
+sub get_sort {
+    if ($Args::args{'sort'} =~ /^(\d+)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid sort flag");
+}
+
+################################
+# st_mon
+################################
+sub check_st_mon {
+    if (   (exists $Args::args{'st_mon'})
+        && ($Args::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::args{'st_mon'} =~ /^(\d\d?)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid Month");
+}
+
+################################
+# st_year
+################################
+sub check_st_year {
+    if (   (exists $Args::args{'st_year'})
+        && ($Args::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::args{'st_year'} =~ /^(\d\d\d\d)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid Year");
+}
+
+################################
+# str
+# search string
+################################
+# This should be made more flexible
+sub check_str {
+    if (!exists $Args::args{'str'}) {
+        Print::print_check_err("Missing string argument");
+    }
+    return 0;
+}
+
+sub get_str {
+    if ($Args::args{'str'} =~ /^\s*(.*)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid String");
+}
+
+###############################
+# submod
+# Used by the tab module to identify the actual module
+###############################
+sub check_submod {
+    if ((!exists $Args::args{'submod'}) || ($Args::args{'submod'} !~ /^\d+$/)) {
+        Print::print_check_err(
+            "Invalid sub-mode argument (positive numbers only)");
+    }
+    return 0;
+}
+
+sub get_submod {
+    if ($Args::args{'submod'} =~ /^(\d+)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid sub-mode");
+}
+
+################################
+# tl
+###############################
+sub check_tl {
+    if ((!exists $Args::args{'tl'}) || ($Args::args{'tl'} !~ /^$::REG_VNAME$/))
+    {
+        Print::print_check_err(
+            "Invalid timeline argument (positive numbers only)");
+    }
+    return 0;
+}
+
+sub get_tl {
+    if ($Args::args{'tl'} =~ /^($::REG_VNAME)$/o) {
+        return $1;
+    }
+    Print::print_err("Invalid Timeline");
+}
+
+################################
+# ts
+# time skew
+################################
+sub check_ts {
+    if ((!exists $Args::args{'ts'}) || ($Args::args{'ts'} !~ /^$::REG_SKEW$/o))
+    {
+        Print::print_check_err("Missing time skew argument");
+    }
+    return 0;
+}
+
+sub get_ts {
+    if ($Args::args{'ts'} =~ /^\s*($::REG_SKEW)$/o) {
+        return $1;
+    }
+    Print::print_err("Invalid Time Skew");
+}
+
+################################
+# tz
+# timezone
+################################
+sub check_tz {
+    if (   (!exists $Args::args{'tz'})
+        || ($Args::args{'tz'} !~ /^$::REG_ZONE_ARGS$/o))
+    {
+        Print::print_check_err("Missing time zone argument");
+    }
+    return 0;
+}
+
+sub get_tz {
+    if ($Args::args{'tz'} =~ /^($::REG_ZONE_ARGS)$/o) {
+        return $1;
+    }
+    Print::print_err("Invalid Timezone");
+}
+
+################################
+# unitsize
+################################
+sub get_unitsize {
+
+    my $vol   = Args::get_vol('vol');
+    my $ftype = $Caseman::vol2ftype{$vol};
+    my $blkcat_out;
+
+    if ($ftype eq 'blkls') {
+        if (exists $Caseman::mod2vol{$vol}) {
+            my $orig    = $Caseman::mod2vol{$vol};
+            my $img     = $Caseman::vol2path{$orig};
+            my $offset  = $Caseman::vol2start{$orig};
+            my $imgtype = $Caseman::vol2itype{$orig};
+
+            local *OUT;
+            Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $Caseman::vol2ftype{$orig} -s -o $offset -i $imgtype $img"
+            );
+            $blkcat_out = <OUT>;
+            close(OUT);
+        }
+
+        # We don't have the original image, so just set the size to 512
+        else {
+            return 512;
+        }
+    }
+    elsif ($ftype eq 'swap') {
+        return 4096;
+    }
+    elsif ($ftype eq 'raw') {
+        return 512;
+    }
+    elsif ($Caseman::vol2cat{$vol} eq 'disk') {
+        return 512;
+    }
+    else {
+        my $img     = $Caseman::vol2path{$vol};
+        my $offset  = $Caseman::vol2start{$vol};
+        my $imgtype = $Caseman::vol2itype{$vol};
+
+        local *OUT;
+        Exec::exec_pipe(*OUT,
+            "'$::TSKDIR/blkcat' -f $ftype -s -o $offset -i $imgtype $img");
+        $blkcat_out = <OUT>;
+        close(OUT);
+    }
+    $blkcat_out = "Error getting unit size"
+      if ((!defined $blkcat_out) || ($blkcat_out eq ""));
+
+    if ($blkcat_out =~ /(\d+): Size of Addressable Unit/) {
+        return $1;
+    }
+    else {
+        Print::print_err("Error identifying block size (blkcat -s output)\n"
+              . "$blkcat_out\n");
+    }
+}
+
+################################
+# View - subset of module
+################################
+sub check_view {
+    if ((!exists $Args::args{'view'}) || ($Args::args{'view'} !~ /^\d+$/)) {
+        Print::print_check_err("Invalid View argument (positive numbers only)");
+    }
+    return 0;
+}
+
+sub get_view {
+    if ($Args::args{'view'} =~ /^(\d+)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid View");
+}
+
+###############################
+# We don't allow much for the volume because this is an argument to
+# the TSK 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_-.
+#
+# The argument is the name of the image
+###############################
+
+sub check_vol {
+    my $vol = shift;
+    if ((!exists $Args::args{$vol}) || ($Args::args{$vol} !~ /^$::REG_VNAME$/))
+    {
+        Print::print_check_err(
+            "Invalid volume argument (name and number only)");
+    }
+    return 0;
+}
+
+sub get_vol {
+    my $vol = shift;
+    if ($Args::args{$vol} =~ /^($::REG_VNAME)$/) {
+        return $1;
+    }
+    Print::print_err("Invalid volume ($vol)");
+}
+
+1;
diff --git a/lib/Caseman.pm b/lib/Caseman.pm
new file mode 100644
index 0000000000000000000000000000000000000000..a34db680878b7ef6a5acec789eb50bfc4296b5ed
--- /dev/null
+++ b/lib/Caseman.pm
@@ -0,0 +1,4161 @@
+#
+# Case Management methods, including the windows and functions to read the
+# config files
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2005 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 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.
+
+package Caseman;
+
+# If the order of these views are changed, then the order of the main
+# function may have to be as well
+
+# Case Views
+$Caseman::CASE_NEW      = 1;
+$Caseman::CASE_NEW_DOIT = 2;
+$Caseman::CASE_OPEN     = 3;
+$Caseman::CASE_OPEN_LOG = 4;
+$Caseman::CASE_DETAILS  = 5;
+
+# $Caseman::CASE_DEL = 6;
+my $CASE_MAX = 5;
+
+# Host Views
+$Caseman::HOST_ADD      = 7;
+$Caseman::HOST_ADD_DOIT = 8;
+$Caseman::HOST_OPEN     = 9;
+$Caseman::HOST_OPEN_LOG = 10;
+$Caseman::HOST_DETAILS  = 11;
+
+# $Caseman::HOST_DEL = 12;
+my $HOST_MAX = 11;
+
+# Image Views
+$Caseman::IMG_ADD       = 13;
+$Caseman::IMG_ADD_PREP  = 14;
+$Caseman::IMG_ADD_DOIT  = 15;
+$Caseman::VOL_OPEN      = 16;
+$Caseman::VOL_OPEN_LOG  = 17;
+$Caseman::VOL_DETAILS   = 18;
+$Caseman::IMG_DEL       = 19;
+$Caseman::VOL_MAKESTR   = 20;
+$Caseman::VOL_MAKEBLKLS = 21;
+my $IMG_MAX = 21;
+
+# Module Variables
+# %vol2par - Volume to parent volume (vol to img, str to vol)
+# %vol2start - Starting sector of volume in image
+# %vol2end  - ending sector of volume in image
+# %vol2cat - The big picture type of volume (part, disk, strings, blkls)
+# %vol2ftype - The file system type (fat, dos, ntfs etc.)
+# %vol2itype - The image file type (could be for a parent image)
+# %vol2dtype- the disk type
+# %mod2vol;   # Mapping for image, given the strings or blkls
+# %vol2mnt;   # Mapping for mount point, given the vol name
+# %vol2str;   # Mapping for ASCII strings file, given  the vol name
+# %vol2uni;   # Mapping for Unicode strings file, given  the vol name
+# %vol2blkls;   # Mapping for blkls file, given  the vol name
+# %vol2path - full file path of volume
+# %vol2sname - short name of volume
+
+sub main {
+
+    # By default, show the case open window
+    $Args::args{'view'} = $Args::enc_args{'view'} = $Caseman::CASE_OPEN
+      unless (exists $Args::args{'view'});
+
+    Args::check_view();
+    my $view = Args::get_view();
+
+    # The only live function is for the open img
+    if ($::LIVE == 1) {
+        Args::check_inv();
+        if ($view == $Caseman::VOL_OPEN) {
+            return vol_open();
+        }
+
+        Args::check_vol('vol');
+
+        # Args::check_ftype();
+        # Args::check_mnt();
+
+        if ($view == $Caseman::VOL_OPEN_LOG) {
+            return vol_open_log();
+        }
+        else {
+            Print::print_check_err(
+                "Invalid Live Analysis Case Management View");
+        }
+        return 0;
+    }
+
+    # Case functions
+    if ($view <= $CASE_MAX) {
+        if ($view == $Caseman::CASE_OPEN) {
+            return case_open();
+        }
+        elsif ($view == $Caseman::CASE_NEW) {
+            return case_new();
+        }
+
+        Args::check_case();
+        $::case_dir = "$::LOCKDIR/" . Args::get_case() . "/";
+        $::case_dir =~ s/\/\//\//g;
+
+        if ($view == $Caseman::CASE_OPEN_LOG) {
+            return case_open_log();
+        }
+        elsif ($view == $Caseman::CASE_NEW_DOIT) {
+            return case_new_doit();
+        }
+        elsif ($view == $Caseman::CASE_DETAILS) {
+            return case_details();
+        }
+    }
+
+    Args::check_case();
+    $::case_dir = "$::LOCKDIR/" . Args::get_case() . "/";
+    $::case_dir =~ s/\/\//\//g;
+
+    # Host functions
+    if ($view <= $HOST_MAX) {
+        if ($view == $Caseman::HOST_OPEN) {
+            return host_open();
+        }
+        elsif ($view == $Caseman::HOST_ADD) {
+            return host_add();
+        }
+
+        Args::check_host();
+        $::host_dir = "$::case_dir" . Args::get_host() . "/";
+        $::host_dir =~ s/\/\//\//g;
+        if ($view == $Caseman::HOST_ADD_DOIT) {
+            return host_add_doit();
+        }
+
+        Caseman::read_host_config();
+        if ($view == $Caseman::HOST_OPEN_LOG) {
+            return host_open_log();
+        }
+        elsif ($view == $Caseman::HOST_DETAILS) {
+            return host_details();
+        }
+    }
+
+    Args::check_host();
+    $::host_dir = "$::case_dir" . Args::get_host() . "/";
+    $::host_dir =~ s/\/\//\//g;
+    Caseman::read_host_config();
+    Args::check_inv();
+
+    if ($view <= $IMG_MAX) {
+        if ($view == $Caseman::VOL_OPEN) {
+            return vol_open();
+        }
+        elsif ($view == $Caseman::IMG_ADD) {
+            return img_add();
+        }
+        elsif ($view == $Caseman::IMG_ADD_PREP) {
+            return img_add_prep();
+        }
+        elsif ($view == $Caseman::IMG_ADD_DOIT) {
+            return img_add_doit();
+        }
+
+        Args::check_vol('vol');
+
+        if ($view == $Caseman::VOL_OPEN_LOG) {
+            return vol_open_log();
+        }
+        elsif ($view == $Caseman::VOL_DETAILS) {
+            return vol_details();
+        }
+
+        #       elsif ($view == $Caseman::IMG_DEL) {
+        # 		return img_del();
+        # 	}
+        elsif ($view == $Caseman::VOL_MAKESTR) {
+            return vol_makestr();
+        }
+        elsif ($view == $Caseman::VOL_MAKEBLKLS) {
+            return vol_makeblkls();
+        }
+    }
+
+    Print::print_check_err("Invalid Case Management View");
+}
+
+####################################################################
+# General menu Functions
+
+sub print_menu_tabs {
+
+    if ($::LIVE == 1) {
+        print "<h2>Live Analysis Mode</h2>\n";
+    }
+
+    print "<table width=\"600\" height=\"60\" background=\"$::YEL_PIX\" "
+      . "border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tr>\n"
+      . "<td align=\"center\" width=\"200\">";
+
+    my $view = Args::get_view();
+
+    # Case Gallery Tab
+    if ($view == $Caseman::CASE_OPEN) {
+        print "<img border=0 src=\"pict/menu_t_cg_cur.jpg\" "
+          . "width=200 height=65 alt=\"Case Gallery (Current Mode)\">\n";
+    }
+    elsif ($::LIVE == 1) {
+        print "<img border=0 src=\"pict/menu_t_cg_org.jpg\" "
+          . "width=200 height=65 alt=\"Case Gallery\">\n";
+    }
+    else {
+        print "<a href=\"$::PROGNAME?"
+          . "mod=$::MOD_CASEMAN&view=$Caseman::CASE_OPEN\">"
+          . "<img border=0 src=\"pict/menu_t_cg_link.jpg\" "
+          . "width=200 height=65 alt=\"Case Gallery\"></a>\n";
+    }
+    print "</td>\n" . "<td align=\"center\" width=\"200\">";
+
+    # Host Gallery Tab
+    # Current
+    if ($view == $Caseman::HOST_OPEN) {
+        print "<img border=0 src=\"pict/menu_t_hg_cur.jpg\" "
+          . "width=200 height=65 alt=\"Host Gallery (Current Mode)\">\n";
+    }
+
+    # Link
+    elsif (($view == $Caseman::VOL_OPEN) && ($::LIVE == 0)) {
+        print "<a href=\"$::PROGNAME?"
+          . "mod=$::MOD_CASEMAN&view=$Caseman::HOST_OPEN"
+          . "&case=$Args::args{'case'}\">"
+          . "<img border=0 src=\"pict/menu_t_hg_link.jpg\" "
+          . "width=200 height=65 alt=\"Host Gallery\"></a>\n";
+    }
+
+    # Non-link
+    else {
+        print "<img border=0 src=\"pict/menu_t_hg_org.jpg\" "
+          . "width=200 height=65 alt=\"Host Gallery (Not Available)\">\n";
+    }
+
+    print "</td>\n" . "<td align=\"center\" width=\"200\">";
+
+    # Host Manager Tab
+    # Current
+    if ($view == $Caseman::VOL_OPEN) {
+        print "<img border=0 src=\"pict/menu_t_hm_cur.jpg\" "
+          . "width=200 height=65 alt=\"Host Manager (Current Mode)\">\n";
+    }
+
+    # non-link
+    else {
+        print "<img border=0 src=\"pict/menu_t_hm_org.jpg\" "
+          . "width=200 height=65 alt=\"Host Manager (Not Available)\">\n";
+    }
+
+    print "</td>\n</tr>\n" . "</table>\n";
+}
+
+####################################################################
+# Case Functions
+
+# 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::args{'case'}/case.aut";
+    }
+}
+
+# Read case config and save it to $Caseman::cvals
+sub read_case_config {
+    return if ($::LIVE == 1);
+
+    my $case;
+
+    if (scalar(@_) == 1) {
+        $case = shift;
+    }
+    else {
+        $case = Args::get_case();
+    }
+
+    my $fname = case_config_fname($case);
+
+    %Caseman::cvals = ();
+
+    open CONFIG, "<$fname"
+      or die "Can't open case config file ($fname)";
+
+    while (<CONFIG>) {
+        next if ((/^\#/) || (/^\s+$/));
+        s/^\s+//;
+        s/\s+$//;
+        $Caseman::cvals{$1} = Print::html_encode($2) if (/^(\S+)\s+(.*)$/);
+    }
+    close(CONFIG);
+
+    $Caseman::cvals{'desc'} = "None Provided"
+      unless (exists $Caseman::cvals{'desc'});
+
+    $Caseman::cvals{'created'} = "unknown"
+      unless (exists $Caseman::cvals{'created'});
+}
+
+sub case_new {
+    Print::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=\"mod\" value=\"$::MOD_CASEMAN\">
+<input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_NEW_DOIT\">
+<tr>
+  <td colspan=3 align=left>
+    1.  <b>Case Name:</b> The name of this investigation.  It can contain only letters, numbers, and symbols.
+  </td>
+</tr>
+<tr>
+  <td>&nbsp;&nbsp;</td>
+  <td align=left colspan=2><input type=\"text\" name=\"case\"></td>
+</tr>
+
+<tr><td colspan=3>&nbsp;</td></tr>
+
+<tr>
+  <td colspan=3 align=left>
+    2.  <b>Description:</b> An optional, one line description of this case.
+  </td>
+</tr>
+<tr>
+  <td>&nbsp;&nbsp;</td>
+  <td align=left colspan=2><input type=\"text\" name=\"desc\" size=32 maxlength=32></td>
+</tr>
+
+<tr><td colspan=3>&nbsp;</td></tr>
+
+<tr>
+  <td colspan=3 align=left>
+    3.  <b>Investigator Names:</b> The optional names (with no spaces) of the investigators for this case.
+  </td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td align=left><tt>a.</tt> <input type=\"text\" name=\"inv1\"></td>
+  <td align=left><tt>b.</tt> <input type=\"text\" name=\"inv2\"></td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td align=left><tt>c.</tt> <input type=\"text\" name=\"inv3\"></td>
+  <td align=left><tt>d.</tt> <input type=\"text\" name=\"inv4\"></td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td align=left><tt>e.</tt> <input type=\"text\" name=\"inv5\"></td>
+  <td align=left><tt>f.</tt> <input type=\"text\" name=\"inv6\"></td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td align=left><tt>g.</tt> <input type=\"text\" name=\"inv7\"></td>
+  <td align=left><tt>h.</tt> <input type=\"text\" name=\"inv8\"></td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td align=left><tt>i.</tt> <input type=\"text\" name=\"inv9\"></td>
+  <td align=left><tt>j.</tt> <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\" height=20 border=0>
+  </td>
+</form>
+  <td align=center>
+    <form action=\"$::PROGNAME\" method=\"get\">
+    <input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">
+    <input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_OPEN\">
+    <input type=\"image\" src=\"pict/menu_b_cancel.jpg\" 
+    alt=\"Cancel\" width=\"167\" height=20 border=0>
+    </form>
+  </td>
+  <td align=center><a href=\"$::HELP_URL\" 
+    target=\"_blank\">
+    <img src=\"pict/menu_b_help.jpg\" alt=\"Help\" 
+    width=\"167\" height=20 border=0></a>
+  </td>
+</tr>
+</table>
+EOF
+
+    Print::print_html_footer();
+    return;
+}
+
+# Create the directory and case configuration file
+# Gets the input from CASE_NEW
+sub case_new_doit {
+    Print::print_html_header("Creating Case: $Args::args{'case'}");
+    my $case = $Args::args{'case'};
+
+    print "<h3>Creating Case: <tt>$case</tt></h3>\n";
+
+    # Make the directory
+    if (-d "$::case_dir") {
+
+        # we can't send all of this to print_err, bc it doesn't want HTML
+        print "Error: $::case_dir already exists<br>"
+          . "Please remove the directory and its contents and try again"
+          . "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
+          . "view=$Caseman::CASE_OPEN\">"
+          . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
+          . "width=\"43\" height=20 border=\"0\"></a>\n";
+        Print::print_err("\n");
+    }
+
+    unless (mkdir "$::case_dir", $::MKDIR_MASK) {
+        Print::print_err("Error making directory $::case_dir: $!");
+    }
+
+    print "Case directory (<tt>$::case_dir</tt>) created<br>\n";
+    Print::log_case_info("Case $case created");
+
+    my $fname = Caseman::case_config_fname();
+
+    open CASE_CONFIG, ">$fname" or die "Can't open case config: $fname";
+
+    print CASE_CONFIG "# Autopsy case config file\n"
+      . "# Case: $case\n\n"
+      . "created "
+      . localtime() . "\n";
+
+    if ((exists $Args::args{'desc'}) && ($Args::args{'desc'} ne "")) {
+        Print::print_err(
+            "Invalid Description\n" . "Use the browser's back button to fix")
+          if ($Args::args{'desc'} =~ /\n/);
+
+        print CASE_CONFIG "desc $Args::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";
+
+    my $iname = investig_fname();
+    open INVES, ">>$iname" or die "Can't open investigators file: $iname";
+
+    my @invs;
+    if (   (exists $Args::args{'inv1'})
+        && ($Args::args{'inv1'} ne "")
+        && ($Args::args{'inv1'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
+    {
+        print INVES "$1\n";
+        push @invs, $1;
+    }
+    if (   (exists $Args::args{'inv2'})
+        && ($Args::args{'inv2'} ne "")
+        && ($Args::args{'inv2'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
+    {
+        print INVES "$1\n";
+        push @invs, $1;
+    }
+    if (   (exists $Args::args{'inv3'})
+        && ($Args::args{'inv3'} ne "")
+        && ($Args::args{'inv3'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
+    {
+        print INVES "$1\n";
+        push @invs, $1;
+    }
+    if (   (exists $Args::args{'inv4'})
+        && ($Args::args{'inv4'} ne "")
+        && ($Args::args{'inv4'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
+    {
+        print INVES "$1\n";
+        push @invs, $1;
+    }
+    if (   (exists $Args::args{'inv5'})
+        && ($Args::args{'inv5'} ne "")
+        && ($Args::args{'inv5'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
+    {
+        print INVES "$1\n";
+        push @invs, $1;
+    }
+    if (   (exists $Args::args{'inv6'})
+        && ($Args::args{'inv6'} ne "")
+        && ($Args::args{'inv6'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
+    {
+        print INVES "$1\n";
+        push @invs, $1;
+    }
+    if (   (exists $Args::args{'inv7'})
+        && ($Args::args{'inv7'} ne "")
+        && ($Args::args{'inv7'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
+    {
+        print INVES "$1\n";
+        push @invs, $1;
+    }
+    if (   (exists $Args::args{'inv8'})
+        && ($Args::args{'inv8'} ne "")
+        && ($Args::args{'inv8'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
+    {
+        print INVES "$1\n";
+        push @invs, $1;
+    }
+    if (   (exists $Args::args{'inv9'})
+        && ($Args::args{'inv9'} ne "")
+        && ($Args::args{'inv9'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
+    {
+        print INVES "$1\n";
+        push @invs, $1;
+    }
+    if (   (exists $Args::args{'inv10'})
+        && ($Args::args{'inv10'} ne "")
+        && ($Args::args{'inv10'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
+    {
+        print INVES "$1\n";
+        push @invs, $1;
+    }
+
+    close(INVES);
+
+    Print::log_session_info("Case $case created");
+
+    print "<br><br>We must now create a host for this case.\n";
+
+    print "<form action=\"$::PROGNAME\" method=\"get\">\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_ADD\">\n"
+      . "<input type=\"hidden\" name=\"case\" value=\"$case\">\n";
+
+    if (scalar @invs == 0) {
+        print "<option hiddden name=\"inv\" value=\"unknown\">\n";
+    }
+    else {
+        print "<br><br>Please select your name from the list: "
+          . "<select name=\"inv\" size=\"1\">\n";
+
+        foreach $i (@invs) {
+            print "<option value=\"$i\">$i</option>\n";
+        }
+        print "</select>\n";
+    }
+
+    print "<br><br>"
+      . "<input type=\"image\" src=\"pict/menu_b_hnew.jpg\" alt=\"Add New Host\" "
+      . "height=20 border=\"0\"></form>\n";
+
+    Print::print_html_footer();
+    return;
+}
+
+# Open a Case
+# This provides a form with a list of options
+sub case_open {
+    Print::print_html_header("Open A Case");
+
+    # 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 = Caseman::case_config_fname($c);
+
+        push @cases, $c
+          if ((-d "$::LOCKDIR/$c") && (-e "$cfile"));
+    }
+    closedir CASES;
+
+    print "<br><br><center>";
+
+    # Were there any cases?
+    if (scalar @cases == 0) {
+        print "No cases exist in <tt>$::LOCKDIR</tt><br><br>\n"
+          . "Select the New Case button below to make one<br>\n";
+    }
+    else {
+
+        print "Select the case to open or create a new one<br>\n";
+
+        print_menu_tabs();
+
+        print "<table width=\"600\" background=\"$::YEL_PIX\" "
+          . " cellspacing=\"0\" cellpadding=\"2\" border=0>\n";
+
+        print "<form action=\"$::PROGNAME\" method=\"get\">\n"
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_OPEN_LOG\">\n"
+          . Args::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 ">" . Print::html_encode($c) . "</td>";
+
+            Caseman::read_case_config($c);
+
+            print "<td>$Caseman::cvals{'desc'}</td>"
+              . "<td align=center>"
+              . "<a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
+              . "view=$Caseman::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\" "
+          . "width=167 height=20 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=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_NEW\">\n"
+      . "<input type=\"image\" src=\"pict/menu_b_cnew.jpg\" "
+      . "width=167 height=20 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\" "
+      . "width=167 height=20 alt=\"Main Menu\" border=0>\n"
+      . "</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\" height=20 border=0>"
+      . "</a></td>"
+      . "<td>&nbsp;</td>\n"
+      . "</tr>\n"
+      . "</table>";
+
+    Print::print_html_footer();
+    return;
+}
+
+# Log that a given case was opened and then proceed to open a host
+sub case_open_log {
+    Print::log_session_info("Case $Args::args{'case'} opened");
+    Print::log_case_info("Case $Args::args{'case'} opened");
+    $Args::args{'view'} = $Args::enc_args{'view'} = $Caseman::HOST_OPEN;
+    host_open();
+}
+
+# Display Case Details
+sub case_details {
+
+    Print::print_html_header("Details of $Args::args{'case'}");
+
+    read_case_config();
+
+    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::args{'case'}</tt></td></tr>\n"
+      .
+
+      # Description
+      "  <tr><td align=\"right\"><b>Description:</b></td>"
+      . "<td align=\"left\"><tt>$Caseman::cvals{'desc'}</tt></td></tr>\n"
+      . "  <tr><td align=\"right\"><b>Created:</b></td>"
+      . "<td align=\"left\"><tt>$Caseman::cvals{'created'}</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>"
+          . Print::html_encode($i)
+          . "</tt></td></tr>\n";
+    }
+
+    print "</table>\n"
+      . "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&view=$Caseman::CASE_OPEN\">"
+      . "<img src=\"pict/menu_b_ok.jpg\" alt=\"Ok\" "
+      . "width=\"167\" height=20 border=\"0\"></a>";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+####################################################################
+# Host Functions
+
+# 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";
+    }
+}
+
+# Converts the original single image host config to the volume-based config
+sub convert_host_config {
+
+    return if ($::LIVE == 1);
+
+    my $host = Args::get_host();
+
+    Print::log_host_info("Converting host config files");
+    print STDERR "Converting host config file to new format\n";
+
+    # The file to convert
+    my $cfile = host_config_fname();
+    unless (open(FILE, $cfile)) {
+        Print::print_check_err("Error opening $cfile");
+    }
+
+    my $tmpcfile = "$::host_dir" . "host-convert.aut";
+    unless (open(FILE_TMP, ">>$tmpcfile")) {
+        Print::print_check_err("Error opening $tmpcfile");
+    }
+
+    my $img_cnt = 0;
+    my $vol_cnt = 0;
+    $img2vol{'qazwsxedc'} = ""; # stores the image path to partition / file name
+    $img2vol2{'qazwsxedc'} =
+      "";    # stores the image path to file name (no partitions)
+
+    while (<FILE>) {
+        if ((/^\#/) || (/^\s+$/)) {
+            print FILE_TMP $_;
+            next;
+        }
+
+        # 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;
+
+            # Add trailing / to original mount point if needed
+            if (($r !~ /.*?\/$/) && ($r !~ /.*?\\$/)) {
+                $r .= '/';
+            }
+            my $vnum = "vol" . $vol_cnt;
+            my $inum = "img" . $img_cnt;
+            $img2vol{$i}  = $vnum;
+            $img2vol2{$i} = $inum;
+
+            print FILE_TMP "image   $inum     raw     $i\n";
+            print FILE_TMP "part    $vnum     $inum   0   0   $t  $r\n";
+
+            $img_cnt++;
+            $vol_cnt++;
+        }
+
+        # swap
+        # swap		images/hda3.dd
+        elsif (/^swap\s+($::REG_IMG)\s*$/o) {
+            my $i = $1;
+
+            my $vnum = "vol" . $vol_cnt;
+            my $inum = "img" . $img_cnt;
+            $img2vol{$i}  = $vnum;
+            $img2vol2{$i} = $inum;
+
+            print FILE_TMP "image   $inum     raw     $i\n";
+            print FILE_TMP "part	$vnum   $inum 0   0   swap\n";
+            $img_cnt++;
+            $vol_cnt++;
+
+        }
+
+        # raw
+        # raw	images/hda3.dd
+        elsif (/^raw\s+($::REG_IMG)\s*$/o) {
+            my $i = $1;
+            $img2vol{$i}  = "vol" . $vol_cnt;
+            $img2vol2{$i} = "img" . $img_cnt;
+
+            print FILE_TMP "image   img" . $img_cnt . "     raw     $i\n";
+            print FILE_TMP "part    vol" . $vol_cnt . "   img" . $img_cnt
+              . " 0   0   raw\n";
+            $img_cnt++;
+            $vol_cnt++;
+        }
+
+        # entry for a strings or blkls file
+        #
+        # strings 	data/hda1.str		images/hda1.dd
+        elsif (/^strings\s+($::REG_IMG)\s+($::REG_IMG)$/o) {
+            my $i = $1;
+            my $o = $2;
+
+            if (exists $img2vol{$o}) {
+                my $vname = $img2vol{$o};
+                print FILE_TMP "strings vol" . $vol_cnt . "     $vname  $i\n";
+                $img2vol{$i}  = "vol" . $vol_cnt;
+                $img2vol2{$i} = "vol" . $vol_cnt;
+            }
+            else {
+                print STDERR "Error: Volume for strings $o not found<br>\n";
+            }
+            $vol_cnt++;
+        }
+
+        # entry for a strings or blkls file
+        #
+        # unistrings 	data/hda1.str		images/hda1.dd
+        elsif (/^unistrings\s+($::REG_IMG)\s+($::REG_IMG)$/o) {
+            my $i = $1;
+            my $o = $2;
+
+            if (exists $img2vol{$o}) {
+                my $vname = $img2vol{$o};
+                print FILE_TMP "unistrings    vol" . $vol_cnt
+                  . "   $vname     $i\n";
+                $img2vol{$i}  = "vol" . $vol_cnt;
+                $img2vol2{$i} = "vol" . $vol_cnt;
+            }
+            else {
+                print STDERR
+                  "Error: Volume for unicode strings $o not found<br>\n";
+            }
+            $vol_cnt++;
+        }
+
+        # blkls entry
+        # blkls data/image.blkls	[images/image.dd]
+        elsif (/^blkls\s+($::REG_IMG)\s*($::REG_IMG)$/o) {
+            my $i = $1;
+            my $o = $2;
+
+            $img2vol{$i} = "vol" . $vol_cnt;
+
+            if (exists $img2vol{$o}) {
+                my $vname = $img2vol{$o};
+                print FILE_TMP "blkls     vol" . $vol_cnt . "  $vname     $i\n";
+                $img2vol{$i}  = "vol" . $vol_cnt;
+                $img2vol2{$i} = "vol" . $vol_cnt;
+            }
+            else {
+                print STDERR "Error: Volume for blkls $o not found<br>\n";
+            }
+            $vol_cnt++;
+        }
+
+        # body data/body.txt
+        elsif (/^body\s+($::REG_IMG)$/o) {
+            my $i = $1;
+            print FILE_TMP "body    vol" . $vol_cnt . " $i\n";
+            $img2vol{$i}  = "vol" . $vol_cnt;
+            $img2vol2{$i} = "vol" . $vol_cnt;
+
+            $vol_cnt++;
+        }
+
+        # timeline data/timeline.txt
+        elsif (/^timeline\s+($::REG_IMG)$/o) {
+            my $i = $1;
+            print FILE_TMP "timeline    vol" . $vol_cnt . " $i\n";
+            $img2vol{$i}  = "vol" . $vol_cnt;
+            $img2vol2{$i} = "vol" . $vol_cnt;
+            $vol_cnt++;
+        }
+
+        # timezone XYZ
+        elsif (/^timezone\s+($::REG_ZONE_ARGS)$/o) {
+            print FILE_TMP "$_\n";
+        }
+
+        # timeskew XYZ
+        elsif (/^timeskew\s+($::REG_SKEW)$/o) {
+            print FILE_TMP "$_\n";
+        }
+
+        # desc XYZ
+        elsif (/^desc\s+(.*)$/) {
+            print FILE_TMP "$_\n";
+        }
+
+        # hash databases
+        elsif (/^alert_db\s+'(.*)'$/) {
+            print FILE_TMP "$_\n";
+        }
+        elsif (/^exclude_db\s+'(.*)'$/) {
+            print FILE_TMP "$_\n";
+        }
+        else {
+            my $msg =
+                "Error: invalid entry in $cfile:$." . "\n"
+              . "image	path	fs_type		mnt_point\n"
+              . "strings	path	orig_img\n"
+              . "blkls		path	[orig_img]\n"
+              . "body		path\n"
+              . "timeline	path\n"
+              . "timezone	TZ\n"
+              . "desc		DESCRIPTION\n";
+            Print::print_check_err($msg);
+        }
+    }
+
+    close(FILE);
+    close(FILE_TMP);
+    unless (rename $cfile, $cfile . ".bak") {
+        print STDERR "Error backing up original host config file\n";
+    }
+    unless (rename $tmpcfile, $cfile) {
+        print STDERR "Error renaming new host config file\n";
+    }
+
+    Notes::convert(\%img2vol);
+    Hash::convert(\%img2vol2);
+}
+
+# reads host config file and sets global hash values for images and other
+sub read_host_config {
+
+    if ($::LIVE == 1) {
+        %Caseman::mod2vol    = ();
+        %Caseman::vol2str    = ();
+        %Caseman::vol2uni    = ();
+        %Caseman::vol2blkls  = ();
+        $Caseman::tz         = "";
+        $Caseman::ts         = 0;
+        $Caseman::host_desc  = "";
+        $Caseman::exclude_db = "";
+        $Caseman::alert_db   = "";
+        return;
+    }
+
+    my $host = Args::get_host();
+
+    my $cfile = host_config_fname();
+  restart:
+    unless (open(FILE, $cfile)) {
+        Print::print_check_err("Error opening $cfile");
+    }
+
+    %Caseman::vol2mnt   = ();
+    %Caseman::vol2ftype = ();
+    %Caseman::vol2dtype = ();
+    %Caseman::vol2cat   = ();
+    %Caseman::mod2vol   = ();
+    %Caseman::vol2str   = ();
+    %Caseman::vol2uni   = ();
+    %Caseman::vol2blkls = ();
+    %Caseman::vol2par   = ();
+    %Caseman::vol2start = ();
+    %Caseman::vol2end   = ();
+    $Caseman::vol2path  = ();
+    $Caseman::vol2sname = ();
+
+    $Caseman::tz         = "";
+    $Caseman::ts         = 0;
+    $Caseman::host_desc  = "";
+    $Caseman::exclude_db = "";
+    $Caseman::alert_db   = "";
+
+    while (<FILE>) {
+        next if ((/^\#/) || (/^\s+$/));
+
+        # remove whitespace
+        s/^\s+//;
+        s/\s+$//;
+
+        # old file system image entry
+        #
+        # 'image	images/hda1.dd		openbsd		/usr
+        if (/^image\s+($::REG_IMG)\s+([\w\-]+)\s+([\w\-\_\.\/:\\]+)$/o) {
+
+            close(FILE);
+            convert_host_config();
+            goto restart;
+        }
+        elsif (
+            /^image\s+($::REG_INAME)\s+($::REG_IMGTYPE)\s+($::REG_IMG_CONFIG)$/o
+          )
+        {
+            my $me = $1;
+            my $t  = $2;
+            my $i  = $3;
+
+            unless ((-e "$::host_dir$i")
+                || ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
+            {
+                Print::print_check_err(
+                        "Error: image $i in ${host}.host:$. not found: "
+                      . "$::host_dir"
+                      . "$i \nEdit the config file and refresh your browser\n"
+                      . "(Or your version of Perl does not support large files)"
+                );
+            }
+
+            if (exists $Caseman::vol2path{$me}) {
+                $Caseman::vol2path{$me} .= " \'$::host_dir" . "$i\'";
+            }
+            else {
+                $Caseman::vol2path{$me}  = "\'$::host_dir" . "$i\'";
+                $Caseman::vol2sname{$me} = $i;
+                $Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
+
+                $Caseman::vol2par{$me}   = "";
+                $Caseman::vol2cat{$me}   = "image";
+                $Caseman::vol2itype{$me} = $t;
+                $Caseman::vol2ftype{$me} = "";
+
+                $Caseman::vol2start{$me} = 0;
+                $Caseman::vol2end{$me}   = 0;
+            }
+        }
+        elsif (
+/^part\s+($::REG_VNAME)\s+($::REG_INAME)\s+(\d+)\s+(\d+)\s+($::REG_FTYPE)\s*([\w\-\_\.\/:\\]+)?$/o
+          )
+        {
+            my $par = $2;
+            my $me  = $1;
+            my $s   = $3;
+            my $e   = $4;
+            my $t   = $5;
+            my $r   = $6;    # Not defined for swap and raw
+
+            unless (exists $Fs::addr_unit{$t}) {
+                Print::print_check_err(
+                        "Error: unknown type: $t in host config: $."
+                      . "\nEdit the file and refresh your browser");
+            }
+
+            if (exists $Caseman::vol2itype{$par}) {
+                $Caseman::vol2itype{$me} = $Caseman::vol2itype{$par};
+            }
+            else {
+                Print::print_check_err(
+"Error: Image $par for partition $me was not found in config: $."
+                      . "\nEdit the file and refresh your browser");
+            }
+
+            $Caseman::vol2ftype{$me} = $t;
+            $Caseman::vol2cat{$me}   = "part";
+            $Caseman::vol2start{$me} = $s;
+            $Caseman::vol2end{$me}   = $e;
+
+            # Add trailing / to original mount point if needed
+            if ((defined $r) && ($r !~ /.*?\/$/) && ($r !~ /.*?\\$/)) {
+                $r .= '/';
+            }
+            $Caseman::vol2mnt{$me}   = $r;
+            $Caseman::vol2par{$me}   = $par;
+            $Caseman::vol2path{$me}  = $Caseman::vol2path{$par};
+            $Caseman::vol2sname{$me} =
+              $Caseman::vol2sname{$par} . "-" . $s . "-" . $e;
+        }
+        elsif (/^disk\s+($::REG_VNAME)\s+($::REG_INAME)\s+($::REG_FTYPE)?$/o) {
+            my $par = $2;
+            my $me  = $1;
+            my $t   = $3;
+
+            unless (exists $Vs::type{$t}) {
+                Print::print_check_err(
+                    "Error: unknown volume system type: $t in host config: $."
+                      . "\nEdit the file and refresh your browser");
+            }
+
+            if (exists $Caseman::vol2itype{$par}) {
+                $Caseman::vol2itype{$me} = $Caseman::vol2itype{$par};
+            }
+            else {
+                Print::print_check_err(
+"Error: Image $par for disk $me was not found in config: $.\n"
+                      . "Edit the file and refresh your browser");
+            }
+
+            $Caseman::vol2ftype{$me} = "raw";
+            $Caseman::vol2dtype{$me} = $t;
+            $Caseman::vol2cat{$me}   = "disk";
+            $Caseman::vol2start{$me} = 0;
+            $Caseman::vol2end{$me}   = 0;
+            $Caseman::vol2mnt{$me}   = "";
+            $Caseman::vol2par{$me}   = $par;
+            $Caseman::vol2path{$me}  = $Caseman::vol2path{$par};
+            $Caseman::vol2sname{$me} = $Caseman::vol2sname{$par} . "-disk";
+        }
+
+        # entry for a strings or blkls file
+        #
+        # strings 	data/hda1.str		volX
+        elsif (/^strings\s+($::REG_VNAME)\s+($::REG_VNAME)\s+($::REG_IMG)$/o) {
+            my $i   = $3;
+            my $par = $2;
+            my $me  = $1;
+
+            unless ((-e "$::host_dir$i")
+                || ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
+            {
+                Print::print_check_err("Error: strings file not found: "
+                      . "$::host_dir$i\nEdit host config in $::host_dir and refresh your browser"
+                );
+            }
+
+            unless (exists $Caseman::vol2cat{$par}) {
+                Print::print_check_err(
+"Error: Volume $par for strings $me was not found in config: $."
+                      . "\nEdit the file and refresh your browser");
+            }
+
+            $Caseman::vol2ftype{$me} = "strings";
+            $Caseman::vol2cat{$me}   = "mod";
+            $Caseman::vol2itype{$me} = "raw";
+            $Caseman::mod2vol{$me}   = $par;
+            $Caseman::vol2str{$par}  = $me;
+            $Caseman::vol2par{$me}   = $par;
+            $Caseman::vol2path{$me}  = "\'$::host_dir" . "$i\'";
+            $Caseman::vol2start{$me} = 0;
+            $Caseman::vol2end{$me}   = 0;
+            $Caseman::vol2sname{$me} = $i;
+            $Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
+
+        }
+
+        # entry for a strings or blkls file
+        #
+        # unistrings 	data/hda1.str		volX
+        elsif (/^unistrings\s+($::REG_VNAME)\s+($::REG_VNAME)\s+($::REG_IMG)$/o)
+        {
+            my $i   = $3;
+            my $par = $2;
+            my $me  = $1;
+
+            unless ((-e "$::host_dir$i")
+                || ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
+            {
+                Print::print_check_err("Error: Unicode strings file not found: "
+                      . "$::host_dir$i\nEdit host config in $::host_dir and refresh your browser"
+                );
+            }
+
+            unless (exists $Caseman::vol2cat{$par}) {
+                Print::print_check_err(
+"Error: Volume $par for unistrings $me was not found in config: $."
+                      . "\nEdit the file and refresh your browser");
+            }
+
+            $Caseman::vol2ftype{$me} = "strings";
+            $Caseman::vol2cat{$me}   = "mod";
+            $Caseman::vol2itype{$me} = "raw";
+            $Caseman::mod2vol{$me}   = $par;
+            $Caseman::vol2uni{$par}  = $me;
+            $Caseman::vol2par{$me}   = $par;
+            $Caseman::vol2path{$me}  = "\'$::host_dir" . "$i\'";
+            $Caseman::vol2start{$me} = 0;
+            $Caseman::vol2end{$me}   = 0;
+            $Caseman::vol2sname{$me} = $i;
+            $Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
+        }
+
+        # blkls entry
+        # blkls themname	myname
+        elsif ((/^blkls\s+($::REG_VNAME)\s+($::REG_VNAME)\s+($::REG_IMG)$/o) || 
+          (/^dls\s+($::REG_VNAME)\s+($::REG_VNAME)\s+($::REG_IMG)$/o)) {
+            my $i   = $3;
+            my $par = $2;
+            my $me  = $1;
+
+            unless (
+                (-e "$::host_dir$i")
+                || (   (-l "$::host_dir$i")
+                    && (-e readlink "$::host_dir$i"))
+              )
+            {
+                Print::print_check_err("Error: blkls file not found: "
+                      . "$::host_dir$i \nEdit host config in $::host_dir and refresh your browser"
+                );
+            }
+
+            unless (exists $Caseman::vol2cat{$par}) {
+                Print::print_check_err(
+"Error: Volume $par for blkls $me was not found in config: $."
+                      . "\nEdit the file and refresh your browser");
+            }
+
+            $Caseman::vol2ftype{$me}  = "blkls";
+            $Caseman::vol2cat{$me}    = "mod";
+            $Caseman::vol2itype{$me}  = "raw";
+            $Caseman::vol2mnt{$me}    = "";
+            $Caseman::vol2par{$me}    = $par;
+            $Caseman::mod2vol{$me}    = $par;
+            $Caseman::vol2blkls{$par} = $me;
+            $Caseman::vol2path{$me}   = "\'$::host_dir" . "$i\'";
+            $Caseman::vol2start{$me}  = 0;
+            $Caseman::vol2end{$me}    = 0;
+            $Caseman::vol2sname{$me}  = $i;
+            $Caseman::vol2sname{$me}  = $1 if ($i =~ /\/($::REG_FILE)$/);
+
+        }
+
+        # body data/body.txt
+        elsif (/^body\s+($::REG_VNAME)\s+($::REG_IMG)$/o) {
+            my $me = $1;
+            my $i  = $2;
+
+            unless ((-e "$::host_dir$i")
+                || ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
+            {
+                Print::print_check_err("Error: body file not found: "
+                      . "$::host_dir$i <br>Edit host config in $::host_dir and refresh your browser"
+                );
+            }
+
+            $Caseman::vol2cat{$me}   = "timeline";
+            $Caseman::vol2ftype{$me} = "body";
+            $Caseman::vol2itype{$me} = "raw";
+            $Caseman::vol2path{$me}  = "\'$::host_dir" . "$i\'";
+            $Caseman::vol2start{$me} = 0;
+            $Caseman::vol2end{$me}   = 0;
+            $Caseman::vol2sname{$me} = $i;
+            $Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
+        }
+
+        # timeline data/timeline.txt
+        elsif (/^timeline\s+($::REG_VNAME)\s+($::REG_IMG)$/o) {
+            my $me = $1;
+            my $i  = $2;
+
+            unless ((-e "$::host_dir$i")
+                || ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
+            {
+                Print::print_check_err("Error: timeline file not found: "
+                      . "$::host_dir$i \nEdit host config in $::host_dir and refresh your browser"
+                );
+            }
+
+            $Caseman::vol2cat{$me}   = "timeline";
+            $Caseman::vol2ftype{$me} = "timeline";
+            $Caseman::vol2itype{$me} = "raw";
+
+# We do not add the quotes to the path for timeline because it is opened only by the Perl code and it doesn't like the quotes
+            $Caseman::vol2path{$me}  = "$::host_dir" . "$i";
+            $Caseman::vol2start{$me} = 0;
+            $Caseman::vol2end{$me}   = 0;
+            $Caseman::vol2sname{$me} = $i;
+            $Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
+
+        }
+
+        # timezone XYZ
+        elsif (/^timezone\s+($::REG_ZONE_ARGS)$/o) {
+            $Caseman::tz = "\'$1\'";
+        }
+
+        # timeskew XYZ
+        elsif (/^timeskew\s+($::REG_SKEW)$/o) {
+            $Caseman::ts = "\'$1\'";
+        }
+
+        # desc XYZ
+        elsif (/^desc\s+(.*)$/) {
+            $Caseman::host_desc = Print::html_encode($1);
+        }
+
+        # hash databases
+        elsif (/^alert_db\s+'($::REG_HASHDB)'$/) {
+            $Caseman::alert_db = "$1";
+        }
+        elsif (/^exclude_db\s+'($::REG_HASHDB)'$/) {
+            $Caseman::exclude_db = "$1";
+        }
+        else {
+            my $msg = "Error: invalid entry in $cfile:$." . "\n" . "$_\n";
+            Print::print_check_err($msg);
+        }
+    }
+    close(FILE);
+}
+
+# Add a new image entry to the host config and return its id
+sub add_img_host_config {
+    my $type  = shift;
+    my $other = shift;
+    my $id    = shift;
+
+    my $read  = host_config_fname();
+    my $write = $read . "-" . rand();
+
+    unless (open(READ, "<$read")) {
+        Print::print_check_err("Error opening $read");
+    }
+
+    unless (open(WRITE, ">$write")) {
+        Print::print_check_err("Error opening $write");
+    }
+
+    my $maxcnt = 0;
+
+    while (<READ>) {
+        s/^\s+//;
+        s/\s+$//;
+        if (/^\w+\s+img(\d+)\s+.*$/) {
+            $maxcnt = $1 if ($1 > $maxcnt);
+        }
+        print WRITE "$_\n";
+    }
+    $maxcnt++;
+    if ($id eq "") {
+        $id = "img" . $maxcnt;
+    }
+    print WRITE "$type  $id  $other\n";
+
+    Print::log_host_info("Image added: $type $id $other");
+
+    close(READ);
+    close(WRITE);
+    unless (rename $write, $read) {
+        print STDERR "Error renaming temp host config file\n";
+    }
+
+    return $id;
+}
+
+# Add a new volume entry to the host config and return its id
+sub add_vol_host_config {
+    my $type  = shift;
+    my $other = shift;
+
+    my $read  = host_config_fname();
+    my $write = $read . "-" . rand();
+
+    unless (open(READ, "<$read")) {
+        Print::print_check_err("Error opening $read");
+    }
+
+    unless (open(WRITE, ">$write")) {
+        Print::print_check_err("Error opening $write");
+    }
+
+    # We want to find the max count ... not just the unused
+    # ones because we could end up reusing one and that could
+    # mess up the notes
+    my $maxcnt = 0;
+
+    while (<READ>) {
+        s/^\s+//;
+        s/\s+$//;
+        if (/^\w+\s+vol(\d+)\s+.*$/) {
+            $maxcnt = $1 if ($1 > $maxcnt);
+        }
+        print WRITE "$_\n";
+    }
+    $maxcnt++;
+    print WRITE "$type  vol" . $maxcnt . "  $other\n";
+    Print::log_host_info("Volume added: $type  vol" . $maxcnt . " $other");
+
+    close(READ);
+    close(WRITE);
+    unless (rename $write, $read) {
+        print STDERR "Error renaming temp host config file\n";
+    }
+
+    return "vol" . $maxcnt;
+}
+
+# Delete anentry from the host config
+# DOES NOT WORK RIGHT NOW
+sub del_host_config_BLAH {
+    return;
+    my $type  = shift;
+    my $other = shift;
+
+    my $read  = host_config_fname();
+    my $write = $read . "-" . rand();
+
+    unless (open(READ, "<$read")) {
+        Print::print_check_err("Error opening $read");
+    }
+
+    unless (open(WRITE, ">$write")) {
+        Print::print_check_err("Error opening $write");
+    }
+
+    while (<READ>) {
+        s/^\s+//;
+        s/\s+$//;
+        print WRITE "$_\n"
+          unless ((/^(\w+)\s+($::REG_IMG)/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);
+    unless (rename $write, $read) {
+        print STDERR "Error renaming temp host config file\n";
+    }
+
+    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 $vol = shift;
+    my $md5 = shift;
+    $md5 =~ tr/[a-f]/[A-F]/;
+
+    my $read  = "$::host_dir/md5.txt";
+    my $write = $read . "-" . rand();
+
+    unless (open(WRITE, ">$write")) {
+        Print::print_check_err("Error opening $write");
+    }
+
+    if (-e "$read") {
+        unless (open(READ, "<$read")) {
+            Print::print_check_err("Error opening $read");
+        }
+
+        while (<READ>) {
+            s/^\s+//;
+            s/\s+$//;
+            print WRITE "$_\n"
+              unless ((/^$::REG_MD5\s+($::REG_VNAME)/o) && ($1 eq $vol));
+        }
+        close(READ);
+    }
+
+    print WRITE "$md5   $vol\n" if ($md5 ne "");
+
+    close(WRITE);
+
+    unless (rename $write, $read) {
+        print STDERR "Error renaming temp MD5 hash file\n";
+    }
+    return;
+}
+
+sub host_add {
+    Print::print_html_header("Add A New Host To $Args::args{'case'}");
+
+    print "<b>Case: </b> $Args::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=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_ADD_DOIT\">\n"
+      . Args::make_hidden()
+      . "<tr><td colspan=\"2\">&nbsp;</td></tr>"
+      .
+
+      # Host name
+"<tr><td align=\"left\" colspan=2>1.  <b>Host Name:</b>  The name of the computer being investigated.  It can contain only letters, numbers, and symbols.</td></tr>"
+      . "<tr><td align=\"left\">&nbsp;&nbsp;&nbsp;</td>"
+      . "<td align=\"left\"><input type=\"text\" name=\"host\" size=32 maxlength=32 value=\"host1\"></td></tr>\n"
+      .
+
+      # Description
+"<tr><td align=\"left\" colspan=2>2.  <b>Description:</b>  An optional one-line description or note about this computer.</td></tr>"
+      . "<tr><td align=\"left\">&nbsp;&nbsp;&nbsp;</td>"
+      . "<td align=\"left\">"
+      . "<input type=\"text\" name=\"desc\" size=32 maxlength=32></td></tr>\n"
+      .
+
+      # Empty line
+      "<tr><td colspan=\"2\">&nbsp;</td></tr>" .
+
+      # Timezone
+"<tr><td align=\"left\" colspan=2>3.  <b>Time zone:</b> An optional timezone value (i.e. EST5EDT).  If not given, it defaults to the local setting.  A list of time zones can be found in the help files.</td></tr>"
+      . "<tr><td align=\"left\">&nbsp;&nbsp;&nbsp;</td>"
+      . "<td align=\"left\">"
+      . "<input type=\"text\" name=\"tz\" size=16 maxlength=64></td></tr>\n"
+      .
+
+      # Timeskew
+"<tr><td align=\"left\" colspan=2>4.  <b>Timeskew Adjustment:</b> An optional value to describe how many seconds this computer's clock was out of sync.  For example, if the computer was 10 seconds fast, then enter -10 to compensate.</td></tr>"
+      . "<tr><td align=\"left\">&nbsp;&nbsp;&nbsp;</td>"
+      . "<td align=\"left\">"
+      . "<input type=\"text\" name=\"ts\" size=8 maxlength=16 value=\"0\">"
+      . "</td></tr>\n"
+      .
+
+      # Spacer
+      "<tr><td colspan=\"2\">&nbsp;</td></tr>" .
+
+      # Alert
+"<tr><td align=\"left\" colspan=2>5.  <b>Path of Alert Hash Database:</b> An optional hash database of known bad files.</td></tr>"
+      . "<tr><td align=\"left\">&nbsp;&nbsp;&nbsp;</td>"
+      . "<td align=\"left\">"
+      . "<input type=\"text\" name=\"alert_db\" size=32 maxlength=512>"
+      . "</td></tr>\n"
+      .
+
+      # Ignore
+"<tr><td align=\"left\" colspan=2>6.  <b>Path of Ignore Hash Database:</b> An optional hash database of known good files.</td></tr>"
+      . "<tr><td align=\"left\">&nbsp;&nbsp;&nbsp;</td>"
+      . "<td align=\"left\">"
+      . "<input type=\"text\" name=\"exclude_db\" size=32 maxlength=512>"
+      . "</td></tr>\n"
+      .
+
+      # Spacer
+      "<tr><td colspan=\"2\">&nbsp;</td></tr>" . "</table>\n";
+
+    if (exists $Args::args{'inv'}) {
+        print
+          "<input type=\"hidden\" name=\"inv\" value=\"$Args::args{'inv'}\">\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\" "
+      . "width=167 height=20 alt=\"Add Host\" border=0>\n"
+      . "</form></td>\n"
+      .
+
+      # Cancel Button
+      "<td align=center>"
+      . "<form action=\"$::PROGNAME\" method=\"get\">\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN\">\n"
+      . "<input type=\"hidden\" name=\"case\" value=\"$Args::args{'case'}\">\n"
+      . "<input type=\"image\" src=\"pict/menu_b_cancel.jpg\" "
+      . "alt=\"Cancel\" width=\"167\" height=20 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\" height=20 border=0></a>"
+      . "</td></tr>\n"
+      . "</table>";
+
+    Print::print_html_footer();
+
+    return 0;
+}
+
+# Make the directories and config files for a host
+sub host_add_doit {
+    Args::check_tz()
+      if ((exists $Args::args{'tz'}) && ($Args::args{'tz'} ne ""));
+    Args::check_ts();
+    Print::print_html_header(
+        "Adding Host $Args::args{'host'} to $Args::args{'case'}");
+
+    print "<h3>Adding host: <tt>$Args::args{'host'}</tt> to "
+      . "case <tt>$Args::args{'case'}</tt></h3>\n";
+
+    # Do some sanity checks before we start making the directories and such
+    if (   (exists $Args::args{'alert_db'})
+        && ($Args::args{'alert_db'} ne ""))
+    {
+
+        unless ($Args::args{'alert_db'} =~ /^$::REG_HASHDB$/o) {
+            print "Invalid Alert Database path\n"
+              . "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
+              . "view=$Caseman::HOST_ADD&case=$Args::args{'case'}\">"
+              . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
+              . "width=\"43\" height=20 border=\"0\"></a>\n";
+            return 1;
+        }
+
+        unless (-e "$Args::args{'alert_db'}") {
+            print "Alert Database Not Found: $Args::args{'alert_db'}"
+              . "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
+              . "view=$Caseman::HOST_ADD&case=$Args::args{'case'}\">"
+              . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
+              . "width=\"43\" height=20 border=\"0\"></a>\n";
+            return 1;
+        }
+    }
+
+    if (   (exists $Args::args{'exclude_db'})
+        && ($Args::args{'exclude_db'} ne ""))
+    {
+        unless ($Args::args{'exclude_db'} =~ /^$::REG_HASHDB$/o) {
+            print "Invalid Exclude Database path\n"
+              . "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
+              . "view=$Caseman::HOST_ADD&case=$Args::args{'case'}\">"
+              . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
+              . "width=\"43\" height=20 border=\"0\"></a>\n";
+            return 1;
+        }
+
+        unless (-e "$Args::args{'exclude_db'}") {
+            print "Exclude Database Not Found: $Args::args{'exclude_db'}"
+              . "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
+              . "view=$Caseman::HOST_ADD&case=$Args::args{'case'}\">"
+              . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
+              . "width=\"43\" height=20 border=\"0\"></a>\n";
+            return 1;
+        }
+    }
+
+    # Make the directory
+    if (-d "$::host_dir") {
+
+        print "Error: $::host_dir already exists<br>"
+          . "Please remove the directory and its contents and try again"
+          . "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
+          . "view=$Caseman::HOST_OPEN&case=$Args::enc_args{'case'}\">"
+          . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
+          . "width=\"43\" height=20 border=\"0\"></a>\n";
+        Print::print_err("\n");
+    }
+    unless (mkdir "$::host_dir", $::MKDIR_MASK) {
+        Print::print_err("Error making directory $::host_dir: $!");
+    }
+
+    print "Host Directory (<tt>$::host_dir</tt>) created<p>\n";
+    Print::log_case_info("Host $Args::args{'host'} added to case");
+
+    # Images directory
+    unless (mkdir "$::host_dir" . "$::IMGDIR", $::MKDIR_MASK) {
+        rmdir "$::host_dir";
+        Print::print_err("Error making $::host_dir" . "$::IMGDIR");
+    }
+
+    # Output Directory
+    unless (mkdir "$::host_dir" . "$::DATADIR", $::MKDIR_MASK) {
+        rmdir "$::host_dir" . "$::IMGDIR";
+        rmdir "$::host_dir";
+        Print::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::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::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::print_err("Error making $::host_dir" . "mnt");
+    }
+
+    Print::log_host_info(
+        "Host $Args::args{'host'} added to case $Args::args{'case'}");
+
+    # Create config file
+    my $fname = Caseman::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::args{'case'}		Host: $Args::args{'host'}\n"
+      . "# Created: "
+      . localtime() . "\n\n";
+
+    if ((exists $Args::args{'desc'}) && ($Args::args{'desc'} ne "")) {
+        Print::print_err(
+            "Invalid Description\n" . "Use the browser's back button to fix")
+          if ($Args::args{'desc'} =~ /\n/);
+
+        print HOST_CONFIG "desc $Args::args{'desc'}\n";
+    }
+
+    print HOST_CONFIG "timezone  " . Args::get_tz() . "\n"
+      if ((exists $Args::args{'tz'}) && ($Args::args{'tz'} ne ""));
+    print HOST_CONFIG "timeskew  " . Args::get_ts() . "\n";
+
+    if (   (exists $Args::args{'alert_db'})
+        && ($Args::args{'alert_db'} ne ""))
+    {
+
+        # Index it if it is not
+        unless (-e "$Args::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::args{'alert_db'});
+            print "<hr>\n";
+        }
+
+        # only print it if it was successful
+        print HOST_CONFIG "alert_db \'$Args::args{'alert_db'}\'\n"
+          if (-e "$Args::args{'alert_db'}-md5.idx");
+    }
+
+    if (   (exists $Args::args{'exclude_db'})
+        && ($Args::args{'exclude_db'} ne ""))
+    {
+
+        # Index it if it is not
+        unless (-e "$Args::args{'exclude_db'}-md5.idx") {
+            print
+"Exclude Database has not been indexed - it will be as an md5sum file<br>\n";
+
+            print "<hr>\n";
+            Hash::index_md5sum($Args::args{'exclude_db'});
+            print "<hr>\n";
+        }
+
+        # only print it if it was successful
+        print HOST_CONFIG "exclude_db \'$Args::args{'exclude_db'}\'\n"
+          if (-e "$Args::args{'exclude_db'}-md5.idx");
+    }
+
+    close HOST_CONFIG;
+
+    print "Configuration file (<tt>$fname</tt>) created<br><br>\n";
+
+    print "We must now import an image file for this host\n";
+
+    print "<br><br><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
+      . "view=$Caseman::HOST_OPEN_LOG&$Args::baseargs\">"
+      . "<img src=\"pict/menu_b_inew.jpg\" alt=\"Add Image\" "
+      . " height=20 border=\"0\"></a>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# Open a host in the given case
+sub host_open {
+    Print::print_html_header("Open Host In $Args::args{'case'}");
+
+    # 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 = Caseman::host_config_fname($h);
+        push @hosts, $h
+          if ((-d "$::case_dir" . "$h") && (-e "$hfile"));
+    }
+    closedir HOSTS;
+
+    print "<b>Case:</b> $Args::args{'case'}<br><br>\n";
+
+    print "<center>";
+
+    if (scalar @hosts == 0) {
+        print "No hosts have been added to the case yet"
+          . "<br><br>Select the Add Host button below to create one.<br>\n";
+    }
+    else {
+
+        print "Select the host to open or create a new one<br>\n";
+
+        print_menu_tabs();
+
+        print "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\" "
+          . "background=\"$::YEL_PIX\" border=0>\n";
+
+        print "<form action=\"$::PROGNAME\" method=\"get\">\n"
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN_LOG\">\n"
+          . Args::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 "> " . Print::html_encode($h) . " </td>";
+
+            my $fname = Caseman::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 = Print::html_encode($1);
+                    last;
+                }
+            }
+            close CONFIG;
+
+            print "<td align=left>$desc</td>"
+              . "<td align=center>"
+              . "<a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
+              . "view=$Caseman::HOST_DETAILS&$Args::baseargs&"
+              . "host=$h\">details</a></td></tr>\n";
+        }
+        print "</table>\n";
+
+        # Display pulldown of investigators
+        my @invs = read_invest();
+        if (scalar @invs == 0) {
+            print "<input type=\"hidden\" name=\"inv\" value=\"unknown\">\n";
+        }
+        else {
+            print "<br>Investigator (for reports only): ";
+            my $cur_inv = "";
+            $cur_inv = $Args::args{'inv'} if (exists $Args::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 ">" . Print::html_encode($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\" height=20 border=0>\n"
+          . "</form>\n</td>\n";
+    }
+
+    # Add Host
+    print "<td align=center>"
+      . "<form action=\"$::PROGNAME\" method=\"get\">\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_ADD\">\n"
+      . "<input type=\"hidden\" name=\"case\" value=\"$Args::args{'case'}\">\n"
+      . "<input type=\"image\" src=\"pict/menu_b_hnew.jpg\" "
+      . "alt=\"Add Host\" width=\"176\" height=20 border=0>\n"
+      . "</form></td>"
+      .
+
+      # Close Button
+      "<td align=center>"
+      . "<form action=\"$::PROGNAME\" method=\"get\">\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_OPEN\">\n"
+      . "<input type=\"image\" src=\"pict/menu_b_ccls.jpg\" "
+      . "alt=\"Close Case\" width=\"176\" height=20 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\" height=20 border=0>"
+      . "</a></td><td>&nbsp;</td></tr>\n"
+      . "</table>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# Log that a given host was opened and then proceed to open an image
+sub host_open_log {
+    unless ((exists $Args::args{'inv'}) && ($Args::args{'inv'} ne "")) {
+        my @invs = read_invest();
+        if (scalar @invs == 0) {
+            $Args::args{'inv'} = $Args::enc_args{'inv'} = 'unknown';
+        }
+        else {
+            Print::print_html_header("Missing Investigator");
+            print "<br>An investigator must be selected<p>\n"
+              . "<form action=\"$::PROGNAME\" method=\"get\">\n"
+              . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+              . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN_LOG\">\n"
+              . Args::make_hidden();
+
+            print "Select one of the following:";
+            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\" "
+              . "width=43 height=20 border=\"0\">\n"
+              . "</form>\n";
+
+            Print::print_html_footer();
+            return 0;
+        }
+    }
+
+    Args::check_inv();
+    Print::log_case_info(
+        "Host $Args::args{'host'} opened by $Args::args{'inv'}");
+    Print::log_host_info(
+        "Host $Args::args{'host'} opened by $Args::args{'inv'}");
+    Print::log_host_inv("Host $Args::args{'host'} opened");
+
+    $Args::args{'view'} = $Args::enc_args{'view'} = $Caseman::VOL_OPEN;
+    vol_open();
+}
+
+# Provide details about the configuration of a host.  This window is
+# a link from the HOST_OPEN window
+sub host_details {
+    Print::print_html_header(
+        "Details of $Args::args{'case'}:$Args::args{'host'}");
+
+    print "<b>Case: </b>$Args::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::args{'host'}</tt></td></tr>\n"
+      .
+
+      # Description
+      "<tr><td align=\"right\"><b>Description:</b></td>"
+      . "<td align=\"left\"><tt>"
+      . (($Caseman::host_desc ne "") ? $Caseman::host_desc : "&nbsp;")
+      . "</tt></td></tr>\n"
+      .
+
+      # Timezone
+      "<tr><td align=\"right\"><b>Time zone: </b></td>"
+      . "<td align=\"left\"><tt>$Caseman::tz</tt></td></tr>\n"
+      .
+
+      # Timeskew
+      "<tr><td align=\"right\"><b>Timeskew:</b></td>"
+      . "<td align=\"left\"><tt>$Caseman::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>"
+      . Print::html_encode($::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>"
+      . (($Caseman::alert_db ne "")
+        ? Print::html_encode($Caseman::alert_db)
+        : "&nbsp;")
+      . "</tt></td></tr>\n"
+      .
+
+      # Exclude Database
+      "<tr><td align=\"right\"><b>Exclude Hash Database:</b></td>"
+      . "<td align=\"left\"><tt>"
+      . (($Caseman::exclude_db ne "")
+        ? Print::html_encode($Caseman::exclude_db)
+        : "&nbsp;")
+      . "</tt></td></tr>\n"
+      . "</table>\n";
+
+    # Final Button
+    print "<br><br><form action=\"$::PROGNAME\" method=\"get\">\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN\">\n"
+      . Args::make_hidden()
+      . "<input type=\"image\" src=\"pict/menu_b_ok.jpg\" "
+      . "alt=\"Ok\" width=\"167\" height=20 border=\"0\">\n</form>";
+
+    Print::print_html_footer();
+
+    return;
+}
+
+# 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, $1
+          if (/^($::REG_INVESTIG)$/o);
+    }
+    close(INVES);
+    sort { lc($a) cmp lc($b) } @investigs;
+}
+
+# File of investigators name in list
+sub investig_fname {
+    return "$::case_dir" . "investigators.txt";
+}
+
+####################################################################
+# Image Functions
+
+# Types of modes for fname (i.e. can we overwrite it if it exists)
+my $FNAME_MODE_INIT = 0;
+my $FNAME_MODE_OVER = 1;
+
+my $MD5_NOTHING = 1;
+my $MD5_CALC    = 2;
+my $MD5_ADD     = 3;
+
+my $IMG_ADD_SYM  = 1;
+my $IMG_ADD_COPY = 2;
+my $IMG_ADD_MOVE = 3;
+
+# Open an image that has been configured
+sub vol_open {
+    Print::print_html_header(
+        "Open Image In $Args::args{'case'}:$Args::args{'host'}");
+
+    print "<b>Case:</b> $Args::args{'case'}<br>\n";
+    print "<b>Host:</b> $Args::args{'host'}<br>\n";
+    print "<center>\n";
+
+    # the images have been loaded from reading the host config file in
+    # autopsy_main
+    if (scalar(keys %Caseman::vol2ftype) == 0) {
+        print "No images have been added to this host yet<br><br>\n"
+          . "Select the Add Image File button below to add one\n";
+        goto EGRESS;
+    }
+
+    if ($::LIVE == 1) {
+        print "Select a volume to analyze.<br>\n";
+    }
+    else {
+        print "Select a volume to analyze or add a new image file.<br>\n";
+    }
+
+    print_menu_tabs();
+
+    print "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\" "
+      . "background=\"$::YEL_PIX\" border=0>\n";
+
+    # We want to sort, so rearrange the hash
+    my %mnt2vol;
+    my %par2disk;
+
+    # Cycle through each image we read from the host config
+    foreach my $i (keys %Caseman::vol2cat) {
+        if ($Caseman::vol2cat{$i} eq "disk") {
+            $mnt2vol{"1disk--AUTOPSY--$i"} = $i;
+        }
+        elsif ($Caseman::vol2cat{$i} eq "part") {
+            if (   ($Caseman::vol2ftype{$i} eq "raw")
+                || ($Caseman::vol2ftype{$i} eq "swap"))
+            {
+                $mnt2vol{"2$Caseman::vol2ftype{$i}--AUTOPSY--$i"} = $i;
+            }
+            else {
+                $mnt2vol{"2$Caseman::vol2mnt{$i}--AUTOPSY--$i"} = $i;
+            }
+        }
+    }
+
+    # sort via parent volume, then starting location,
+    # and then mount point (which includes the name)
+    my @mnt = sort {
+        ($Caseman::vol2par{$mnt2vol{$a}} cmp $Caseman::vol2par{$mnt2vol{$b}})
+          or ($Caseman::vol2start{$mnt2vol{$a}} <=>
+            $Caseman::vol2start{$mnt2vol{$b}})
+          or (lc($a) cmp lc($b))
+    } keys %mnt2vol;
+
+    # It is possible to have only the blkls 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_blkls;
+
+    # cycle through each image and check its type and original
+    foreach my $k (keys %Caseman::vol2ftype) {
+        if (   ($Caseman::vol2ftype{$k} eq "blkls")
+            && (!exists $Caseman::mod2vol{$k}))
+        {
+            push @orphan_blkls, $k;
+        }
+    }
+
+    print "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_OPEN_LOG\">\n"
+      . Args::make_hidden()
+
+      . "<tr><th>&nbsp;</th>"
+      . "<th align=left>mount</th>"
+      . "<th align=left>name</th>"
+      .    # vol name
+      "<th align=left>fs type</th></tr>\n";
+
+    my $prev_par = "";
+
+    for (my $i = 0; $i <= $#mnt; $i++) {
+        my $vol = $mnt2vol{$mnt[$i]};
+
+        if ($Caseman::vol2par{$vol} ne $prev_par) {
+            print "<tr><td colspan=5><hr></td></tr>\n" if ($i != 0);
+            $prev_par = $Caseman::vol2par{$vol};
+        }
+
+        # 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] =~ /^\d(.*?)--AUTOPSY--$::REG_VNAME$/o);
+        print "<tr>" . "<td><input type=\"radio\" name=\"vol\" value=$vol";
+        print " CHECKED" if ($i == 0);
+        print "></td>"
+          . "<td><tt>"
+          . Print::html_encode($mnt[$i])
+          . "</tt></td>";
+
+        # image name and ftype
+        print
+"<td><tt>$Caseman::vol2sname{$vol}</tt></td><td>$Caseman::vol2ftype{$vol}</td>";
+        if ($::LIVE == 0) {
+            print "<td align=center><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
+              . "view=$Caseman::VOL_DETAILS&$Args::baseargs&"
+              . "vol=$vol\">details</a></td>"
+              . "</tr>\n";
+        }
+        else {
+            print "<td>&nbsp;</td></tr>\n";
+        }
+    }
+
+    # If we are done with the regular images and have some orphan
+    # blkls images, print them
+    my @sort = sort @orphan_blkls;
+    for (my $i = 0; $i <= $#sort; $i++) {
+        print
+"<tr><td>&nbsp;</td><td>&nbsp;</td><td>(<input type=\"radio\" name=\"vol\" "
+          . "value=$sort[$i]";
+        print " CHECKED" if ($#mnt == 0);
+        print "> unalloc)</td><td><tt>"
+          . Print::html_encode($Caseman::vol2sname{$sort[$i]})
+          . "</tt></td><td>"
+          . Print::html_encode($Caseman::vol2ftype{$sort[$i]})
+          . "</td></tr>\n";
+    }
+
+    # Begin Button
+    print "</table>\n";
+
+  EGRESS:
+
+    print "<br><br>"
+      . "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">\n";
+
+    # Ok Button
+    if (scalar(keys %Caseman::vol2ftype) == 0) {
+        print "<tr><td width=200>&nbsp;</td>\n";
+    }
+    else {
+        print "<tr><td align=center width=200>"
+          . "<input type=\"image\" src=\"pict/menu_b_analyze.jpg\" "
+          . "alt=\"Analyze\" width=\"167\" height=20 border=0>\n"
+          . "</form></td>\n";
+    }
+
+    # Image Add Button
+    if ($::LIVE == 0) {
+        print "<td align=center width=200>"
+          . "<form action=\"$::PROGNAME\" method=\"get\">\n"
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_ADD\">\n"
+          . Args::make_hidden()
+          . "<input type=\"image\" src=\"pict/menu_b_ifnew.jpg\" "
+          . "alt=\"Add Image\" width=167 height=20 border=0></form></td>\n"
+          .
+
+          # Cancel Button
+          "<td align=center width=200>"
+          . "<form action=\"$::PROGNAME\" method=\"get\">\n"
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN\">\n"
+          . "<input type=\"hidden\" name=\"case\" value=\"$Args::args{'case'}\">\n"
+          . "<input type=\"image\" src=\"pict/menu_b_hcls.jpg\" "
+          . "width=167 height=20 alt=\"Close Host\" border=0>\n"
+          . "</form></td></tr>";
+    }
+    else {
+        print "<td width=200>&nbsp;</td><td width=200>&nbsp;</td></tr>\n";
+    }
+
+    # Help Button
+    print
+"<td width=200>&nbsp;</td><td align=center width=200><a href=\"$::HELP_URL\" "
+      . " target=\"_blank\">"
+      . "<img src=\"pict/menu_b_help.jpg\" alt=\"Help\" "
+      . "width=\"167\" height=20 border=0>"
+      . "</a></td><td width=200>&nbsp;</td></tr>\n"
+      . "</table>\n";
+
+    # Other features that can be done on a host
+
+    if ($::LIVE == 0) {
+        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?${Args::baseargs_novol}&"
+          . "mod=$::MOD_TL&view=$Timeline::FRAME\">"
+          . "<img border=0 "
+          . "src=\"pict/menu_b_tl.jpg\" "
+          . "width=\"167\" height=20 "
+          . "alt=\"File Activity Timelines\"></a></td>\n";
+
+        # verify the integrity of the images
+        print "<td align=\"center\" width=200>"
+          . "<a href=\"$::PROGNAME?${Args::baseargs_novol}&"
+          . "mod=$::MOD_HASH&view=$Hash::IMG_LIST_FR\">"
+          . "<img border=0 "
+          . "src=\"pict/menu_b_int.jpg\" "
+          . "width=\"167\" height=20 "
+          . "alt=\"Image Integrity\"></a></td>\n"
+          .
+
+          # Hashdatabases
+          "<td align=\"center\" width=200>"
+          . "<a href=\"$::PROGNAME?${Args::baseargs_novol}&"
+          . "mod=$::MOD_HASH&view=$Hash::DB_MANAGER\">"
+          . "<img border=0 "
+          . "src=\"pict/menu_b_hashdb.jpg\" "
+          . "width=\"167\" height=20 "
+          . "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?${Args::baseargs_novol}&mod=$::MOD_NOTES&view=$Notes::READ_NORM\">"
+              . "<img border=0 "
+              . "src=\"pict/menu_b_note.jpg\" "
+              . "width=\"167\" height=20 "
+              . "alt=\"View Notes\"></a></td>\n"
+              .
+
+              "<td width=300 align=\"center\">"
+              . "<a href=\"$::PROGNAME?${Args::baseargs_novol}&mod=$::MOD_NOTES&view=$Notes::READ_SEQ\">"
+              . "<img border=0 "
+              . "src=\"pict/menu_b_seq.jpg\" "
+              . "width=\"167\" height=20 "
+              . "alt=\"Event Sequencer\"></a></td>\n"
+              .
+
+              "</tr>\n" . "</table>\n";
+        }
+
+        # If LIVE
+    }
+    else {
+        print "<a href=\"./about\"><br>\n"
+          . "<img src=\"pict/logo.jpg\" border=0 alt=\"Logo\"></a><br>\n";
+
+    }
+
+    Print::print_html_footer();
+
+    return 0;
+}
+
+# Log in the host log that a given image was opened by what user
+# then open the main window
+sub vol_open_log {
+
+    # These will be stopped in the func during  LIVE
+    Print::log_host_info(
+        "Image $Args::args{'vol'} opened by $Args::args{'inv'}");
+    Print::log_host_inv("$Args::args{'vol'}: volume opened");
+
+    $Args::args{'mod'}  = $Args::enc_args{'mod'}  = $::MOD_FRAME;
+    $Args::args{'view'} = $Args::enc_args{'view'} = $Frame::IMG_FRAME;
+    Frame::main();
+}
+
+# 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
+#
+sub img_add {
+    Print::print_html_header(
+        "Add Image To $Args::args{'case'}:$Args::args{'host'}");
+
+    print "<b>Case:</b> $Args::args{'case'}<br>\n"
+      . "<b>Host:</b> $Args::args{'host'}<br>\n";
+
+    print "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_ADD_PREP\">\n"
+      . Args::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=4>&nbsp;</td>
+</tr>
+
+<tr>
+  <td align=left colspan=4>
+    1. <b>Location</b><br>Enter the full path (starting with <tt>/</tt>) to the image file.<br>
+    If the image is split (either raw or EnCase), then enter '*' for the extension.
+  </td>
+</tr>
+<tr>
+  <td>&nbsp;&nbsp;</td>
+  <td align=left colspan=3>
+    <input type=\"text\" name=\"img_path\" size=36 maxlength=256>
+  </td>
+</tr>
+<tr><td colspan=4>&nbsp;</td><tr>
+<tr>
+  <td align=left colspan=4>2. <b>Type</b><br>Please select if this image file is for a disk or a single partition.</td>
+</tr>
+<tr>
+  <td>&nbsp;&nbsp;</td>
+  <td align=left>
+    <input type=\"radio\" name=\"imgtype\" value="disk" CHECKED>
+      Disk
+  </td>
+  <td align=left>
+    <input type=\"radio\" name=\"imgtype\" value="volume">
+      Partition 
+  </td>
+  <td align=left>&nbsp;
+  </td>
+</tr>
+
+<tr><td colspan=4>&nbsp;</td><tr>
+<tr>
+  <td align=left colspan=4>3. <b>Import Method</b><br>To analyze the image file, it must be located in the evidence locker. It can be imported from its current location using a symbolic link, by copying it, or by moving it.  Note that if a system failure occurs during the move, then the image could become corrupt.</td>
+</tr>
+<tr>
+  <td>&nbsp;&nbsp;</td>
+  <td align=left>
+    <input type=\"radio\" name=\"sort\" value=$IMG_ADD_SYM CHECKED>
+      Symlink
+  </td>
+  <td align=left>
+    <input type=\"radio\" name=\"sort\" value=$IMG_ADD_COPY>
+      Copy 
+  </td>
+  <td align=left>
+    <input type=\"radio\" name=\"sort\" value=$IMG_ADD_MOVE>
+	  Move 
+  </td>
+</tr>
+
+
+<tr>
+  <td colspan=4>&nbsp;</td>
+</tr>
+
+</table>
+
+<br>
+<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">
+<tr>
+  <td align=center colspan=2>
+    <input type=\"image\" src=\"pict/menu_b_next.jpg\" alt=\"Next Step\" width=\"167\" height=20 border=0>
+  </td>
+</tr>
+
+</form>
+
+EOF1
+
+    print "<tr><td colspan=2>&nbsp;</td></tr>\n"
+      . "<td align=center>\n"
+      . "    <form action=\"$::PROGNAME\" method=\"get\">\n"
+      . "    <input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+      . "    <input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_OPEN\">\n"
+      .
+
+      Args::make_hidden()
+      . "    <input type=\"image\" src=\"pict/menu_b_cancel.jpg\" "
+      . "alt=\"Cancel\" width=\"167\" height=20 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\" height=20 border=0></a>\n"
+      . "  </td>\n"
+      . "</tr>\n"
+      . "</table>\n";
+
+    Print::print_html_footer();
+
+    return 0;
+}
+
+# List the images from the glob - called from img_add_prep if spl_conf is not set
+sub img_add_split_conf {
+    my $img_path = Args::get_img_path_wild();
+    my $img_type = $Args::args{'imgtype'};
+
+    print "<center><br><br><b>Split Image Confirmation</b><br><br>\n";
+
+    my @spl_img = glob($img_path);
+    if (scalar(@spl_img) == 0) {
+        print "No images were found at this location ($img_path)<br>\n"
+          . "Use the back button and fix the path<br>\n";
+        return;
+    }
+
+    print <<EOF1;
+The following images will be added to the case.<br>
+If this is not the correct order, then you should change the naming convention.<br>
+Press the Next button at the bottom of the page if this is correct.<br><br>
+
+<table width=\"600\" cellpadding=\"2\" cellspacing=\"0\" background=\"$::YEL_PIX\" border=0>
+<tr>
+  <td colspan=2>&nbsp;</td>
+</tr>
+EOF1
+
+    my $a = 0;
+    foreach $i (@spl_img) {
+
+       # We need to do this when we analyze the image, so do it here too to show
+       # what will be analyzed
+        $i = $1 if ($i =~ /^($::REG_IMG_PATH)$/);
+        print
+"<tr><td align=\"center\">$a</td><td align=\"left\"><tt>$i</tt></td></tr>\n";
+        $a++;
+    }
+
+    my $vs = "";
+    $vs = "&vstype=$Args::args{'vstype'}"
+      if (exists $Args::args{'vstype'});
+
+    # Print the Ok Button
+    print "</table><br><br>\n"
+      . "<table width=\"600\" cellpadding=\"2\" cellspacing=\"0\" border=0>"
+      . "<tr><td width=\"300\" align=\"center\"><a href=\"$::PROGNAME?${Args::baseargs_novol}&"
+      . "mod=$::MOD_CASEMAN&view=$Caseman::IMG_ADD_PREP&spl_conf=1&sort=$Args::args{'sort'}&"
+      . "img_path=$img_path&imgtype=$Args::args{'imgtype'}$vs\">"
+      . "<img src=\"pict/menu_b_next.jpg\" alt=\"Next\" "
+      . "width=\"167\" height=20 border=0></a></td>\n"
+      . "<td width=\"300\" align=\"center\"><a href=\"$::PROGNAME?${Args::baseargs_novol}&"
+      . "mod=$::MOD_CASEMAN&view=$Caseman::IMG_ADD\">"
+      . "<img src=\"pict/menu_b_cancel.jpg\" alt=\"cancel\" width=\"167\" height=\"20\" border=\"0\">"
+      . "</a></td></tr></table>\n";
+
+    return 0;
+}
+
+# Run the autodetect stuff and get confirmation from the user
+sub img_add_prep {
+    Args::check_img_path_wild();
+    Args::check_sort();
+    unless ((exists $Args::args{'imgtype'})
+        && ($Args::args{'imgtype'} =~ /^\w+$/))
+    {
+        Print::print_check_err("Invalid image type");
+    }
+
+    Print::print_html_header("Collecting details on new image file");
+
+    my $img_path = Args::get_img_path_wild();
+
+    my $img_type = $Args::args{'imgtype'};
+    my $spl_conf = 0;
+    $spl_conf = 1
+      if ((exists $Args::args{'spl_conf'}) && ($Args::args{'spl_conf'} == 1));
+
+    # If we have a wildcard then it is a split image, so we verify it first and
+    # then make a string of the images so we can test it.
+    if ($img_path =~ /[\*\?]/) {
+        if ($spl_conf == 0) {
+            return img_add_split_conf();
+        }
+        else {
+            $img_tmp = "";
+            foreach my $i (glob($img_path)) {
+                if ($i =~ /^($::REG_IMG_PATH)$/) {
+                    $img_tmp .= "\"$1\" ";
+                }
+            }
+            $img_path = $img_tmp;
+        }
+    }
+    else {
+        unless ((-f $img_path)
+            || (-d $img_path)
+            || (-l $img_path)
+            || (-b $img_path)
+            || (-c $img_path))
+        {
+            Print::print_err("Image file not found ($img_path)");
+        }
+        $img_path = "\"$img_path\"";
+    }
+
+    # Get the image type
+    local *OUT;
+    Exec::exec_pipe(*OUT, "'$::TSKDIR/img_stat' -t $img_path");
+    my $itype = Exec::read_pipe_line(*OUT);
+    if (defined $itype) {
+        chomp $itype;
+        $itype = $1 if ($itype =~ /^(\w+)$/);
+    }
+    else {
+        print
+"The image format type could not be determined for this image file<br>\n";
+        return;
+    }
+    close(OUT);
+
+    # The plan here is to collect the needed info and then we print it
+
+    my $conflict = 0;
+    my $cnt      = 0;
+    $start[0]  = "";
+    $end[0]    = "";
+    $type[0]   = "";
+    $desc[0]   = "";
+    $active[0] = "";
+
+    my $vstype = "";
+
+    my $vstype_flag = "";
+    my $mmls_out    = "";    # Will contain output of mmls (if disk image)
+    if ($img_type eq "disk") {
+        my $out;
+
+        if (   (exists $Args::args{'vstype'})
+            && ($Args::args{'vstype'} =~ /^(\w+)$/))
+        {
+            $vstype      = $Args::args{'vstype'};
+            $vstype_flag = "-t $vstype";
+        }
+
+        # Get the type
+        else {
+
+            Exec::exec_pipe(*OUT, "'$::TSKDIR/mmstat' -i $itype $img_path");
+
+            $vstype = Exec::read_pipe_line(*OUT);
+            close(OUT);
+
+            chomp $vstype if (defined $vstype);
+
+            if (   (!defined $vstype)
+                || ($vstype =~ /^Error determining/)
+                || ($vstype eq "")
+                || (!exists $Vs::type{$vstype})
+                || ($vstype !~ /^\w+$/))
+            {
+                print
+"<table><tr><td colspan=2><font color=\"$::DEL_COLOR[0]\">Warning:</font> Autopsy could not determine the volume system type for the disk image (i.e. the type of partition table).<br>\n"
+                  . "Please select the type from the list below or reclassify the image as a volume image instead of as a disk image.</td></tr>\n"
+                  . "<tr><td colspan=2>&nbsp;</td></tr>\n"
+                  . "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
+                  . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+                  . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_ADD_PREP\">\n"
+                  . "<input type=\"hidden\" name=\"spl_conf\" value=\"1\">\n"
+                  . "<input type=\"hidden\" name=\"img_path\" value=\"$Args::args{'img_path'}\">\n"
+                  . "<input type=\"hidden\" name=\"sort\" value=\"$Args::enc_args{'sort'}\">\n"
+                  . Args::make_hidden()
+                  . "<tr><td>Disk Image <input type=\"radio\" name=\"imgtype\" value=\"disk\" CHECKED></td>\n"
+                  . "<td>Volume Image<input type=\"radio\" name=\"imgtype\" value=\"volume\"></td></tr>\n"
+                  . "<tr><td>Volume System Type (disk image only): <select name=\"vstype\">\n";
+
+                foreach my $vs (sort keys %Vs::type) {
+                    print "<option value=\"$vs\"";
+                    print " selected" if ($vs eq 'dos');
+                    print ">${vs}</option>\n";
+                }
+
+                print "</select></td>"
+                  . "<td>&nbsp;</td></tr>"
+                  . "<tr><td colspan=2>&nbsp;</td></tr>"
+                  . "</table><br><br>\n"
+                  . "<input type=\"image\" src=\"pict/menu_b_ok.jpg\" alt=\"Ok\" width=\"176\" height=20 border=0>"
+                  . "</form>\n";
+                return;
+            }
+            $vstype = $1 if ($vstype =~ /^(\w+)$/);
+            $vstype_flag = "-t $vstype";
+        }
+
+        # Run 'mmls' on the image
+        Exec::exec_pipe(*OUT,
+            "'$::TSKDIR/mmls' -a -i $itype -aM $vstype_flag -r $img_path");
+
+        # cycle through results and add each to table with file system type
+        my $part_type = "";
+
+        while ($_ = Exec::read_pipe_line(*OUT)) {
+            $mmls_out .= "$_";    # Save the line
+            last if (/^Error determining partition/);
+
+            if (/^\d+:\s+[\d:]+\s+(\d+)\s+(\d+)\s+\d+\s+(\S.*)$/) {
+                $start[$cnt]  = $1;
+                $end[$cnt]    = $2;
+                $desc[$cnt]   = $3;
+                $active[$cnt] = 1;
+            }
+            elsif ((/^DOS Partition/)
+                || (/^BSD Disk/)
+                || (/^Sun VTOC/)
+                || (/^MAC Partition/)
+                || (/^GUID Partition/))
+            {
+                $part_type = $_;
+
+                #print "<tr><td colspan=7>&nbsp;</td></tr>\n";
+                #print "<tr><td colspan=7>$_</td></tr>\n";
+                next;
+            }
+            elsif (/^Sector:/) {
+
+                #print "<tr><td colspan=7>$_</td></tr>\n";
+                next;
+            }
+            else {
+                next;
+            }
+
+            # Skip the BSD partition for the full disk
+            next
+              if ( ($part_type =~ /^BSD Disk/)
+                && ($start[$cnt] == 0)
+                && ($desc[$cnt] =~ /^Unused/));
+
+            # Skip if this is an extended DOS partition
+            next
+              if ( ($part_type =~ /^DOS Partition/)
+                && ($desc[$cnt] =~ /Extended \(/));
+
+            # Get rid of the leading 0s
+            $start[$cnt] = $1
+              if ($start[$cnt] =~ /^0+([1-9]\d*)$/);
+            $end[$cnt] = $1
+              if ($end[$cnt] =~ /^0+([1-9]\d*)$/);
+
+            # Do we already have this partition?
+            my $i;
+            for ($i = 0; $i < $cnt; $i++) {
+                next if ($active[$i] == 0);
+
+                if ($start[$i] == $start[$cnt]) {
+                    $conflict = 1;
+
+                    if ($end[$i] == $end[$cnt]) {
+                        last;
+                    }
+
+                    #The previous was the BSD partition - skip it */
+                    if (   ($desc[$i] =~ /^FreeBSD \(0xA5\)/)
+                        || ($desc[$i] =~ /^OpenBSD \(0xA6\)/)
+                        || ($desc[$i] =~ /^NetBSD \(0xA9\)/))
+                    {
+                        $active[$i] = 0;
+
+                        # if the current one is the BSD partition for
+                        # the full partition/disk then skip it
+                        if ($desc[$cnt] =~ /^Unused /) {
+                            $active[$cnt] = 0;
+                        }
+                    }
+                }
+
+                # Do we start inside of another?
+                if (($start[$i] > $start[$cnt]) && ($end[$i] < $start[$cnt])) {
+                    $conflict = 1;
+                }
+
+                # Do we end inside of another?
+                elsif (($start[$i] < $end[$cnt]) && ($end[$i] > $end[$cnt])) {
+                    $conflict = 1;
+                }
+            }
+            if (($end[$i] == $end[$cnt]) && ($i != $cnt)) {
+                next;
+            }
+
+            local *OUT2;
+            my $out2;
+
+            # Run 'fstat -t' on the image
+            Exec::exec_pipe(*OUT2,
+                "'$::TSKDIR/fsstat' -o $start[$cnt] -i $itype -t $img_path");
+
+            $type[$cnt] = Exec::read_pipe_line(*OUT2);
+            close(OUT2);
+
+            if (   (!exists $type[$cnt])
+                || (!defined $type[$cnt])
+                || ($type[$cnt] =~ /^Cannot determine/)
+                || ($type[$cnt] eq ""))
+            {
+                $type[$cnt] = "Unknown";
+            }
+            chomp $type[$cnt];
+
+            $cnt++;
+        }
+        close(OUT);
+
+        if ($conflict == 1) {
+            print
+"<tr><td colspan=2><font color=\"$::DEL_COLOR[0]\">Warning:</font> Conflicts in the partitions were detected.<br>The full <tt>mmls</tt> output is given at the bottom of the page</td></tr>\n"
+              . "<tr><td colspan=2>&nbsp;</td></tr>\n";
+        }
+    }
+
+    # If a volume, then run fsstat on it
+    elsif ($img_type eq "volume") {
+
+        # Run 'fstat -t' on the image
+        Exec::exec_pipe(*OUT, "'$::TSKDIR/fsstat' -t -i $itype $img_path");
+
+        $type[0] = Exec::read_pipe_line(*OUT);
+        close(OUT);
+
+        if (   (!defined $type[0])
+            || ($type[0] =~ /^Cannot determine/)
+            || ($type[0] eq ""))
+        {
+            $type[0] = "Unknown";
+            print
+"<font color=\"$::DEL_COLOR[0]\">Warning:</font> The file system type of the volume image file could not be determined.<br>\n"
+              . "If this is a disk image file, return to the previous page and change the type.<br><br>\n";
+        }
+        chomp $type[0];
+        $start[0]  = 0;
+        $end[0]    = 0;
+        $active[0] = 1;
+        $desc[0]   = $type[0];
+        $cnt++;
+        close(OUT);
+    }
+    else {
+        Print::print_err("Unknown image type: $img_type");
+    }
+
+    my $sname = $img_path;
+    $sname = "$::IMGDIR/" . "$1" if ($sname =~ /\/($::REG_FILE)\"$/);
+
+# Now that we have the information about the partitions and disks, print the fields
+    print <<EOF1;
+		
+<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">
+<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">
+<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_ADD_DOIT\">
+<input type=\"hidden\" name=\"img_path\" value=\"$Args::args{'img_path'}\">
+<input type=\"hidden\" name=\"num_img\" value=\"$cnt\">
+<input type=\"hidden\" name=\"sort\" value=\"$Args::enc_args{'sort'}\">
+
+
+<center>
+<h3>Image File Details</h3>
+<table width=\"600\" cellpadding=\"2\" cellspacing=\"0\" background=\"$::YEL_PIX\" border=0>
+<tr>
+  <td align=left colspan=4>
+	<b>Local Name: </b> $sname
+  </td>
+</tr>
+
+EOF1
+
+    # We do not currently offer integrity options for non-raw files
+    if (($itype eq "raw") || ($itype eq "split")) {
+
+        print <<EOF1b;
+<tr>
+  <td align=left colspan=4>
+	<b>Data Integrity: </b> An MD5 hash can be used to verify the 
+	integrity of the image.  (With split images, this hash is for the full image file)
+  </td>
+</tr>
+
+<tr>
+  <td>&nbsp;&nbsp;</td>
+  <td align=left colspan=3>
+    <input type=\"radio\" name=\"do_md5\" value=\"$MD5_NOTHING\" CHECKED>
+	<u>Ignore</u> the hash value for this image.
+  </td>
+</tr>
+
+<tr>
+  <td>&nbsp;&nbsp;</td>
+  <td align=left colspan=3>
+    <input type=\"radio\" name=\"do_md5\" value=\"$MD5_CALC\">
+	<u>Calculate</u> the hash value for this image.
+  </td>
+</tr>
+
+<tr>
+  <td>&nbsp;&nbsp;</td>
+  <td align=left colspan=3>
+    <input type=\"radio\" name=\"do_md5\" value=\"$MD5_ADD\">
+	<u>Add</u> the following MD5 hash value for this image:
+  </td>
+</tr>
+
+<tr>
+  <td>&nbsp;&nbsp;</td>
+  <td align=left colspan=3>&nbsp;&nbsp;&nbsp;&nbsp;
+	<input type=\"text\" name=\"md5\" size=36 maxlength=32>
+  </td>
+</tr>
+
+<tr>
+  <td>&nbsp;&nbsp;</td>
+  <td align=left colspan=3>&nbsp;&nbsp;&nbsp;&nbsp;
+	<input type=\"checkbox\" name=\"ver_md5\" value=\"1\">
+	&nbsp;Verify hash after importing?
+  </td>
+</tr>
+EOF1b
+    }
+    else {
+        print
+          "<input type=\"hidden\" name=\"do_md5\" value=\"$MD5_NOTHING\">\n";
+    }
+
+    print <<EOF1c;
+</table>
+
+<h3>File System Details</h3>
+<table width=\"600\" cellpadding=\"2\" cellspacing=\"0\" background=\"$::YEL_PIX\" border=0>
+
+<tr>
+  <td colspan=2 align=left>Analysis of the image file shows the following partitions:</td>
+</tr>
+<tr>
+  <td colspan=2>&nbsp;</td>
+</tr>
+
+EOF1c
+
+    print Args::make_hidden();
+
+    print "<input type=\"hidden\" name=\"vstype\" value=\"$vstype\">\n"
+      if ($vstype ne "");
+
+    my $idx     = 1;
+    my $ms_cnt  = 0;
+    my @ms_name = ("C:", "D:", "E:", "F:", "G:", "H:", "I:", "J:");
+    for (my $i = 0; $i < $cnt; $i++) {
+        next if ($active[$i] == 0);
+        print
+"<tr><td colspan=2><u>Partition $idx</u> (Type: $desc[$i])</td><tr>\n";
+
+        if ($cnt > 1) {
+            print "<tr><td colspan=2>&nbsp;&nbsp;Add to case? "
+              . "<input type=\"checkbox\" name=\"yes-${idx}\" value=1 CHECKED></td></tr>\n";
+        }
+        else {
+            print "<input type=\"hidden\" name=\"yes-${idx}\" value=1>\n";
+        }
+
+        unless (($start[$i] == 0) && ($end[$i] == 0)) {
+            print "<tr><td colspan=2>&nbsp;&nbsp;Sector Range: "
+              . "$start[$i] to $end[$i]"
+              . "</td></tr>\n";
+        }
+
+        print
+          "<input type=\"hidden\" name=\"start-${idx}\" value=\"$start[$i]\">"
+          . "<input type=\"hidden\" name=\"end-${idx}\" value=\"$end[$i]\">\n"
+          . "<tr><td>&nbsp;&nbsp;Mount Point: <input type=\"text\" name=\"mnt-${idx}\" size=\"6\"";
+        if (($type[$i] =~ /^ntfs/) || ($type[$i] =~ /^fat/)) {
+            print " value=\"$ms_name[$ms_cnt]\""
+              if ($ms_cnt < 8);
+            $ms_cnt++;
+        }
+        elsif (($type[$i] =~ /^raw/)
+            || ($type[$i] =~ /^swap/))
+        {
+            print " value=\"N/A\"";
+        }
+        else {
+            print " value=\"/$idx/\"";
+        }
+        print "></td>\n"
+          . "<td>File System Type: <select name=\"ftype-${idx}\">\n";
+
+        foreach my $fs (@Fs::types) {
+            print "<option value=\"$fs\"";
+            print " selected" if ($fs eq $type[$i]);
+            print ">${fs}</option>\n";
+        }
+
+        # The following do not have 'metas' but should be in the list
+        print "<option value=\"\">======</option>\n";
+        if ($type[$i] eq "Unknown") {
+            print "<option value=\"raw\" selected>raw</option>\n";
+        }
+        else {
+            print "<option value=\"raw\">raw</option>\n";
+        }
+
+        print "<option value=\"swap\">swap</option>\n"
+          . "</select></td></tr>\n"
+          . "<tr><td colspan=2>&nbsp;</td></tr>\n";
+
+        $idx++;
+    }
+
+    print "</table>\n";
+
+    print <<EOF2;
+<br><br>
+<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">
+<tr>
+  <td align=center>
+    <input type=\"image\" src=\"pict/menu_b_add.jpg\" 
+      alt=\"Add\" width=\"176\" height=20 border=0>
+  </td>
+</form>
+  <td align=center>
+    <form action=\"$::PROGNAME\" method=\"get\">
+EOF2
+    print Args::make_hidden();
+    print <<EOF3;
+    <input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">
+    <input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_OPEN\">
+    <input type=\"image\" src=\"pict/menu_b_cancel.jpg\" 
+    alt=\"Cancel\" width=\"167\" height=20 border=0>
+    </form>
+  </td>
+  <td align=center><a href=\"$::HELP_URL\" 
+    target=\"_blank\">
+    <img src=\"pict/menu_b_help.jpg\" alt=\"Help\" 
+    width=\"167\" height=20 border=0></a>
+  </td>
+</tr>
+</table>
+EOF3
+
+    if ($img_type eq "disk") {
+        print
+"</center><p>For your reference, the <tt>mmls</tt> output was the following:<br><pre>$mmls_out</pre>\n";
+    }
+
+    Print::print_html_footer();
+
+    return 0;
+}
+
+# Add the image to the configuration by adding it to the host config file
+# and the md5.txt file if that data was provided
+sub img_add_doit {
+
+    Args::check_num_img();
+    Args::check_img_path_wild();
+    Args::check_sort();
+    Args::check_do_md5();
+
+    my $num_img     = Args::get_num_img();
+    my $img_path    = Args::get_img_path_wild();
+    my $import_type = Args::get_sort();
+
+    Print::print_html_header("Add a new image to an Autopsy Case");
+
+    my $err     = 0;
+    my $add_num = 0;
+    $start[0] = 0;
+    $end[0]   = 0;
+    $ftype[0] = "";
+    $mnt[0]   = "";
+
+ # We need a string with all images in it for the hashes and file system testing
+    my $img_path_full;
+    if ($img_path =~ /[\*\?]/) {
+        $img_path_full = "";
+        foreach my $i (glob($img_path)) {
+            if ($i =~ /^($::REG_IMG_PATH)$/) {
+                $img_path_full .= "\"$1\" ";
+            }
+        }
+    }
+    else {
+        $img_path_full = "\"$img_path\"";
+    }
+
+    # Get the image type
+    local *OUT;
+    Exec::exec_pipe(*OUT, "'$::TSKDIR/img_stat' -t $img_path_full");
+    my $itype = Exec::read_pipe_line(*OUT);
+    if (defined $itype) {
+        chomp $itype;
+        $itype = $1 if ($itype =~ /^(\w+)$/);
+    }
+    else {
+        print
+"The image format type could not be determined for this image file<br>\n";
+        return;
+    }
+    close(OUT);
+
+    # Check the hash of the image if that is the plan
+    my $do_md5  = Args::get_do_md5();
+    my $act_md5 = "";
+    unless ($do_md5 == $MD5_NOTHING) {
+
+        # Do we need to calculate an MD5?
+        if (
+            ($do_md5 == $MD5_CALC)
+            || (   ($do_md5 == $MD5_ADD)
+                && (exists $Args::args{'ver_md5'})
+                && ($Args::args{'ver_md5'} == 1))
+          )
+        {
+
+            print "<p>Calculating MD5 (this could take a while)<br>\n";
+            $act_md5 = Hash::calc_md5_split($img_path_full);
+            unless ($act_md5 =~ /^$::REG_MD5$/o) {
+                print "Error calculating MD5: $act_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::args{'md5'})) {
+
+            my $md5 = $Args::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?"
+                  . "mod=$::MOD_CASEMAN&view=$Caseman::IMG_ADD&"
+                  . "$Args::baseargs\">"
+                  . "<img src=\"pict/menu_b_back.jpg\" border=\"0\" "
+                  . "width=\"167\" height=20 alt=\"Back\"></a>\n";
+                return 1;
+            }
+            $md5 =~ tr/[a-f]/[A-F]/;
+
+            # They also want us to validate the MD5
+            if (   (exists $Args::args{'ver_md5'})
+                && ($Args::args{'ver_md5'} == 1))
+            {
+
+                if ($act_md5 eq $md5) {
+                    print "Integrity Check Passed<br>\n";
+                    Print::log_host_info("Integrity check passed on new image");
+                }
+                else {
+                    print "<font color=\"$::DEL_COLOR[0]\">"
+                      . "Integrity Check Failed<br></font><br>\n"
+                      . "Provided: <tt>$md5</tt><br>\n"
+                      . "Image not added to case<br>\n";
+
+                    Print::log_host_info("Integrity check failed on new image");
+                    return 1;
+                }
+            }
+
+            # set the act_md5 value to what was given and verified
+            $act_md5 = $md5;
+        }
+
+        # We will add the MD5 to the config file after we get its ID
+    }
+
+    # Proces the image arguments to make sure they are all there and test the
+    # file system type
+    print "Testing partitions<br>\n";
+    for (my $i = 0; $i <= $num_img; $i++) {
+
+        next
+          unless ((exists $Args::args{"yes-" . $i})
+            && ($Args::args{"yes-" . $i} == 1));
+
+        if (   (exists $Args::args{"start-" . $i})
+            && ($Args::args{"start-" . $i} =~ /^(\d+)$/))
+        {
+            $start[$add_num] = $1;
+        }
+        else {
+            print "Missing starting address for partition $i<br>\n";
+            $err = 1;
+            last;
+        }
+
+        if (   (exists $Args::args{"end-" . $i})
+            && ($Args::args{"end-" . $i} =~ /^(\d+)$/))
+        {
+            $end[$add_num] = $1;
+        }
+        else {
+            print "Missing ending address for partition $i<br>\n";
+            $err = 1;
+            last;
+        }
+
+        if (   (exists $Args::args{"mnt-" . $i})
+            && ($Args::args{"mnt-" . $i} =~ /^($::REG_MNT)$/))
+        {
+            $mnt[$add_num] = $1;
+        }
+        else {
+            print "Missing mount point for partition $i<br>\n";
+            $err = 1;
+            last;
+        }
+
+        if (   (exists $Args::args{"ftype-" . $i})
+            && ($Args::args{"ftype-" . $i} =~ /^($::REG_FTYPE)$/))
+        {
+            $ftype[$add_num] = $1;
+        }
+        else {
+            print "Missing file system type for partition $i<br>\n";
+            $err = 1;
+            last;
+        }
+
+        # Test the File System
+        if (($ftype[$add_num] ne 'swap') && ($ftype[$add_num] ne 'raw')) {
+
+            local *OUT;
+            my $out;
+
+            # Run 'fsstat' and see if there is any output - else there was
+            # an error and the data went to STDERR
+            Exec::exec_pipe(*OUT,
+"'$::TSKDIR/fsstat' -o $start[$add_num] -i $itype -f $ftype[$add_num] $img_path_full"
+            );
+            unless (read(OUT, $out, 1)) {
+                print
+"<p>Partition $i is not a <tt>$ftype[$add_num]</tt> file system<br>\n";
+                $err = 1;
+                last;
+            }
+            close(OUT);
+        }
+        $add_num++;
+    }
+
+    # Go back if we got an error
+    if ($err == 1) {
+        print "Use the browser's back button to fix the data<br>\n";
+        return 1;
+    }
+
+    ##################################################
+    # Copy the images and add them to the config file
+
+    if ($import_type == $IMG_ADD_SYM) {
+        Print::print_err("ERROR: /bin/ln missing")
+          unless (-x '/bin/ln');
+
+        print "Linking image(s) into evidence locker<br>\n";
+    }
+    elsif ($import_type == $IMG_ADD_COPY) {
+        Print::print_err("ERROR: /bin/cp missing")
+          unless (-x '/bin/cp');
+
+        print
+"Copying image(s) into evidence locker (this could take a little while)<br>\n";
+    }
+    elsif ($import_type == $IMG_ADD_MOVE) {
+        Print::print_err("ERROR: /bin/mv missing")
+          unless (-x '/bin/mv');
+
+        print "Moving image(s) into evidence locker<br>\n";
+    }
+    else {
+        Print::print_err("Invalid Import Type: $import_type\n");
+    }
+
+    my $imgid = "";
+    foreach my $i (glob($img_path)) {
+
+        # remove the tainting
+        $i = $1 if ($i =~ /^($::REG_IMG_PATH)$/);
+
+        # Deterine the local (target) name
+        my $img = "";
+        if ($i =~ /\/($::REG_FILE)$/) {
+            $img = "$::IMGDIR/$1";
+        }
+        else {
+            Print::print_err("Error Parsing Image Path ($i)\n");
+        }
+
+        # Get the full path of the destination
+        my $img_dst = "$::host_dir" . "$img";
+        if ((-e "$img_dst") || (-l "$img_dst")) {
+            Print::print_err(
+"An image by the same name already exists in the Host directory ($img)\n"
+                  . "Use the browser's back button to fix the name or delete the existing file."
+            );
+        }
+
+        my $orig_size = (stat("$i"))[7];
+
+        # Copy, Move, or link it
+        if ($import_type == $IMG_ADD_SYM) {
+
+            Print::log_host_info(
+"Sym Linking image $img_path into $Args::args{'case'}:$Args::args{'host'}"
+            );
+
+            Exec::exec_sys("/bin/ln -s '$i' '$img_dst'");
+        }
+        elsif ($import_type == $IMG_ADD_COPY) {
+            Print::log_host_info(
+"Copying image $img_path into $Args::args{'case'}:$Args::args{'host'}"
+            );
+
+            Exec::exec_sys("/bin/cp '$i' '$img_dst'");
+        }
+        elsif ($import_type == $IMG_ADD_MOVE) {
+            Print::log_host_info(
+"Moving image $img_path into $Args::args{'case'}:$Args::args{'host'}"
+            );
+
+            Exec::exec_sys("/bin/mv '$i' '$img_dst'");
+        }
+
+        my $new_size = (stat("$img_dst"))[7];
+
+        if ($new_size != $orig_size) {
+            Print::print_err(
+"Original image size ($orig_size) is not the same as the destination size ($new_size)"
+            );
+        }
+
+        # Add the disk and partition images to the config file
+        $imgid = Caseman::add_img_host_config("image", "$itype  $img", $imgid);
+    }
+    print "Image file added with ID <tt>$imgid</tt><br>\n";
+
+    # AFM files have raw files that we also need to copy
+    # This approach is not the best, since it may copy more than
+    # is needed
+    if ($itype eq "afm") {
+        my $afm_base_path = "";
+
+        if ($img_path =~ /^(.*?)\.afm/i) {
+            $afm_base_path = $1;
+            $afm_base_path .= ".[0-9][0-9][0-9]";
+        }
+        else {
+            Print::print_err(
+                "Error parsing out base name of AFM file $img_path");
+        }
+
+        print "BASE: $afm_base_path<br>\n";
+
+        my $copied = 0;
+
+        foreach my $i (glob($afm_base_path)) {
+            $copied++;
+
+            # remove the tainting
+            $i = $1 if ($i =~ /^($::REG_IMG_PATH)$/);
+
+            # Deterine the local (target) name
+            my $img = "";
+            if ($i =~ /\/($::REG_FILE)$/) {
+                $img = "$::IMGDIR/$1";
+            }
+            else {
+                Print::print_err("Error Parsing Image Path ($i)\n");
+            }
+
+            # Get the full path of the destination
+            my $img_dst = "$::host_dir" . "$img";
+            if ((-e "$img_dst") || (-l "$img_dst")) {
+                Print::print_err(
+"An image by the same name already exists in the Host directory ($img) (AFM import)\n"
+                      . "Use the browser's back button to fix the name or delete the existing file."
+                );
+            }
+
+            my $orig_size = (stat("$i"))[7];
+
+            # Copy, Move, or link it
+            if ($import_type == $IMG_ADD_SYM) {
+
+                Print::log_host_info(
+"Sym Linking image $img_path into $Args::args{'case'}:$Args::args{'host'}"
+                );
+
+                Exec::exec_sys("/bin/ln -s '$i' '$img_dst'");
+            }
+            elsif ($import_type == $IMG_ADD_COPY) {
+                Print::log_host_info(
+"Copying image $img_path into $Args::args{'case'}:$Args::args{'host'}"
+                );
+
+                Exec::exec_sys("/bin/cp '$i' '$img_dst'");
+            }
+            elsif ($import_type == $IMG_ADD_MOVE) {
+                Print::log_host_info(
+"Moving image $img_path into $Args::args{'case'}:$Args::args{'host'}"
+                );
+
+                Exec::exec_sys("/bin/mv '$i' '$img_dst'");
+            }
+
+            my $new_size = (stat("$img_dst"))[7];
+
+            if ($new_size != $orig_size) {
+                Print::print_err(
+"Original image size ($orig_size) is not the same as the destination size ($new_size) after AFM import"
+                );
+            }
+        }
+        if ($copied == 0) {
+            Print::print_err(
+"No AFM raw files were found with the same base name and a numeric extension"
+            );
+        }
+        else {
+            print "$copied AFM raw files imported<br>\n";
+        }
+    }
+
+    Caseman::update_md5("$imgid", "$act_md5")
+      unless (($do_md5 == $MD5_NOTHING) || ($imgid eq ""));
+
+    # Add a disk entry if the image is of a disk
+    unless (($add_num == 1) && ($end[0] == 0) && ($start[0] == 0)) {
+        unless ((exists $Args::args{'vstype'})
+            && ($Args::args{'vstype'} =~ /^(\w+)$/))
+        {
+            Print::print_err("Missing Volume System Type");
+        }
+        my $vstype = $Args::args{'vstype'};
+
+        my $diskid = Caseman::add_vol_host_config("disk", "$imgid    $vstype");
+        print "<p>Disk image (type $vstype) added with ID <tt>$diskid</tt>\n";
+    }
+
+    # Add the file system / partition entries
+    for (my $i = 0; $i < $add_num; $i++) {
+        my $volid =
+          Caseman::add_vol_host_config("part",
+            "$imgid	$start[$i]  $end[$i]    $ftype[$i]  $mnt[$i]");
+        print
+"<p>Volume image ($start[$i] to $end[$i] - $ftype[$i] - $mnt[$i]) added with ID <tt>$volid</tt>\n";
+    }
+
+    print <<EOF;
+<p>
+<center>
+<table width=600>
+<tr>
+  <td width=300 align=center>
+    <a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&view=$Caseman::VOL_OPEN&${Args::baseargs_novol}\">
+    <img src=\"pict/menu_b_ok.jpg\" alt=\"Ok\" width=\"167\" height=20 border=\"0\">
+    </a>
+  </td>
+  <td width=300 align=center>
+    <a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&view=$Caseman::IMG_ADD&${Args::baseargs_novol}\">
+    <img src=\"pict/menu_b_inew.jpg\" alt=\"Ok\" width=\"167\" height=20 border=\"0\">
+    </a>
+  </td>
+</tr>
+</table>
+</center>
+
+EOF
+    Print::print_html_footer();
+
+    return 0;
+}
+
+# Display details of image based on config values
+# provides links to remove the config of the image and to get the file
+# system details
+
+sub vol_details {
+    Print::print_html_header("Details of $Args::args{'vol'}");
+
+    Args::get_unitsize();
+
+    my $vol = Args::get_vol('vol');
+
+    my $mnt   = $Caseman::vol2mnt{$vol};
+    my $ftype = $Caseman::vol2ftype{$vol};
+
+    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>$Caseman::vol2sname{$vol}</tt></td></tr>\n"
+      . "<tr><td align=\"right\" width=\"300\"><b>Volume Id:</b></td>"
+      . "<td align=\"left\"><tt>$vol</tt></td></tr>\n"
+      . "<tr><td align=\"right\" width=\"300\"><b>Parent Volume Id:</b></td>"
+      . "<td align=\"left\"><tt>$Caseman::vol2par{$vol}</tt></td></tr>\n"
+      . "<tr><td align=\"right\" width=\"300\"><b>Image File Format:</b></td>"
+      . "<td align=\"left\"><tt>$Caseman::vol2itype{$vol}</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";
+
+    # Host Directory
+    print "  <tr><td colspan=\"2\">&nbsp;</td></tr>\n"
+
+      # Strings File
+      . "  <tr><td colspan=2 align=\"center\"><b>External Files</b></td></tr>\n"
+      . "  <tr><td align=\"right\"><b>ASCII Strings:</b></td>"
+      . "<td align=\"left\"><tt>"
+      . (
+        (exists $Caseman::vol2str{$vol})
+        ? $Caseman::vol2sname{$Caseman::vol2str{$vol}}
+        : "&nbsp;"
+      )
+      . "</tt></td></tr>\n"
+      .
+
+      # Unicode Strings File
+      "  <tr><td align=\"right\"><b>Unicode Strings:</b></td>"
+      . "<td align=\"left\"><tt>"
+      . (
+        (exists $Caseman::vol2uni{$vol})
+        ? $Caseman::vol2sname{$Caseman::vol2uni{$vol}}
+        : "&nbsp;"
+      )
+      . "</tt></td></tr>\n";
+
+    if (($ftype ne "raw") && ($ftype ne "swap")) {
+
+        # blkls file
+        print
+"  <tr><td align=\"right\"><b>Unallocated $Fs::addr_unit{$ftype}s:</b></td>"
+          . "<td align=\"left\"><tt>"
+          . (
+            (exists $Caseman::vol2blkls{$vol})
+            ? $Caseman::vol2sname{$Caseman::vol2blkls{$vol}}
+            : "&nbsp;"
+          )
+          . "</tt></td></tr>\n";
+
+        # Strings of blkls
+        print
+          "  <tr><td align=\"right\"><b>ASCII Strings of Unallocated:</b></td>"
+          . "<td align=\"left\"><tt>"
+          . (
+            (
+                     (exists $Caseman::vol2blkls{$vol})
+                  && (exists $Caseman::vol2str{$Caseman::vol2blkls{$vol}})
+            )
+            ? $Caseman::vol2sname{$Caseman::vol2str{$Caseman::vol2blkls{$vol}}}
+            : "&nbsp;"
+          )
+          . "</tt></td></tr>\n";
+
+        # Unicodde Strings of blkls
+        print
+"  <tr><td align=\"right\"><b>Unicode Strings of Unallocated:</b></td>"
+          . "<td align=\"left\"><tt>"
+          . (
+            (
+                     (exists $Caseman::vol2blkls{$vol})
+                  && (exists $Caseman::vol2uni{$Caseman::vol2blkls{$vol}})
+            )
+            ? $Caseman::vol2sname{$Caseman::vol2uni{$Caseman::vol2blkls{$vol}}}
+            : "&nbsp;"
+          )
+          . "</tt></td></tr>\n";
+    }
+
+    print "  <tr><td colspan=\"2\">&nbsp;</td></tr>\n"
+      . "</table>\n<a name=\"extract\"\n";
+
+    # Section for Strings file and 'blkls' file
+
+    if (
+           (!(exists $Caseman::vol2str{$vol}))
+        || (!(exists $Caseman::vol2uni{$vol}))
+        || (!(exists $Caseman::vol2blkls{$vol}))
+        || (
+            (exists $Caseman::vol2blkls{$vol})
+            && (   (!(exists $Caseman::vol2str{$Caseman::vol2blkls{$vol}}))
+                || (!(exists $Caseman::vol2uni{$Caseman::vol2blkls{$vol}})))
+        )
+      )
+    {
+        print "<hr><table width=600>\n<tr>";
+    }
+
+    # Strings File
+    if (   (!(exists $Caseman::vol2str{$vol}))
+        || (!(exists $Caseman::vol2uni{$vol})))
+    {
+
+        print
+"<td align=\"center\" width=280><h3>Extract Strings of<br>Entire Volume</h3>"
+          . "Extracting the ASCII and Unicode strings from a file system will "
+          . "make keyword searching faster.<br><br>\n"
+          . "<form action=\"$::PROGNAME\" method=\"get\">\n"
+          . "Generate MD5? "
+          . "<input type=\"checkbox\" name=\"md5\" value=\"1\" CHECKED><br><br>"
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_MAKESTR\">\n"
+          . "<input type=\"hidden\" name=\"vol\" value=\"$Args::args{'vol'}\">\n"
+          . Args::make_hidden();
+
+        if (!(exists $Caseman::vol2str{$vol})) {
+            print
+"ASCII: <input type=\"checkbox\" name=\"str\" value=\"1\" CHECKED>  \n";
+        }
+        if (!(exists $Caseman::vol2uni{$vol})) {
+            print
+"  Unicode: <input type=\"checkbox\" name=\"uni\" value=\"1\" CHECKED>\n";
+        }
+
+        print "<br><br><input type=\"image\" src=\"pict/srch_b_str.jpg\" "
+          . "alt=\"Extract Strings\" border=\"0\">\n</form></td>\n"
+          . "<td width=40>&nbsp;</td>\n";
+    }
+
+    if (($ftype eq 'blkls') || ($ftype eq 'swap') || ($ftype eq 'raw')) {
+
+        # Place holder for types that have no notion of unallocated
+    }
+
+    # Unallocated Space File
+    elsif (!(exists $Caseman::vol2blkls{$vol})) {
+
+        print
+"<td align=\"center\" width=280><h3>Extract Unallocated $Fs::addr_unit{$ftype}s</h3>"
+          . "Extracting the unallocated data in a file system allows "
+          . "more focused keyword searches and data recovery.<br><br>\n"
+          . "(Note: This Does Not Include Slack Space)<br>\n"
+          . "<form action=\"$::PROGNAME\" method=\"get\">\n";
+
+        print "Generate MD5? "
+          . "<input type=\"checkbox\" name=\"md5\" value=\"1\" CHECKED><br><br>"
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_MAKEBLKLS\">\n"
+          .
+
+          "<input type=\"hidden\" name=\"vol\" value=\"$Args::args{'vol'}\">\n"
+          . Args::make_hidden()
+          . "<input type=\"image\" src=\"pict/srch_b_un.jpg\" "
+          . "alt=\"Extract Unallocated Data\" border=\"0\">\n<br></form>\n";
+    }
+
+    # strings of 'blkls'
+    elsif ((!(exists $Caseman::vol2str{$Caseman::vol2blkls{$vol}}))
+        || (!(exists $Caseman::vol2uni{$Caseman::vol2blkls{$vol}})))
+    {
+
+        print
+"<td align=\"center\" width=280><h3>Extract Strings of<br>Unallocated $Fs::addr_unit{$ftype}s</h3>"
+          . "Extracting the ASCII strings from the unallocated data will make "
+          . "keyword searching faster.<br><br>\n"
+          . "<form action=\"$::PROGNAME\" method=\"get\">\n"
+          . "Generate MD5? "
+          . "<input type=\"checkbox\" name=\"md5\" value=\"1\" CHECKED><br><br>"
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_MAKESTR\">\n"
+          .
+
+"<input type=\"hidden\" name=\"vol\" value=\"$Caseman::vol2blkls{$vol}\">\n"
+          . "<input type=\"hidden\" name=\"fname_mode\" value=\"$FNAME_MODE_INIT\">\n"
+          . Args::make_hidden();
+
+        if (!(exists $Caseman::vol2str{$Caseman::vol2blkls{$vol}})) {
+            print
+"ASCII: <input type=\"checkbox\" name=\"str\" value=\"1\" CHECKED>  \n";
+        }
+        if (!(exists $Caseman::vol2uni{$Caseman::vol2blkls{$vol}})) {
+            print
+"  Unicode: <input type=\"checkbox\" name=\"uni\" value=\"1\" CHECKED>\n";
+        }
+        print "<br><br><input type=\"image\" src=\"pict/srch_b_str.jpg\" "
+          . "alt=\"Extract Strings\" border=\"0\">\n</form></td>\n";
+    }
+    if (
+           (!(exists $Caseman::vol2str{$vol}))
+        || (!(exists $Caseman::vol2uni{$vol}))
+        || (!(exists $Caseman::vol2blkls{$vol}))
+        || (
+            (exists $Caseman::vol2blkls{$vol})
+            && (   (!(exists $Caseman::vol2str{$Caseman::vol2blkls{$vol}}))
+                || (!(exists $Caseman::vol2uni{$Caseman::vol2blkls{$vol}})))
+        )
+      )
+    {
+        print "</tr></table><hr>\n";
+    }
+
+    print "<p>"
+      . "<table width=\"400\" cellspacing=\"0\" cellpadding=\"2\">\n"
+      .
+
+      # Ok
+      "<tr><td align=center width=200>"
+      . "<form action=\"$::PROGNAME\" method=\"get\">\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_OPEN\">\n"
+      . Args::make_hidden()
+      . "<input type=\"image\" src=\"pict/menu_b_close.jpg\" "
+      . "alt=\"Close\" width=\"167\" height=20 border=0></form></td>\n";
+
+    print "<td align=center width=200>";
+    if (($ftype ne "raw") && ($ftype ne "swap")) {
+
+        # File System Details
+        print "<form action=\"$::PROGNAME\" method=\"get\" target=\"_blank\">\n"
+          . Args::make_hidden()
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_FRAME\">\n"
+          . "<input type=\"hidden\" name=\"submod\" value=\"$::MOD_FS\">\n"
+          . "<input type=\"hidden\" name=\"vol\" value=\"$vol\">\n"
+          . "<input type=\"image\" src=\"pict/menu_b_fs.jpg\" "
+          . "width=167 height=20 "
+          . "alt=\"File System\" border=0></form></td>\n";
+    }
+    else {
+        print "&nbsp;</td>\n";
+    }
+
+# Remove Image
+# THis was removed 12/03 because it causes problems because the image still
+# exists and config entries and ... it becomes a mess
+#	print
+#	  "<td align=center width=200>".
+#	  "<form action=\"$::PROGNAME\" method=\"get\">\n".
+#          "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n".
+#          "<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_DEL\">\n".
+#	  Args::make_hidden().
+#          "<input type=\"hidden\" name=\"vol\" value=\"$Args::args{'vol'}\">\n".
+#          "<input type=\"hidden\" name=\"mnt\" value=\"$Args::args{'mnt'}\">\n".
+#	  "<input type=\"image\" src=\"pict/menu_b_rem.jpg\" ".
+#	  "width=167 height=20 alt=\"Remove\" border=0></form>".
+#          "</td>\n".
+#	  "</tr></table>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# remove the config files
+sub img_del {
+    Args::check_vol('vol');
+
+    # Args::check_ftype();
+    Print::print_html_header(
+        "Removing Configuration Settings for $Args::args{'vol'}");
+
+    Caseman::del_host_config("", $Args::args{'vol'}, "");
+    Caseman::update_md5($Args::args{'vol'}, "");
+
+    print "Settings for <tt>$Args::args{'vol'}</tt> removed from "
+      . "<tt>$Args::args{'case'}:$Args::args{'host'}</tt>.\n"
+      . "<p>NOTE: The actual file still exists in the host directory.\n";
+
+    print "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
+      . "view=$Caseman::VOL_OPEN&${Args::baseargs_novol}\">"
+      . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
+      . "width=\"43\" height=20 border=\"0\"></a>\n";
+
+    Print::print_html_footer();
+
+    return 0;
+}
+
+# Make a strings -t d file for the image to decrease the search time
+# Can make both ASCII and Unicode strings files
+sub vol_makestr {
+    Print::print_html_header("Extracting Strings");
+
+    my $ascii = 0;
+    my $uni   = 0;
+
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    if ((exists $Args::args{'str'}) && ($Args::args{'str'} == 1)) {
+        if (exists $Caseman::vol2str{$vol}) {
+            Print::print_err(
+"Image already has an ASCII strings file: $Caseman::vol2sname{$vol}"
+            );
+        }
+        $ascii = 1;
+    }
+
+    if ((exists $Args::args{'uni'}) && ($Args::args{'uni'} == 1)) {
+        if (exists $Caseman::vol2uni{$vol}) {
+            Print::print_err(
+"Image already has a Unicode strings file: $Caseman::vol2sname{$vol}"
+            );
+        }
+
+        $uni = 1;
+    }
+    if (($uni == 0) && ($ascii == 0)) {
+        goto str_egress;
+    }
+
+    my $base_name = $Caseman::vol2sname{$vol};
+
+    if ($ascii == 1) {
+        my $fname_rel = "$::DATADIR/${base_name}-$ftype.asc";
+        my $fname     = "$::host_dir" . "$fname_rel";
+
+        if (-e "$fname") {
+            my $i = 1;
+            $i++ while (-e "$::host_dir"
+                . "$::DATADIR/"
+                . "${base_name}-$ftype-$i.asc");
+
+            $fname_rel = "$::DATADIR/${base_name}-$ftype-$i.asc";
+            $fname     = "$::host_dir" . "$fname_rel";
+        }
+
+        print
+"Extracting ASCII strings from <tt>$Caseman::vol2sname{$vol}</tt><br>\n";
+
+        Print::log_host_inv(
+            "$Caseman::vol2sname{$vol}: Saving ASCII strings to $fname_rel");
+
+        local *OUT;
+
+        my $hit_cnt = 0;
+        $SIG{ALRM} = sub {
+            if (($hit_cnt++ % 5) == 0) {
+                print "+";
+            }
+            else {
+                print "-";
+            }
+            alarm(5);
+        };
+
+        alarm(5);
+
+        if ($ftype eq "blkls") {
+            Exec::exec_pipe(*OUT,
+                "'$::TSKDIR/srch_strings' -a -t d $img > '$fname'");
+        }
+        elsif ((($ftype eq "raw") || ($ftype eq "swap"))
+            && ($Caseman::vol2end{$vol} != 0))
+        {
+            Exec::exec_pipe(*OUT,
+                    "'$::TSKDIR/blkls' -e -f $ftype -i $imgtype $img "
+                  . $Caseman::vol2start{$vol} . "-"
+                  . $Caseman::vol2end{$vol}
+                  . " | '$::TSKDIR/srch_strings' -a -t d > '$fname'");
+        }
+        else {
+            Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkls' -e -f $ftype -o $offset -i $imgtype $img | '$::TSKDIR/srch_strings' -a -t d > '$fname'"
+            );
+        }
+        alarm(0);
+        $SIG{ALRM} = 'DEFAULT';
+
+        print $_ while ($_ = Exec::read_pipe_line(*OUT));
+        close(OUT);
+
+        print "<br>\n" if ($hit_cnt != 0);
+
+        # 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<br>");
+            goto str_uni;
+        }
+
+        # append to config
+        my $strvol =
+          Caseman::add_vol_host_config("strings", "$vol   $fname_rel");
+        print "Host configuration file updated<br>";
+
+        $Caseman::vol2ftype{$strvol} = "strings";
+        $Caseman::mod2vol{$strvol}   = $vol;
+        $Caseman::vol2str{$vol}      = $strvol;
+        $Caseman::vol2cat{$strvol}   = "mod";
+        $Caseman::vol2itype{$strvol} = "raw";
+
+        $Caseman::vol2par{$strvol}   = $vol;
+        $Caseman::vol2path{$strvol}  = "$::host_dir" . "$fname_rel";
+        $Caseman::vol2start{$strvol} = 0;
+        $Caseman::vol2end{$strvol}   = 0;
+        $Caseman::vol2sname{$strvol} = $fname_rel;
+
+        # Calculate MD5
+        if ((exists $Args::args{'md5'}) && ($Args::args{'md5'} == 1)) {
+            print "Calculating MD5 Value<br><br>\n";
+            my $m = Hash::int_create_wrap($strvol);
+            print "MD5 Value: <tt>$m</tt><br><br>\n";
+        }
+    }
+
+  str_uni:
+
+    if ($uni == 1) {
+
+        my $fname_rel = "$::DATADIR/${base_name}-$ftype.uni";
+        my $fname     = "$::host_dir" . "$fname_rel";
+
+        if (-e "$fname") {
+            my $i = 1;
+            $i++ while (-e "$::host_dir"
+                . "$::DATADIR/"
+                . "${base_name}-$ftype-$i.uni");
+
+            $fname_rel = "$::DATADIR/${base_name}-$ftype-$i.uni";
+            $fname     = "$::host_dir" . "$fname_rel";
+        }
+
+        print "<hr>\n" if ($ascii == 1);
+
+        print
+"Extracting Unicode strings from <tt>$Caseman::vol2sname{$vol}</tt><br>\n";
+
+        Print::log_host_inv(
+            "$Caseman::vol2sname{$vol}: Saving Unicode strings to $fname_rel");
+
+        local *OUT;
+
+        my $hit_cnt = 0;
+        $SIG{ALRM} = sub {
+            if (($hit_cnt++ % 5) == 0) {
+                print "+";
+            }
+            else {
+                print "-";
+            }
+            alarm(5);
+        };
+
+        alarm(5);
+        if ($ftype eq "blkls") {
+            Exec::exec_pipe(*OUT,
+                "'$::TSKDIR/srch_strings' -a -t d -e l $img > '$fname'");
+        }
+        elsif ((($ftype eq "raw") || ($ftype eq "swap"))
+            && ($Caseman::vol2end{$vol} != 0))
+        {
+            Exec::exec_pipe(*OUT,
+                    "'$::TSKDIR/blkls' -e -f $ftype -i $imgtype $img "
+                  . $Caseman::vol2start{$vol} . "-"
+                  . $Caseman::vol2end{$vol}
+                  . " | '$::TSKDIR/srch_strings' -a -t d -e l > '$fname'");
+        }
+
+        else {
+            Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkls' -e -f $ftype -o $offset -i $imgtype $img | '$::TSKDIR/srch_strings' -a -t d -e l  > '$fname'"
+            );
+        }
+
+        alarm(0);
+        $SIG{ALRM} = 'DEFAULT';
+
+        print $_ while ($_ = Exec::read_pipe_line(*OUT));
+        close(OUT);
+
+        print "<br>\n" if ($hit_cnt != 0);
+
+        # Verify that it worked
+        unless (open(STR, "$fname")) {
+            print "Error opening $fname<br>\n"
+              . "Either an error occurred while generating the file or "
+              . "no Unicode strings exist";
+            goto str_egress;
+        }
+
+        # append to config
+        my $strvol =
+          Caseman::add_vol_host_config("unistrings", "$vol    $fname_rel");
+        print "Host configuration file updated<br>";
+
+        $Caseman::vol2ftype{$strvol} = "strings";
+        $Caseman::mod2vol{$strvol}   = $vol;
+        $Caseman::vol2uni{$vol}      = $strvol;
+        $Caseman::vol2cat{$strvol}   = "mod";
+        $Caseman::vol2itype{$strvol} = "raw";
+
+        $Caseman::vol2par{$strvol}   = $vol;
+        $Caseman::vol2path{$strvol}  = "$::host_dir" . "$fname_rel";
+        $Caseman::vol2start{$strvol} = 0;
+        $Caseman::vol2end{$strvol}   = 0;
+        $Caseman::vol2sname{$strvol} = $fname_rel;
+
+        # Calculate MD5
+        if ((exists $Args::args{'md5'}) && ($Args::args{'md5'} == 1)) {
+            print "Calculating MD5 Value<br><br>\n";
+            $m = Hash::int_create_wrap($strvol);
+            print "MD5 Value: <tt>$m</tt><br><br>\n";
+        }
+    }
+
+  str_egress:
+
+    my $dest_vol = $vol;
+
+    # We need to return with a real image to VOL_DETAILS so check the mod
+    $dest_vol = $Caseman::mod2vol{$vol}
+      if (exists $Caseman::mod2vol{$vol});
+
+    print "<hr><a href=\"$::PROGNAME?$Args::baseargs_novol&mod=$::MOD_CASEMAN&"
+      . "view=$Caseman::VOL_DETAILS&vol=$dest_vol\" target=_top>Image Details</a><p>\n";
+
+    print
+"<a href=\"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_KWSRCH&$Args::baseargs\""
+      . " target=\"_top\">Keyword Search</a>\n";
+
+    Print::print_html_footer();
+
+    return 0;
+}
+
+sub vol_makeblkls {
+    Print::print_html_header("Extracting Unallocated Space");
+
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $base_name = $Caseman::vol2sname{$vol};
+    $base_name = $1 if ($base_name =~ /^(.*?)\.dd$/);
+    my $fname_rel = "$::DATADIR/${base_name}-$ftype.unalloc";
+    my $fname     = "$::host_dir" . "$fname_rel";
+
+    if (-e "$::host_dir" . "$fname_rel") {
+        my $i = 1;
+        $i++ while (-e "$::host_dir"
+            . "$::DATADIR/"
+            . "${base_name}-$ftype-$i.unalloc");
+
+        $fname_rel = "$::DATADIR/${base_name}-$ftype-$i.unalloc";
+        $fname     = "$::host_dir" . "$fname_rel";
+    }
+
+    Print::log_host_inv(
+        "$Args::args{'vol'}: Saving unallocated data to $fname_rel");
+
+    print
+"Extracting unallocated data from <tt>$Caseman::vol2sname{$vol}</tt><br>\n";
+
+    local *OUT;
+
+    my $hit_cnt = 0;
+    $SIG{ALRM} = sub {
+        if (($hit_cnt++ % 5) == 0) {
+            print "+";
+        }
+        else {
+            print "-";
+        }
+        alarm(5);
+    };
+
+    alarm(5);
+
+    Exec::exec_pipe(*OUT,
+        "'$::TSKDIR/blkls' -f $ftype  -o $offset -i $imgtype $img > '$fname'");
+
+    alarm(0);
+    $SIG{ALRM} = 'DEFAULT';
+
+    print "$_" while ($_ = Exec::read_pipe_line(*OUT));
+    close(OUT);
+
+    print "<br>\n"
+      if ($hit_cnt != 0);
+
+    # append to config
+    my $blklsvol = Caseman::add_vol_host_config("blkls", "$vol    $fname_rel");
+    print "Host configuration file updated<br>";
+
+    $Caseman::vol2ftype{$blklsvol} = "blkls";
+    $Caseman::mod2vol{$blklsvol}   = $vol;
+    $Caseman::vol2blkls{$vol}      = $blklsrvol;
+    $Caseman::vol2cat{$blklsvol}   = "mod";
+    $Caseman::vol2itype{$blklsvol} = "raw";
+
+    $Caseman::vol2par{$blklsvol}   = $vol;
+    $Caseman::vol2path{$blklsvol}  = "$::host_dir" . "$fname_rel";
+    $Caseman::vol2start{$blklsvol} = 0;
+    $Caseman::vol2end{$blklsvol}   = 0;
+    $Caseman::vol2sname{$blklsvol} = $fname_rel;
+
+    # Calculate MD5
+    if ((exists $Args::args{'md5'}) && ($Args::args{'md5'} == 1)) {
+        print "Calculating MD5 Value<br>\n";
+        my $m = Hash::int_create_wrap($blklsvol);
+        print "MD5 Value: <tt>$m</tt><br><br>\n";
+    }
+
+    print "<a href=\"$::PROGNAME?$Args::baseargs&mod=$::MOD_CASEMAN&"
+      . "view=$Caseman::VOL_DETAILS\" target=_top>Image Details</a><p>\n";
+
+    print
+"<a href=\"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_KWSRCH&$Args::baseargs_novol&"
+      . "vol=$fname_rel\" target=\"_top\">Keyword Search</a>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+1;
diff --git a/lib/Data.pm b/lib/Data.pm
new file mode 100644
index 0000000000000000000000000000000000000000..f8e2ef43fe671acd6661ed2634f6591dd56a8de3
--- /dev/null
+++ b/lib/Data.pm
@@ -0,0 +1,927 @@
+#
+# Data / Content layer functions
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2005 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 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.
+
+package Data;
+
+$Data::FRAME        = 1;
+$Data::ENTER        = 2;
+$Data::CONT         = 3;
+$Data::CONT_MENU    = 4;
+$Data::CONT_MENU_FR = 5;
+$Data::REPORT       = 6;
+$Data::LIST         = 7;
+$Data::EXPORT       = 8;
+$Data::BLANK        = 9;
+
+# Display types that use the sort variable
+$Data::SORT_ASC = 0;
+$Data::SORT_HEX = 1;
+$Data::SORT_STR = 2;
+
+# Types of block numbers
+$Data::ADDR_DD    = 0;
+$Data::ADDR_BLKLS = 1;
+
+sub main {
+
+    # By default, show the main frame
+    $Args::args{'view'} = $Args::enc_args{'view'} = $Data::FRAME
+      unless (exists $Args::args{'view'});
+
+    Args::check_view();
+    my $view = Args::get_view();
+
+    # Check Basic Args
+    Args::check_vol('vol');
+
+    # These windows don't need the data unit address
+    if ($view == $Data::FRAME) {
+        return frame();
+    }
+    elsif ($view == $Data::ENTER) {
+        return enter();
+    }
+    elsif ($view == $Data::LIST) {
+        return list();
+    }
+    elsif ($view == $Data::BLANK) {
+        return blank();
+    }
+
+    # These windows do need the data unit address
+    Args::check_block();
+    if ($view == $Data::CONT) {
+        return content();
+    }
+    elsif ($view == $Data::CONT_MENU) {
+        return content_menu();
+    }
+    elsif ($view == $Data::CONT_MENU_FR) {
+        return content_menu_frame();
+    }
+    elsif ($view == $Data::REPORT) {
+        return report();
+    }
+
+    elsif ($view == $Data::EXPORT) {
+        return export();
+    }
+    else {
+        Print::print_check_err("Invalid Data View");
+    }
+
+}
+
+# Generate the 2 frames for block browsing
+sub frame {
+    Print::print_html_header_frameset("Data Browse on $Args::args{'vol'}");
+
+    print "<frameset cols=\"20%,80%\">\n";
+
+    # Data Contents
+    if (exists $Args::args{'block'}) {
+        my $len = Args::get_len();
+
+        print "<frame src=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::ENTER&"
+          . "$Args::baseargs&block=$Args::enc_args{'block'}\">\n"
+          . "<frame src=\"$::PROGNAME?"
+          . "mod=$::MOD_DATA&view=$Data::CONT_MENU_FR&"
+          . "block=$Args::enc_args{'block'}&$Args::baseargs&len=$len\" "
+          . "name=\"content\">\n</frameset>\n";
+    }
+    else {
+        print "<frame src=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::ENTER&"
+          . "$Args::baseargs\">\n"
+          . "<frame src=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::BLANK&"
+          . "$Args::baseargs\" name=\"content\">\n</frameset>\n";
+    }
+
+    Print::print_html_footer_frameset();
+    return 0;
+}
+
+# Frame to enter the data into
+sub enter {
+    Print::print_html_header("");
+
+    my $vol   = Args::get_vol('vol');
+    my $ftype = $Caseman::vol2ftype{$vol};
+    my $bs    = Args::get_unitsize();
+
+    print "<form action=\"$::PROGNAME\" method=\"get\" "
+      . "target=\"content\">\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_DATA\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Data::CONT_MENU_FR\">\n"
+      . "<input type=\"hidden\" name=\"vol\" value=\"$vol\">\n"
+      . Args::make_hidden()
+      .
+
+      # Address
+      "<b>$Fs::addr_unit{$ftype} Number:</b><br>&nbsp;&nbsp;&nbsp;&nbsp;"
+      . "<input type=\"text\" name=\"block\" size=12 maxlength=12";
+    print " value=\"$Args::enc_args{'block'}\""
+      if (exists $Args::args{'block'});
+    print ">\n";
+
+    # Number of units
+    print "<p><b>Number of $Fs::addr_unit{$ftype}" . "s:</b>"
+      . "<br>&nbsp;&nbsp;&nbsp;&nbsp;"
+      . "<input type=\"text\" name=\"len\" value=\"1\" size=6 maxlength=6>\n";
+
+    print "<p><b>$Fs::addr_unit{$ftype} Size:</b>" . "&nbsp;$bs\n";
+
+    # blkls images do not get to select this
+    # if (($ftype ne 'blkls') && ($ftype ne 'swap') && ($ftype ne 'raw')) {
+    if ($Fs::is_fs{$ftype} == 1) {
+        print "<p><b>Address Type:</b><br>&nbsp;&nbsp;&nbsp;&nbsp;"
+          . "<select name=\"btype\" size=1>\n"
+          . "<option value=\"$Data::ADDR_DD\" selected>Regular (dd)</option>\n"
+          . "<option value=\"$Data::ADDR_BLKLS\">Unallocated (blkls)</option>\n"
+          . "</select>\n";
+    }
+    else {
+        print
+          "<input type=\"hidden\" name=\"btype\" value=\"$Data::ADDR_DD\">\n";
+    }
+
+    # Lazarus
+    print "<p><b>Lazarus Addr:</b> "
+      . "<input type=\"checkbox\" name=\"btype2\">\n"
+      . "<p><input type=\"image\" src=\"pict/but_view.jpg\" "
+      . "width=45 height=22 alt=\"View\" border=\"0\">\n"
+      . "</form>\n";
+
+    print "<hr><p>"
+      . "<a href=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::LIST&$Args::baseargs\" target=\"content\">"
+      . "<img src=\"pict/but_alloc_list.jpg\" border=\"0\" "
+      . "width=113 height=20 alt=\"Allocation List\"></a><br>\n"
+      if ($Fs::is_fs{$ftype} == 1);
+
+ #      unless (($ftype eq 'blkls') || ($ftype eq 'swap') || ($ftype eq 'raw'));
+
+    # If there is a blkls image, then provide a button for it
+    if (($ftype ne 'blkls') && (exists $Caseman::vol2blkls{$vol})) {
+        print "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_FRAME\">\n"
+          . "<input type=\"hidden\" name=\"submod\" value=\"$::MOD_DATA\">\n"
+          . "<input type=\"hidden\" name=\"vol\" value=\"$Caseman::vol2blkls{$vol}\">\n"
+          . Args::make_hidden()
+          . "<p><input type=\"image\" src=\"pict/srch_b_lun.jpg\" "
+          . "alt=\"Load Unallocated Image\" border=\"0\">\n<br></form>\n";
+    }
+
+    # If we are using a blkls image, then give a button for the original
+    elsif (($ftype eq 'blkls') && (exists $Caseman::mod2vol{$vol})) {
+        print "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_FRAME\">\n"
+          . "<input type=\"hidden\" name=\"submod\" value=\"$::MOD_DATA\">\n"
+          . "<input type=\"hidden\" name=\"vol\" value=\"$Caseman::mod2vol{$vol}\">\n"
+          . Args::make_hidden()
+          . "<p><input type=\"image\" src=\"pict/srch_b_lorig.jpg\" "
+          . "alt=\"Load Original Image\" border=\"0\">\n<br></form>\n";
+    }
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# generate frame for block content
+sub content_menu_frame {
+    Print::print_html_header_frameset("");
+
+    my $sort = $Data::SORT_ASC;
+    $sort = $1
+      if ((exists $Args::args{'sort'}) && ($Args::args{'sort'} =~ /^(\d+)$/));
+
+    my $len = Args::get_len();
+    if ($len == 0) {
+        Print::print_err("Invalid length: 0");
+    }
+
+    my $blk;
+
+    my $ifind = Args::get_ifind();
+
+    # off is 1 if a lazarus block number as they are off by one
+    my $off = 0;
+    $off = -1 if (exists $Args::args{'btype2'});
+
+    # Do we need to convert from blkls value to dd value ?
+    if (   (exists $Args::args{'btype'})
+        && ($Args::args{'btype'} == $Data::ADDR_BLKLS))
+    {
+
+        my $vol     = Args::get_vol('vol');
+        my $b       = Args::get_block() + $off;
+        my $ftype   = $Caseman::vol2ftype{$vol};
+        my $img     = $Caseman::vol2path{$vol};
+        my $offset  = $Caseman::vol2start{$vol};
+        my $imgtype = $Caseman::vol2itype{$vol};
+
+        local *OUT;
+        Exec::exec_pipe(*OUT,
+            "'$::TSKDIR/blkcalc' -f $ftype -u $b -o $offset -i $imgtype $img");
+        $blk = Exec::read_pipe_line(*OUT);
+        close(OUT);
+
+        $blk = "Error getting block"
+          if ((!defined $blk) || ($blk eq ""));
+
+        if ($blk !~ /^\d+$/) {
+            print "$blk\n";
+            return 1;
+        }
+    }
+    else {
+        $blk = Args::get_block() + $off;
+    }
+
+    print "<frameset rows=\"25%,75%\">\n"
+      . "<frame src=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::CONT_MENU&$Args::baseargs"
+      . "&block=$blk&sort=$sort&len=$len&ifind=$ifind\">\n"
+      . "<frame src=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::CONT&$Args::baseargs"
+      . "&block=$blk&sort=$sort&len=$len\" name=\"cont2\">\n"
+      . "</frameset>";
+
+    Print::print_html_footer_frameset();
+    return 0;
+}
+
+sub print_ifind {
+    my $block = Args::get_block();
+
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    Print::log_host_inv(
+"$Caseman::vol2sname{$vol}: Finding $Fs::meta_str{$ftype} for data unit $block"
+    );
+
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+        "'$::TSKDIR/ifind' -f $ftype -d $block -o $offset -i $imgtype $img");
+    my $meta = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $meta = "Error getting meta address"
+      if ((!defined $meta) || ($meta eq ""));
+
+    if ($meta =~ /^($::REG_META)$/o) {
+        $meta = $1;
+        my $tmpr = $Caseman::vol2mnt{$vol};
+        print "<b>Pointed to by $Fs::meta_str{$ftype}:</b> "
+          . "<a href=\"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_META&$Args::baseargs&"
+          . "meta=$meta\" target=\"_top\">$meta</a><br>\n";
+
+        print "<b>Pointed to by file:</b>\n";
+        Exec::exec_pipe(*OUT,
+            "'$::TSKDIR/ffind' -f $ftype -a -o $offset -i $imgtype $img $meta");
+        while ($_ = Exec::read_pipe_line(*OUT)) {
+            chop;
+
+            # Make it red if it is deleted
+            if (/^(\*)\s+\/*(.*)$/) {
+                Print::print_output("<tt><font color=\"$::DEL_COLOR[0]\">"
+                      . Print::html_encode(${tmpr} . ${2})
+                      . "</font></tt> (deleted)<br>\n");
+            }
+
+            # If it starts with a '/' then it must be a file
+            elsif (/^\/(.*)$/) {
+                Print::print_output("<tt>"
+                      . Print::html_encode(${tmpr} . ${1})
+                      . "</tt><br>\n");
+            }
+
+            # this must be an error
+            else {
+                Print::print_output(Print::html_encode($_) . "<br>\n");
+            }
+        }
+        close(OUT);
+    }
+    else {
+        print "$meta\n";
+    }
+}
+
+# Generate index for block content
+sub content_menu {
+    Print::print_html_header("");
+
+    my $block = Args::get_block();
+    my $prev  = $block - 1;
+    my $next  = $block + 1;
+
+    my $sort    = Args::get_sort();
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $ifind = Args::get_ifind();
+
+    my $len = Args::get_len();
+    my $bs  = Args::get_unitsize();
+
+    if ($len == 0) {
+        Print::print_err("Invalid length: 0");
+    }
+
+    print "<center>";
+    my $url =
+        "$::PROGNAME?mod=$::MOD_DATA&view=$Data::CONT_MENU_FR&"
+      . "$Args::baseargs&sort=$sort&len=$len"
+      . "&ifind=$ifind";
+
+    # Next and Previous pointers
+    print "<table cellspacing=\"0\" cellpadding=\"2\">\n" . "<tr>\n";
+
+    # Previous
+    if ($prev < $Fs::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\" height=20 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\" height=20 border=\"0\"></a></td>\n</tr>\n";
+
+    print "<tr><td align=\"right\"><a href=\"$::PROGNAME?"
+      . "mod=$::MOD_DATA&view=$Data::EXPORT&$Args::baseargs&"
+      . "block=$block&len=$len\">"
+      . "<img src=\"pict/but_export.jpg\" border=\"0\" alt=\"Export\" "
+      . "width=123 height=20></a></td>\n";
+
+    if ($::USE_NOTES == 1) {
+        print "<td align=\"left\">"
+          . "<a href=\"$::PROGNAME?mod=$::MOD_NOTES&view=$Notes::ENTER_DATA&$Args::baseargs&block=$block&len=$len\" "
+          . "target=\"_blank\">"
+          . "<img src=\"pict/but_addnote.jpg\" border=\"0\" "
+          . "width=\"89\" height=20 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 == $Data::SORT_ASC) {
+        print "display - ";
+    }
+    else {
+        print "<a href=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::CONT_MENU_FR&"
+          . "$Args::baseargs&"
+          . "sort=$Data::SORT_ASC&block=$block&len=$len\" target=\"_parent\">"
+          . "display</a> - \n";
+    }
+
+    print "<a href=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::REPORT&"
+      . "$Args::baseargs&sort=$Data::SORT_ASC"
+      . "&block=$block&len=$len\" target=\"_blank\">report</a>)</td>\n"
+      . "<td>*</td>\n";
+
+    print "<td>Hex (";
+    if ($sort == $Data::SORT_HEX) {
+        print "display - ";
+    }
+    else {
+        print "<a href=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::CONT_MENU_FR&"
+          . "$Args::baseargs&"
+          . "sort=$Data::SORT_HEX&block=$block&len=$len\" target=\"_parent\">"
+          . "display</a> - \n";
+    }
+
+    print "<a href=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::REPORT&"
+      . "$Args::baseargs&sort=$Data::SORT_HEX"
+      . "&block=$block&len=$len\" target=\"_blank\">report</a>)</td>\n"
+      . "<td>*</td>\n";
+
+    print "<td>ASCII Strings (";
+    if ($sort == $Data::SORT_STR) {
+        print "display - ";
+    }
+    else {
+        print "<a href=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::CONT_MENU_FR&"
+          . "$Args::baseargs&"
+          . "sort=$Data::SORT_STR&block=$block&len=$len\" target=\"_parent\">"
+          . "display</a> - \n";
+    }
+
+    print "<a href=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::REPORT&"
+      . "$Args::baseargs&sort=$Data::SORT_STR"
+      . "&block=$block&len=$len\" target=\"_blank\">report</a>)</td>\n"
+      . "</tr></table>\n";
+
+    # Special case for 'blkls' b.c. we need to specify original data unit size
+    local *OUT;
+    if ($ftype eq 'blkls') {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $ftype -u $bs  -o $offset -i $imgtype $img $block | '$::FILE_EXE' -z -b -"
+        );
+    }
+    else {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $ftype  -o $offset -i $imgtype $img $block | '$::FILE_EXE' -z -b -"
+        );
+    }
+    my $file_type = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $file_type = "Error getting file type"
+      if ((!defined $file_type) || ($file_type eq ""));
+
+    print "<b>File Type:</b> $file_type<br></center>\n";
+
+    if ($len == 1) {
+        print "<b>$Fs::addr_unit{$ftype}:</b> $block<br>\n";
+    }
+    else {
+        my $end = $block + $len - 1;
+        print "<b>$Fs::addr_unit{$ftype}" . "s:</b> $block-$end<br>\n";
+    }
+    if ($Fs::is_fs{$ftype} == 1) {
+
+        Exec::exec_pipe(*OUT,
+            "'$::TSKDIR/blkstat' -f $ftype  -o $offset -i $imgtype $img $block"
+        );
+
+        my $cnt = 0;
+        while ($_ = Exec::read_pipe_line(*OUT)) {
+
+            if ($_ =~ /((Not )?Allocated)/) {
+                print "<font color=\"$::DEL_COLOR[0]\">" if (defined $2);
+                print "<b>Status:</b> $1<br>";
+                print "</font>" if (defined $2);
+            }
+            elsif ($_ =~ /Group: (\d+)/) {
+                print "<b>Group:</b> $1<br>\n";
+            }
+            $cnt++;
+        }
+        close(OUT);
+        if ($cnt == 0) {
+            print "Invalid $Fs::addr_unit{$ftype} address<br>\n";
+            return;
+        }
+
+        # Make ifind an option
+        $url =
+            "$::PROGNAME?mod=$::MOD_DATA&view=$Data::CONT_MENU&"
+          . "$Args::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();
+        }
+    }
+
+    # Option to view original if it exists
+    if (   ($ftype eq 'blkls')
+        && (exists $Caseman::mod2vol{$vol}))
+    {
+        print "<a href=\"$::PROGNAME?mod=$::MOD_DATA&"
+          . "view=$Data::CONT_MENU_FR&${Args::baseargs_novol}"
+          . "&vol=$Caseman::mod2vol{$vol}&"
+          . "block=$block&sort=$sort&len=$len&btype=$Data::ADDR_BLKLS\" "
+          . "target=\"_parent\">View Original</a><br>\n";
+    }
+
+    Print::print_html_footer();
+    return 0;
+}
+
+#Display actual block content
+sub content {
+    Args::check_sort();
+
+    Print::print_text_header();
+
+    my $sort    = Args::get_sort();
+    my $block   = Args::get_block();
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $len = Args::get_len();
+    my $bs  = Args::get_unitsize();
+
+    my $range = "";
+    if ($len == 0) {
+        print "Invalid length: 0\n";
+        exit(1);
+    }
+    elsif ($len == 1) {
+        $range = "$Fs::addr_unit{$ftype} $block";
+    }
+    else {
+        my $end = $block + $len - 1;
+        $range = "$Fs::addr_unit{$ftype}" . "s $block-$end";
+    }
+    my $str     = "Contents of $range in $Caseman::vol2sname{$vol}\n\n\n";
+    my $log_str = "contents of $range";
+
+    my $usize_str = "";
+    $usize_str = " -u $bs "
+      if ($ftype eq 'blkls');
+
+    local *OUT;
+    if ($sort == $Data::SORT_HEX) {
+        print "Hex " . $str;
+        Print::log_host_inv(
+            "$Caseman::vol2sname{$vol}: Displaying Hex $log_str");
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $ftype $usize_str -h -o $offset -i $imgtype $img $block $len"
+        );
+    }
+    elsif ($sort == $Data::SORT_ASC) {
+        print "ASCII " . $str;
+        Print::log_host_inv(
+            "$Caseman::vol2sname{$vol}: Displaying ASCII $log_str");
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $ftype $usize_str -a -o $offset -i $imgtype $img $block $len"
+        );
+    }
+    elsif ($sort == $Data::SORT_STR) {
+        print "ASCII String " . $str;
+        Print::log_host_inv(
+            "$Caseman::vol2sname{$vol}: Displaying string $log_str");
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $ftype $usize_str -o $offset -i $imgtype $img $block $len | '$::TSKDIR/srch_strings' -a"
+        );
+    }
+    print $_ while ($_ = Exec::read_pipe_data(*OUT, 512));
+    close(OUT);
+
+    Print::print_text_footer();
+
+    return 0;
+}
+
+sub report {
+    Args::check_sort();
+
+    my $sort    = Args::get_sort();
+    my $vol     = Args::get_vol('vol');
+    my $block   = Args::get_block();
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+    my $len     = Args::get_len();
+    my $type;
+
+    if ($len == 0) {
+        print("Invalid length: 0");
+        exit(1);
+    }
+    my $bs = Args::get_unitsize();
+
+    my $usize_str = "";
+    $usize_str = " -u $bs " if ($ftype eq 'blkls');
+
+    Print::print_text_header("$vol" . "-"
+          . "$Fs::addr_unit{$ftype}"
+          . "$Args::args{'block'}"
+          . ".txt");
+
+    if ($sort == $Data::SORT_ASC) {
+        Print::log_host_inv(
+"$Caseman::vol2sname{$vol}: Generating ASCII report on data unit $block"
+        );
+        $type = "ascii";
+    }
+    elsif ($sort == $Data::SORT_STR) {
+        Print::log_host_inv(
+"$Caseman::vol2sname{$vol}: Generating ASCII strings report on data unit $block"
+        );
+        $type = "string";
+    }
+    elsif ($sort == $Data::SORT_HEX) {
+        Print::log_host_inv(
+"$Caseman::vol2sname{$vol}: Generating hex report on data unit $block"
+        );
+        $type = "hex";
+    }
+    else {
+        print "\n\n";
+        print "invalid sort value";
+        return 1;
+    }
+
+    print "                 Autopsy $type $Fs::addr_unit{$ftype} Report\n\n"
+      . "-" x 70 . "\n"
+      . "                   GENERAL INFORMATION\n\n";
+
+    if ($len == 1) {
+        print "$Fs::addr_unit{$ftype}: $Args::args{'block'}\n";
+    }
+    else {
+        my $end = $block + $len - 1;
+        print "$Fs::addr_unit{$ftype}" . "s: $Args::args{'block'}-$end\n";
+    }
+    print "$Fs::addr_unit{$ftype} Size: $bs\n";
+
+    # if (($ftype ne 'blkls') && ($ftype ne 'raw') && ($ftype ne 'swap')) {
+    if ($Fs::is_fs{$ftype} == 1) {
+
+        local *OUT;
+        Exec::exec_pipe(*OUT,
+            "'$::TSKDIR/ifind' -f $ftype -d $block  -o $offset -i $imgtype $img"
+        );
+        my $meta = Exec::read_pipe_line(*OUT);
+        close(OUT);
+
+        $meta = "Error getting meta address"
+          if ((!defined $meta) || ($meta eq ""));
+
+        if ($meta =~ /^($::REG_META)$/o) {
+            my $tmpi = $1;
+            print "\nPointed to by $Fs::meta_str{$ftype}: $tmpi\n";
+
+            my $tmpr = $Caseman::vol2mnt{$vol};
+            print "Pointed to by files:\n";
+            Exec::exec_pipe(*OUT,
+"'$::TSKDIR/ffind' -f $ftype -a  -o $offset -i $imgtype $img $tmpi"
+            );
+            while ($_ = Exec::read_pipe_line(*OUT)) {
+                chop;
+                if (/^(\*)\s+\/*(.*)$/) {
+                    Print::print_output(
+                        "  $tmpr$2 (deleted)\n");
+                }
+                elsif (/^\/(.*)$/) {
+                    Print::print_output(
+                        "  $tmpr$1\n");
+                }
+                else {
+                    Print::print_output("  $_\n");
+                }
+            }
+            close(OUT);
+        }
+        else {
+            print "Not allocated to any meta data structures\n";
+        }
+    }    # not blkls
+
+    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $ftype $usize_str  -o $offset -i $imgtype $img $block $len | '$::MD5_EXE'"
+    );
+    my $md5 = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $md5 = "Error getting md5"
+      if ((!defined $md5) || ($md5 eq ""));
+
+    chop $md5;
+    print "MD5 of raw $Fs::addr_unit{$ftype}: $md5\n";
+
+    if ($sort == $Data::SORT_HEX) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $ftype $usize_str -h  -o $offset -i $imgtype $img $block $len | '$::MD5_EXE'"
+        );
+    }
+    elsif ($sort == $Data::SORT_ASC) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $ftype $usize_str -a  -o $offset -i $imgtype $img $block $len | '$::MD5_EXE'"
+        );
+    }
+    elsif ($sort == $Data::SORT_STR) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $ftype $usize_str  -o $offset -i $imgtype $img $block $len | '$::TSKDIR/srch_strings' -a | '$::MD5_EXE'"
+        );
+    }
+
+    $md5 = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $md5 = "Error getting md5"
+      if ((!defined $md5) || ($md5 eq ""));
+
+    chop $md5;
+    print "MD5 of $type output: $md5\n";
+
+    print "\nImage: $Caseman::vol2path{$vol}\n";
+    if (($Caseman::vol2start{$vol} == 0) && ($Caseman::vol2end{$vol} == 0)) {
+        print "Offset: Full image\n";
+    }
+    elsif ($Caseman::vol2end{$vol} == 0) {
+        print "Offset: $Caseman::vol2start{$vol} to end\n";
+    }
+    else {
+        print "Offset: $Caseman::vol2start{$vol} to $Caseman::vol2end{$vol}\n";
+    }
+    print "File System Type: $ftype\n";
+
+    my $date = localtime();
+
+    print "\nDate Generated: $date\n"
+      . "Investigator: $Args::args{'inv'}\n"
+      . "-" x 70 . "\n"
+      . "                        CONTENT\n\n";
+
+    if ($sort == $Data::SORT_HEX) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $ftype $usize_str -h  -o $offset -i $imgtype $img $block $len"
+        );
+    }
+    elsif ($sort == $Data::SORT_ASC) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $ftype $usize_str -a  -o $offset -i $imgtype $img $block $len"
+        );
+    }
+    elsif ($sort == $Data::SORT_STR) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $ftype $usize_str  -o $offset -i $imgtype $img $block $len | '$::TSKDIR/srch_strings' -a"
+        );
+    }
+    Print::print_output($_)
+      while ($_ = Exec::read_pipe_data(*OUT, 512));
+    close(OUT);
+
+    print "\n"
+      . "-" x 70 . "\n"
+      . "                   VERSION INFORMATION\n\n"
+      . "Autopsy Version: $::VER\n";
+    print "The Sleuth Kit Version: " . ::get_tskver() . "\n";
+
+    Print::print_text_footer();
+
+    return 0;
+}
+
+#
+# Display the block allocation list
+#
+sub list {
+    Print::print_html_header("Block Allocation List");
+
+    my $BLKLS_GAP = 500;
+
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $min = 0;
+    $min = Args::get_min() if (exists $Args::args{'min'});
+    my $max = $min + $BLKLS_GAP - 1;
+
+    # set fmin to the minimum for the file system
+    my $fmin = $min;
+    $fmin = $Fs::first_addr{$ftype} if ($min < $Fs::first_addr{$ftype});
+
+    Print::log_host_inv(
+        "$Caseman::vol2sname{$vol}: Block Allocation List for $min to $max");
+    print "<center><H2>$Fs::addr_unit{$ftype}: $min - $max</H2>";
+
+    my $tmp;
+
+    if ($min - $BLKLS_GAP >= 0) {
+        $tmp = $min - $BLKLS_GAP;
+        print "<a href=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::LIST&"
+          . "$Args::baseargs&min=$tmp\">"
+          . "<img src=\"pict/but_prev.jpg\" alt=\"previous\" "
+          . "width=\"89\" height=20 border=\"0\"></a> ";
+    }
+    $tmp = $min + $BLKLS_GAP;
+    print " <a href=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::LIST&"
+      . "$Args::baseargs&min=$tmp\">"
+      . "<img src=\"pict/but_next.jpg\" alt=\"next\" "
+      . "width=\"89\" height=20 border=\"0\"></a><br>";
+    print "</center>\n";
+
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkls' -el -f $ftype  -o $offset -i $imgtype $img $fmin-$max"
+    );
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        if (/^(\d+)\|([af])/) {
+            print "<a href=\"$::PROGNAME?mod=$::MOD_DATA&"
+              . "view=$Data::CONT_MENU_FR&$Args::baseargs&block=$1\">"
+              . "$1:</a> ";
+            if ($2 eq "a") {
+                print "allocated<br>\n";
+            }
+            else {
+                print "<font color=\"$::DEL_COLOR[0]\">free</font><br>\n";
+            }
+        }
+    }
+    close(OUT);
+
+    print "<center>\n";
+    if ($min - $BLKLS_GAP >= 0) {
+        $tmp = $min - $BLKLS_GAP;
+        print "<a href=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::LIST&"
+          . "$Args::baseargs&min=$tmp\">"
+          . "<img src=\"pict/but_prev.jpg\" alt=\"previous\" "
+          . "width=\"89\" height=20 border=\"0\"></a> ";
+    }
+    $tmp = $min + $BLKLS_GAP;
+    print " <a href=\"$::PROGNAME?mod=$::MOD_DATA&view=$Data::LIST&"
+      . "$Args::baseargs&min=$tmp\">"
+      . "<img src=\"pict/but_next.jpg\" alt=\"next\" "
+      . "width=\"89\" height=20 border=\"0\"></a><br>";
+    print "</center>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+sub export {
+    my $block   = Args::get_block();
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+    my $len     = Args::get_len();
+    my $bs      = Args::get_unitsize();
+
+    Print::print_oct_header(
+        "$vol" . "-" . "$Fs::addr_unit{$ftype}" . "$block" . ".raw");
+
+    Print::log_host_inv(
+"$Caseman::vol2sname{$vol}: Saving contents of data unit $block (unit size: $bs  number: $len)"
+    );
+
+    local *OUT;
+    if ($ftype eq 'blkls') {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $ftype -u $bs  -o $offset -i $imgtype $img $block $len"
+        );
+    }
+    else {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkcat' -f $ftype  -o $offset -i $imgtype $img $block $len"
+        );
+    }
+    print "$_" while ($_ = Exec::read_pipe_data(*OUT, 512));
+    close(OUT);
+
+    Print::print_oct_footer();
+    return 0;
+}
+
+# Blank Page
+sub blank {
+    Print::print_html_header("Data Unit Blank Page");
+    my $vol   = Args::get_vol('vol');
+    my $ftype = $Caseman::vol2ftype{$vol};
+
+    print "<center><h3>Data Unit Mode</h3><br>\n"
+      . "Here you can view the contents of any $Fs::addr_unit{$ftype} in the file system.<br>\n"
+      . "Enter the address in the field on the left.\n";
+    Print::print_html_footer();
+    return 0;
+}
diff --git a/lib/Exec.pm b/lib/Exec.pm
new file mode 100644
index 0000000000000000000000000000000000000000..e13871275673d3e1b2b7fbbfc958f7956c646362
--- /dev/null
+++ b/lib/Exec.pm
@@ -0,0 +1,91 @@
+#
+# Functions that wrap the execution of tools so that they are logged
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2005 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 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.
+
+package Exec;
+
+# exec_pipe(HANDLE, CMD);
+sub exec_pipe {
+    my $handle = shift(@_);
+    my $cmd    = shift(@_);
+
+    die "Can't open pipe for exec_pipe"
+      unless defined(my $pid = open($handle, '-|'));
+
+    if ($pid) {
+        return $handle;
+    }
+    else {
+        $| = 1;
+        Print::log_host_inv_exec("$cmd");
+        exec("$cmd") or die "Can't exec program: $!";
+    }
+}
+
+sub read_pipe_line {
+    my $handle = shift(@_);
+    my $out;
+
+# for (my $i = 0; ($len = read ($handle, $$buf, $size)) && (!defined $len); $i++) {
+
+    for (my $i = 0; $i < 100; $i++) {
+        $out = <$handle>;
+        return $out if (defined $out);
+    }
+    return $out;
+}
+
+sub read_pipe_data {
+    my $handle = shift(@_);
+    my $size   = shift(@_);
+    my $out;
+    my $len;
+
+    for (
+        my $i = 0;
+        ($len = read($handle, $out, $size)) && (!defined $len) && ($i < 100);
+        $i++
+      )
+    {
+    }
+
+    return $out;
+}
+
+sub exec_sys {
+    my $cmd = shift(@_);
+    Print::log_host_inv_exec("$cmd");
+    system($cmd);
+    return;
+}
+
+1;
diff --git a/lib/File.pm b/lib/File.pm
new file mode 100644
index 0000000000000000000000000000000000000000..59696d013cb2ba05195a368e1cf9b9af68ecbd5d
--- /dev/null
+++ b/lib/File.pm
@@ -0,0 +1,2310 @@
+#
+# File name layer functions
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2005 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 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.
+
+# Updated 1/15
+
+package File;
+
+# If the order of these views are changed, then the checks in main
+# must be as well
+$File::BLANK          = 0;
+$File::FRAME          = 1;
+$File::DIR_LIST       = 2;
+$File::FILE_LIST_DIR  = 3;
+$File::FILE_LIST_FILE = 4;
+$File::FILE_LIST_DEL  = 5;
+$File::FILE_LIST      = 6;
+$File::CONT           = 7;
+$File::CONT_FR        = 8;
+$File::CONT_MENU      = 9;
+$File::REPORT         = 10;
+$File::EXPORT         = 11;
+$File::MD5LIST        = 12;
+$File::CONT_IMG       = 13;
+
+$File::REC_NO  = 0;
+$File::REC_YES = 1;
+
+sub main {
+
+    # By default, show the main frame
+    $Args::args{'view'} = $Args::enc_args{'view'} = $File::FRAME
+      unless (exists $Args::args{'view'});
+
+    Args::check_view();
+    my $view = Args::get_view();
+
+    if ($view == $File::BLANK) {
+        blank();
+        return 0;
+    }
+
+    # Check Basic Args
+    Args::check_vol('vol');
+
+    # These windows don't need the meta data address
+    if ($view < $File::FILE_LIST) {
+
+        if ($view == $File::FRAME) {
+            return frame();
+        }
+
+        Args::check_dir();
+        if ($view == $File::DIR_LIST) {
+            return dir_list();
+        }
+        elsif ($view == $File::FILE_LIST_DIR) {
+            return file_list_dir();
+        }
+        elsif ($view == $File::FILE_LIST_DEL) {
+            return file_list_del();
+        }
+        elsif ($view == $File::FILE_LIST_FILE) {
+            return file_list_file();
+        }
+    }
+
+    # These windows need the meta data address
+    Args::check_dir();
+    Args::check_meta('meta');
+
+    if ($view < $File::REPORT) {
+        if ($view == $File::FILE_LIST) {
+            return file_list();
+        }
+        elsif ($view == $File::CONT) {
+            return content();
+        }
+        elsif ($view == $File::CONT_FR) {
+            return content_fr();
+        }
+        elsif ($view == $File::CONT_MENU) {
+            return content_menu();
+        }
+    }
+    else {
+        if ($view == $File::REPORT) {
+            return report();
+        }
+        elsif ($view == $File::EXPORT) {
+            return export();
+        }
+        elsif ($view == $File::MD5LIST) {
+            return md5list();
+        }
+        elsif ($view == $File::CONT_IMG) {
+            return content_img();
+        }
+    }
+
+    Print::print_check_err("Invalid File View");
+}
+
+# Sorting and display types
+my $FIL_SORT_ASC = 0;
+my $FIL_SORT_STR = 1;
+my $FIL_SORT_HEX = 2;
+
+# Methods of sorting the file listings
+my $SORT_DTYPE = 0;    # type according to dentry
+my $SORT_ITYPE = 1;    # type according to meta
+my $SORT_NAME  = 2;
+my $SORT_MOD   = 3;
+my $SORT_ACC   = 4;
+my $SORT_CHG   = 5;
+my $SORT_CRT   = 6;
+my $SORT_SIZE  = 7;
+my $SORT_GID   = 8;
+my $SORT_UID   = 9;
+my $SORT_META  = 10;
+my $SORT_DEL   = 11;
+
+my $DIRMODE_SHOW   = 1;
+my $DIRMODE_NOSHOW = 2;
+
+#
+# Make the three frames and fill them in
+#
+sub frame {
+    my $vol = Args::get_vol('vol');
+    my $mnt = $Caseman::vol2mnt{$vol};
+
+    my $ftype = $Caseman::vol2ftype{$vol};
+
+    # If we were not given the meta, then look up the root
+    unless (exists $Args::args{'meta'}) {
+        $Args::args{'meta'} = $Args::enc_args{'meta'} = $Fs::root_meta{$ftype};
+    }
+
+    unless (exists $Args::args{'dir'}) {
+        $Args::enc_args{'dir'} = $Args::args{'dir'} = "/";
+    }
+
+    Args::check_meta('meta');
+    Args::check_dir();
+
+    my $meta = Args::get_meta('meta');
+    my $dir  = Args::get_dir();
+
+    Print::print_html_header_frameset("$mnt$dir on $Args::args{'vol'}");
+
+    my $sort = $SORT_NAME;
+    $sort = $Args::args{'sort'} if (exists $Args::args{'sort'});
+
+    my $dirmode = $DIRMODE_NOSHOW;
+    $dirmode = $Args::args{'dirmode'} if (exists $Args::args{'dirmode'});
+
+    print "<frameset cols=\"175,*\">\n";
+
+    # Directory Listing on Left
+    my $url =
+      "$::PROGNAME?$Args::baseargs&dir=$dir&" . "sort=$sort&dirmode=$dirmode";
+
+    print "<frame src=\"$url&mod=$::MOD_FILE&view=$File::DIR_LIST\">\n";
+
+    # File frameset on right
+    print "<frameset rows=\"50%,50%\">\n";
+
+    # File Listings on top
+    print
+      "<frame src=\"$url&mod=$::MOD_FILE&view=$File::FILE_LIST&meta=$meta\" "
+      . "name=\"list\">\n";
+
+    # File Contents
+    print "<frame src=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::BLANK&"
+      . "$Args::baseargs\" name=\"content\">\n"
+      . "</frameset>\n"
+      . "</frameset>\n";
+
+    Print::print_html_footer_frameset();
+    return 0;
+}
+
+#
+# Print the directory names for the lhs frame and other
+# Search forms
+#
+
+sub dir_list {
+    Args::check_sort();
+    Args::check_dirmode();
+
+    Print::print_html_header("");
+
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $sort    = Args::get_sort();
+    my $dirmode = Args::get_dirmode();
+    my $mnt     = $Caseman::vol2mnt{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $lcldir     = "";
+    my $prev_plus  = "";    # previous number of '+' directory spacers
+    my $prev_fname = "";
+    my $prev_meta  = "";
+
+    # Field to enter a directory into:
+    print "<p><form action=\"$::PROGNAME\" method=\"get\" target=\"list\">\n"
+      . "<center><b>Directory Seek</b></center><br>"
+      . "Enter the name of a directory that you want to view.<br>"
+      . "<tt>$mnt</tt>"
+      . "<input type=\"text\" name=\"dir\" size=24 maxlength=100>\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_FILE\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$File::FILE_LIST_DIR\">\n"
+      . "<input type=\"hidden\" name=\"vol\" value=\"$vol\">\n"
+      . "<input type=\"hidden\" name=\"sort\" value=\"$Args::args{'sort'}\">\n"
+      . "<input type=\"hidden\" name=\"dirmode\" value=\"$Args::args{'dirmode'}\">\n"
+      . Args::make_hidden()
+      .
+
+      # View Button
+      "<br><input type=\"image\" src=\"pict/but_view.jpg\" "
+      . "width=45 height=22 alt=\"View\" border=\"0\"></form>\n";
+
+    # Field to enter a name into:
+    print
+      "<hr><p><form action=\"$::PROGNAME\" method=\"get\" target=\"list\">\n"
+      . "<center><b>File Name Search</b></center><br>"
+      . "Enter a Perl regular expression for the file names you want to find.<br><br>\n"
+      . "<input type=\"text\" name=\"dir\" size=24 maxlength=100>\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_FILE\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$File::FILE_LIST_FILE\">\n"
+      . "<input type=\"hidden\" name=\"vol\" value=\"$Args::args{'vol'}\">\n"
+      . "<input type=\"hidden\" name=\"sort\" value=\"$Args::args{'sort'}\">\n"
+      . "<input type=\"hidden\" name=\"dirmode\" value=\"$Args::args{'dirmode'}\">\n"
+      . Args::make_hidden()
+      . "<br>\n"
+      .
+
+      # Search Button
+      "<input type=\"image\" src=\"pict/but_search.jpg\" "
+      . "width=61 height=22 alt=\"Search\" border=\"0\"></form>\n";
+
+    print "<p><hr><p>\n";
+
+    my $base_url = "$::PROGNAME?$Args::baseargs&sort=$sort";
+
+    # All deleted files button
+    print "<a href=\"$base_url&mod=$::MOD_FILE&view=$File::FILE_LIST_DEL&"
+      . "dir=&dirmode=$dirmode\" target=\"list\">"
+      . "<img border=\"0\" src=\"pict/file_b_alldel.jpg\" width=\"127\" "
+      . "alt=\"Show All Deleted Files\">"
+      . "</a><p>\n";
+
+    # The dirmode arg shows if we should expand the whole directory listing
+    # or not
+    if ($dirmode == $DIRMODE_NOSHOW) {
+        print "<a href=\"$base_url&mod=$::MOD_FILE&view=$File::FRAME&"
+          . "dirmode=$DIRMODE_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&mod=$::MOD_FILE&view=$File::FRAME&"
+          . "dirmode=$DIRMODE_NOSHOW\" target=\"_parent\">"
+          . "<img src=\"pict/file_b_hide.jpg\" alt=\"Hide All Directories\" "
+          . "border=\"0\"></a><p><hr>\n";
+    }
+
+    $base_url .= "&dirmode=$dirmode";
+
+    Print::log_host_inv("$Args::args{'vol'}: List of all directories");
+
+    # We need to maintain state to create dir and this is done by
+    # counting the + marks.
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+        "'$::TSKDIR/fls' -f $ftype -ruD -o $offset -i $imgtype $img");
+
+    # Print root
+    my $url =
+        "$base_url&mod=$::MOD_FILE&view=$File::FILE_LIST&"
+      . "meta=$Fs::root_meta{$ftype}&dir=";
+    print "<p><a href=\"$url\" target=\"list\">$mnt</a><br>\n";
+
+    while ($_ = Exec::read_pipe_line(*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&mod=$::MOD_FILE&view=$File::FILE_LIST&"
+              . "meta=$meta&dir="
+              . Args::url_encode($lcldir . $fname . "/");
+
+            print "<font color=\"$::DEL_COLOR[0]\">" if defined $del;
+            print "+$plus<a href=\"$url\" target=\"list\"><tt>/"
+              . Print::html_encode($fname)
+              . "</tt></a><br>\n";
+            print "</font>" if defined $del;
+        }
+    }
+    close(OUT);
+    Print::print_html_footer();
+    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
+#
+sub file_list {
+    Args::check_sort();
+    Args::check_dirmode();
+
+    my $vol     = Args::get_vol('vol');
+    my $sort    = Args::get_sort();
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $meta    = Args::get_meta('meta');
+    my $mnt     = $Caseman::vol2mnt{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $fname = "$mnt$Args::args{'dir'}";
+    $fname =~ s/\/\//\//g;
+
+    my $sp = "&nbsp;&nbsp;";
+
+    Print::print_html_header("Entries in $fname");
+
+    my (@itype, @dtype, @name, @mod, @acc, @chg, @crt, @size, @gid, @uid,
+        @meta);
+    my (@dir, @entry, @del, @realloc, @meta_int);
+
+    my $tz = "";
+    $tz = "-z '$Caseman::tz'" unless ("$Caseman::tz" eq "");
+
+    Print::log_host_inv(
+        "$Caseman::vol2sname{$vol}: Directory listing of $fname ($meta)");
+
+    local *OUT;
+
+    # execute command
+    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/fls' -f $ftype -la $tz -s $Caseman::ts -o $offset -i $imgtype $img $meta"
+    );
+
+    # Make the big table, small table, and start the current directory
+
+    my $iurl =
+"$::PROGNAME?$Args::baseargs&dirmode=$Args::enc_args{'dirmode'}&sort=$sort";
+
+    # base number of columns in table
+    my $cols = 15;
+    $cols += 2 if ($Fs::has_ctime{$ftype});
+    $cols += 2 if ($Fs::has_crtime{$ftype});
+    $cols += 2 if ($Fs::has_mtime{$ftype});
+
+    print <<EOF1;
+<!-- Big Table -->
+<table cellspacing=\"0\" cellpadding=\"2\" border=0>
+
+<!-- Small Table -->
+<tr>
+  <td colspan=$cols>
+    <table border=0 align=\"left\" cellspacing=\"0\" cellpadding=\"2\" width=500>
+    <tr>
+      <td colspan=2><b>Current Directory:</b> <tt>
+
+        <a href=\"${iurl}&mod=$::MOD_FILE&view=$File::FILE_LIST&meta=$Fs::root_meta{$ftype}&dir=\">$mnt</a>&nbsp;
+
+EOF1
+
+    # Each file in the path will get its own link
+    $iurl .= "&mod=$::MOD_FILE&view=$File::FILE_LIST_DIR";
+    my $path = "";
+    my @dir_split = split('/', $Args::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 =
+"&$Args::baseargs&dir=$Args::enc_args{'dir'}&meta=$Args::enc_args{'meta'}";
+    if ($::USE_NOTES == 1) {
+
+        print <<EOF2;
+    <tr>
+      <td width=\"100\" align=left>
+        <a href=\"$::PROGNAME?mod=$::MOD_NOTES&view=$Notes::ENTER_FILE$iurl\" target=\"_blank\">
+          <img border=\"0\" src=\"pict/but_addnote.jpg\" width=\"89\" height=20 alt=\"Add Note About Directory\">
+         </a>
+      </td>
+EOF2
+
+    }
+
+    # Generate MD5 List Button
+    print <<EOF3;
+
+      <td width=\"206\" align=left>
+        <a href=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::MD5LIST$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=$cols><hr></td>
+</tr>
+
+EOF3
+
+    # Make the Table and Headers
+    my $url =
+        "$::PROGNAME?mod=$::MOD_FILE&view=$File::FRAME&"
+      . "$Args::baseargs&meta=$Args::enc_args{'meta'}"
+      . "&dir=$Args::enc_args{'dir'}&dirmode=$Args::enc_args{'dirmode'}";
+
+    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\" height=20 "
+          . "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\" height=20 "
+          . "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\" height=20 "
+          . "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\" height=20 "
+          . "alt=\"File Name\">"
+          . "</a></td>\n";
+    }
+
+    print "  <td background=\"$::YEL_PIX\">$sp</td>\n";
+
+    # Modified / Written
+    if ($Fs::has_mtime{$ftype}) {
+        if ($sort == $SORT_MOD) {
+            print "  <td align=\"left\" background=\"$::YEL_PIX\">"
+              . "<img border=\"0\" "
+              . "src=\"pict/file_h_wr_cur.jpg\" "
+              . "width=\"89\" height=20 "
+              . "alt=\"Modified/Written Time\">"
+              . "</td>\n";
+        }
+        else {
+            $iurl = $url . "&sort=$SORT_MOD";
+            print "  <td align=\"left\" background=\"$::YEL_PIX\">"
+              . "<a href=\"$iurl\" target=\"_parent\">"
+              . "<img border=\"0\" "
+              . "src=\"pict/file_h_wr_link.jpg\" "
+              . "width=\"60\" height=20 "
+              . "alt=\"Modified/Written Time\">"
+              . "</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\" height=20 "
+          . "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\" height=20 "
+          . "alt=\"Access Time\">"
+          . "</a></td>\n";
+    }
+
+    print "  <td background=\"$::YEL_PIX\">$sp</td>\n";
+
+    # Change
+    if ($Fs::has_ctime{$ftype}) {
+        if ($sort == $SORT_CHG) {
+            print "  <td align=\"left\" background=\"$::YEL_PIX\">"
+              . "<img border=\"0\" "
+              . "src=\"pict/file_h_chg_cur.jpg\" "
+              . "width=\"90\" height=20 "
+              . "alt=\"Change Time\">"
+              . "</td>\n";
+        }
+        else {
+            $iurl = $url . "&sort=$SORT_CHG";
+            print "  <td align=\"left\" background=\"$::YEL_PIX\">"
+              . "<a href=\"$iurl\" target=\"_parent\">"
+              . "<img border=\"0\" "
+              . "src=\"pict/file_h_chg_link.jpg\" "
+              . "width=\"62\" height=20 "
+              . "alt=\"Change Time\">"
+              . "</a></td>\n";
+        }
+        print "  <td background=\"$::YEL_PIX\">$sp</td>\n";
+    }
+
+    # Create
+    if ($Fs::has_crtime{$ftype}) {
+        if ($sort == $SORT_CRT) {
+            print "  <td align=\"left\" background=\"$::YEL_PIX\">"
+              . "<img border=\"0\" "
+              . "src=\"pict/file_h_cre_cur.jpg\" "
+              . "width=\"84\" height=20 "
+              . "alt=\"Create Time\">"
+              . "</td>\n";
+        }
+        else {
+            $iurl = $url . "&sort=$SORT_CRT";
+            print "  <td align=\"left\" background=\"$::YEL_PIX\">"
+              . "<a href=\"$iurl\" target=\"_parent\">"
+              . "<img border=\"0\" "
+              . "src=\"pict/file_h_cre_link.jpg\" "
+              . "width=\"59\" height=20 "
+              . "alt=\"Create Time\">"
+              . "</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\" height=20 "
+          . "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\" height=20 "
+          . "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\" height=20 "
+          . "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\" height=20 "
+          . "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\" height=20 "
+          . "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\" height=20 "
+          . "alt=\"GID\">"
+          . "</a></td>\n";
+    }
+
+    print "  <td background=\"$::YEL_PIX\">$sp</td>\n";
+
+    # meta
+    if ($sort == $SORT_META) {
+        print "  <td align=\"left\" background=\"$::YEL_PIX\">"
+          . "<img border=\"0\" "
+          . "src=\"pict/file_h_meta_cur.jpg\" "
+          . "width=\"62\" height=20 "
+          . "alt=\"Meta\">"
+          . "</td>\n";
+    }
+    else {
+        $iurl = $url . "&sort=$SORT_META";
+        print "  <td align=\"left\" background=\"$::YEL_PIX\">"
+          . "<a href=\"$iurl\" target=\"_parent\">"
+          . "<img border=\"0\" "
+          . "src=\"pict/file_h_meta_link.jpg\" "
+          . "width=\"41\" height=20 "
+          . "alt=\"Meta\">"
+          . "</a></td>\n";
+    }
+    print "</tr>\n";
+
+    my $cnt = 0;
+    my %seen;
+
+    # sort fls into arrays
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        if (
+/^($::REG_MTYPE)\/($::REG_MTYPE)\s*(\*?)\s*($::REG_META)(\(realloc\))?:\t(.+?)\t($::REG_DATE)\t($::REG_DATE)\t($::REG_DATE)\t($::REG_DATE)\t(\d+)\t(\d+)\t(\d+)$/o
+          )
+        {
+
+            my $lcldir = $Args::args{'dir'};
+            $dtype[$cnt]   = $1;
+            $itype[$cnt]   = $2;
+            $del[$cnt]     = $3;
+            $meta[$cnt]    = $4;
+            $realloc[$cnt] = "";
+            $realloc[$cnt] = $5 if (defined $5);
+            $name[$cnt]    = $6;
+            $mod[$cnt]     = $7;
+            $acc[$cnt]     = $8;
+            $chg[$cnt]     = $9;
+            $crt[$cnt]     = $10;
+            $size[$cnt]    = $11;
+            $gid[$cnt]     = $12;
+            $uid[$cnt]     = $13;
+
+            if ($meta[$cnt] =~ /^(\d+)(-\d+(-\d+)?)?$/) {
+                $meta_int[$cnt] = $1;
+            }
+            else {
+                $meta_int[$cnt] = $meta[$cnt];
+            }
+
+            # See if we have already seen this file yet
+            if (exists $seen{"$name[$cnt]-$meta[$cnt]"}) {
+                my $prev_cnt = $seen{"$name[$cnt]-$meta[$cnt]"};
+
+                # If we saw it while it was deleted, & it
+                # is now undel, then update it
+                if (   ($del[$cnt] eq "")
+                    && ($del[$prev_cnt] eq '*'))
+                {
+                    $del[$prev_cnt] = $del[$cnt];
+                }
+                next;
+
+                # Add it to the seen list
+            }
+            else {
+                $seen{"$name[$cnt]-$meta[$cnt]"} = $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);
+
+            $crt[$cnt] = "$1&nbsp;$2"
+              if ($crt[$cnt] =~ /($::REG_DAY\s+$::REG_TIME)\s+($::REG_ZONE2)/o);
+
+            $dir[$cnt]   = Args::url_encode($lcldir);
+            $entry[$cnt] = $cnt;
+            $cnt++;
+
+        }
+
+        # We missed it for some reason
+        else {
+            print
+"<tr><td colspan=10>Error Parsing File (Invalid Characters?):<br>$_</td></tr>\n";
+        }
+    }
+    close(OUT);
+
+    if ($cnt == 0) {
+        print "</table>\n<center>No Contents</center>\n";
+        return 0;
+    }
+
+    # 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_CRT) {
+        @sorted =
+          sort { $crt[$a] cmp $crt[$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_META) {
+        @sorted = sort {
+            $meta_int[$a] <=> $meta_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 $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 view values
+        if ($itype[$i] eq 'd') {
+            $target = "list";
+            $url    =
+                "$::PROGNAME?mod=$::MOD_FILE&view=$File::FILE_LIST&"
+              . "$Args::baseargs&meta=$meta_int[$i]"
+              . "&sort=$sort&dir=$dir[$i]&dirmode=$Args::enc_args{'dirmode'}";
+        }
+        else {
+            $target = "content";
+            $url    =
+                "$::PROGNAME?mod=$::MOD_FILE&view=$File::CONT_FR&"
+              . "$Args::baseargs&meta=$meta[$i]"
+              . "&sort=$sort&dir=$dir[$i]&dirmode=$Args::enc_args{'dirmode'}";
+            if ($del[$i] eq '*') {
+                $url .= "&recmode=$File::REC_YES";
+            }
+            else {
+                $url .= "&recmode=$File::REC_NO";
+            }
+        }
+
+        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
+        # Special rule for $OrphanFiles directory and HFS directories, which have a size of 0
+        if (
+               ($meta_int[$i] >= $Fs::first_meta{$ftype})
+            && (($size[$i] > 0) || (($name[$i] =~ /^\$Orphan/) && ($itype[$i] eq 'd')) || (($ftype =~ /hfs/) && ($itype[$i] eq 'd')))
+            && (   ($itype[$i] eq 'r')
+                || ($itype[$i] eq 'd')
+                || ($itype[$i] eq 'v'))
+          )
+        {
+            print "  <td><a href=\"$url\" target=\"$target\">$lcolor";
+        }
+        else {
+            print "  <td>$color";
+        }
+        print "<tt>"
+          . Print::html_encode($name[$i])
+          . "</tt></td>\n"
+          . "  <td>$sp</td>\n";
+        print "  <td>${color}$mod[$i]</td>\n" . "  <td>$sp</td>\n"
+          if ($Fs::has_mtime{$ftype});
+        print "  <td>${color}$acc[$i]</td>\n" . "  <td>$sp</td>\n";
+        print "  <td>${color}$chg[$i]</td>\n" . "  <td>$sp</td>\n"
+          if ($Fs::has_ctime{$ftype});
+        print "  <td>${color}$crt[$i]</td>\n" . "  <td>$sp</td>\n"
+          if ($Fs::has_crtime{$ftype});
+        print "  <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 meta, make a link to meta browsing mode
+        if ($meta_int[$i] >= $Fs::first_meta{$ftype}) {
+            my $iurl =
+"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_META&$Args::baseargs&meta=$meta[$i]";
+            print "<td><a href=\"$iurl\" target=\"_top\">$lcolor";
+        }
+        else {
+            print "<td>$color";
+        }
+        print "$meta[$i]</a> $realloc[$i]</td>\n</tr>\n";
+
+        $row++;
+    }
+
+    print "</table>\n";
+    Print::print_html_footer();
+    return 0;
+
+};    #end of FIL_LIST
+
+# This takes a directory name as an argument and converts it to
+# the meta value and calls FIL_LIST
+#
+# The meta value can be anything when this is run, it will be
+# overwritten
+sub file_list_dir {
+
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $dir     = Args::get_dir();
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    Print::log_host_inv(
+        "$Args::args{'vol'}: Finding meta data address for $dir");
+
+    # Use 'ifind -n' to get the meta data address for the given name
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+        "'$::TSKDIR/ifind' -f $ftype -n '$dir'  -o $offset -i $imgtype $img");
+    my $meta;
+
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        $meta = $1
+          if (/^($::REG_META)$/);
+    }
+    close(OUT);
+
+    Print::print_check_err("Error finding meta data address for $dir")
+      unless (defined $meta);
+
+    Print::print_check_err("Error finding meta data address for $dir: $meta")
+      unless ($meta =~ /^$::REG_META$/);
+
+    # Verify it is a directory with istat
+    Exec::exec_pipe(*OUT,
+        "'$::TSKDIR/istat' -f $ftype  -o $offset -i $imgtype $img $meta");
+
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+
+        # This is a directory
+        if (   (/mode:\s+d/)
+            || (/File Attributes: Directory/)
+            || (/^Flags:.*?Directory/))
+        {
+            close(OUT);
+
+            # Set the meta variables
+            $Args::enc_args{'meta'} = $Args::args{'meta'} = $meta;
+
+            $Args::args{'dir'} .= "/"
+              unless ($Args::args{'dir'} =~ /.*?\/$/);
+            $Args::enc_args{'dir'} .= "/"
+              unless ($Args::enc_args{'dir'} =~ /.*?\/$/);
+
+            # List the directory contents
+            file_list();
+
+            return 0;
+        }
+    }
+    close(OUT);
+
+    # This is not a directory, so just give a link
+    Print::print_html_header("");
+
+    my $meta_int = $meta;
+    $meta_int = $1 if ($meta_int =~ /(\d+)-\d+(-\d+)?/);
+
+    my $recmode = $File::REC_NO;
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+        "'$::TSKDIR/ils' -f $ftype -e  -o $offset -i $imgtype $img $meta_int");
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        chop;
+        next unless ($_ =~ /^$meta/);
+        if ($_ =~ /^$meta\|f/) {
+            $recmode = $File::REC_YES;
+        }
+        elsif ($_ =~ /^$meta\|a/) {
+            $recmode = $File::REC_NO;
+        }
+        else {
+            Print::print_err("Error parsing ils output: $_");
+        }
+    }
+    close(OUT);
+
+    print <<EOF;
+
+<tt>$dir</tt> (
+<a href=\"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_META&$Args::baseargs&meta=$meta&recmode=$recmode\" target=\"_top\">
+meta $meta</a>) is not a directory.
+
+<p>
+<a href=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::CONT_FR&$Args::baseargs&meta=$meta&dir=$dir&recmode=$recmode\" target=\"content\">
+  <img src=\"pict/but_viewcont.jpg\" height=20 width=123 alt=\"view contents\" border=\"0\">
+</a>
+
+EOF
+
+    Print::print_html_footer();
+    return 1;
+
+}
+
+# List the files that meet a certain pattern
+sub file_list_file {
+    Args::check_sort();
+    Args::check_dirmode();
+    Args::check_dir();
+
+    my $vol     = Args::get_vol('vol');
+    my $mnt     = $Caseman::vol2mnt{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $meta    = $Fs::root_meta{$ftype};
+    my $sort    = Args::get_sort();
+    my $dirmode = Args::get_dirmode();
+    my $dir     = Args::get_dir();
+
+    Print::print_html_header(
+        "Filtered files on $Caseman::vol2sname{$vol} $mnt");
+
+    my $tz = "";
+    $tz = "-z '$Caseman::tz'" unless ("$Caseman::tz" eq "");
+
+    my $sp = "&nbsp;&nbsp;";
+
+    Print::log_host_inv(
+        "$Caseman::vol2sname{$vol}: Listing all files with $dir");
+
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/fls' -f $ftype -lpr $tz -s $Caseman::ts -o $offset -i $imgtype $img $meta"
+    );
+
+    print "<b>All files with \'<tt>$dir</tt>\' in the name</b><p>\n"
+      . "<a href=\"$::PROGNAME?$Args::baseargs&dirmode=$Args::enc_args{'dirmode'}"
+      . "&sort=$sort&mod=$::MOD_FILE&view=$File::FILE_LIST"
+      . "&meta=$Fs::root_meta{$ftype}&dir=\">"
+      . "<img border=\"0\" src=\"pict/file_b_allfiles.jpg\" width=\"112\" "
+      . "alt=\"Show All Files\"></a>\n" . "<hr>"
+      . "<table cellspacing=\"0\" cellpadding=\"2\"  border=0>\n"
+      . "<tr valign=\"MIDDLE\" align=\"left\" "
+      . "background=\"$::YEL_PIX\">\n";
+
+    # deleted
+    print "<td align=\"left\">"
+      . "<img border=\"0\" src=\"pict/file_h_del_link.jpg\" "
+      . "width=\"28\" height=20 alt=\"Deleted Files\">"
+      . "</td>\n"
+      . "<td>$sp</td>\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\" height=20 "
+      . "alt=\"File Name\">"
+      . "</td>\n"
+      . "<td>$sp</td>\n";
+
+    # Mod / Written
+    if ($Fs::has_mtime{$ftype}) {
+        print "  <td><img border=\"0\" "
+          . "src=\"pict/file_h_wr_link.jpg\" "
+          . "width=\"60\" "
+          . "alt=\"Written Time\">"
+          . "</td>\n"
+          . "<td>$sp</td>\n";
+    }
+
+    # Access
+    print "  <td><img border=\"0\" "
+      . "src=\"pict/file_h_acc_link.jpg\" "
+      . "width=\"66\" height=20 "
+      . "alt=\"Access Time\">"
+      . "</td>\n"
+      . "<td>$sp</td>\n";
+
+    # Change
+    if ($Fs::has_ctime{$ftype}) {
+        print "  <td><img border=\"0\" "
+          . "src=\"pict/file_h_chg_link.jpg\" "
+          . "width=\"62\" "
+          . "alt=\"Change Time\">"
+          . "</td>\n"
+          . "<td>$sp</td>\n";
+    }
+
+    # Create
+    if ($Fs::has_crtime{$ftype}) {
+        print "  <td><img border=\"0\" "
+          . "src=\"pict/file_h_cre_link.jpg\" "
+          . "width=\"59\" "
+          . "alt=\"Create Time\">"
+          . "</td>\n"
+          . "<td>$sp</td>\n";
+    }
+
+    # Size
+    print "  <td><img border=\"0\" "
+      . "src=\"pict/file_h_siz_link.jpg\" "
+      . "width=\"31\" height=20 "
+      . "alt=\"Size\">"
+      . "</td>\n"
+      . "<td>$sp</td>\n";
+
+    # UID
+    print "  <td><img border=\"0\" "
+      . "src=\"pict/file_h_uid_link.jpg\" "
+      . "width=\"27\" height=20 "
+      . "alt=\"UID\">"
+      . "</td>\n"
+      . "<td>$sp</td>\n";
+
+    # GID
+    print "  <td><img border=\"0\" "
+      . "src=\"pict/file_h_gid_link.jpg\" "
+      . "width=\"28\" height=20 "
+      . "alt=\"GID\">"
+      . "</td>\n"
+      . "<td>$sp</td>\n";
+
+    # Meta
+    print "  <td><img border=\"0\" "
+      . "src=\"pict/file_h_meta_link.jpg\" "
+      . "width=\"41\" height=20 "
+      . "alt=\"Meta\">"
+      . "</td>\n"
+      . "<td>$sp</td>\n";
+
+    my $row = 0;
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        if (
+/^($::REG_MTYPE)\/($::REG_MTYPE)\s*(\*?)\s*($::REG_META)(\(realloc\))?:\t(.+?)\t($::REG_DATE)\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 $cr = $10;
+            my $s  = $11;
+            my $g  = $12;
+            my $u  = $13;
+
+            if ($n =~ /^\/(.*)/) {
+                $n = $1;
+            }
+
+            my $p = "";
+            my $f = $n;
+
+            if ($n =~ /^(.+?)\/([^\/]+)$/) {
+                $p = $1;
+                $f = $2;
+            }
+
+            next unless ($f =~ /$dir/i);
+
+            my $enc_n = Args::url_encode($n);
+            my $iurl  =
+"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_META&$Args::baseargs&meta=$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=\"left\">\n";
+
+            my $color;
+            my $lcolor;
+            if ($d eq '*') {
+                $color  = "<font color=\"" . $::DEL_COLOR[$r] . "\">";
+                $lcolor = $color;
+
+                print "<img src=\"pict/file_b_check.jpg\" border=\"0\">\n";
+
+            }
+            else {
+                $color  = "<font color=\"$::NORM_COLOR\">";
+                $lcolor = "<font color=\"$::LINK_COLOR\">";
+                print "&nbsp;";
+            }
+
+            print "</td><td>$sp</td>";
+
+            print "<td align=\"center\">$color"
+              . "$dt&nbsp;/&nbsp;$it</td>"
+              . "<td>$sp</td>\n";
+
+            if ($it eq 'd') {
+                my $url =
+                    "$::PROGNAME?mod=$::MOD_FILE&"
+                  . "view=$File::FILE_LIST&$Args::baseargs&meta=$i"
+                  . "&sort=$sort&dir=$enc_n&dirmode=$dirmode";
+
+                print "<td>";
+                if ($i_int >= $Fs::first_meta{$ftype}) {
+                    print "<a href=\"$url\" target=\"_self\">$lcolor";
+                }
+                else {
+                    print "$color";
+                }
+                print "<tt>"
+                  . Print::html_encode($mnt . $n)
+                  . "</tt></td>"
+                  . "<td>$sp</td>\n";
+            }
+            else {
+                my $url =
+                    "$::PROGNAME?mod=$::MOD_FILE&view=$File::CONT_FR&"
+                  . "$Args::baseargs&meta=$i&sort=$sort&dir=$enc_n";
+
+                if ($d eq '*') {
+                    $url .= "&recmode=$File::REC_YES";
+                }
+                else {
+                    $url .= "&recmode=$File::REC_NO";
+                }
+
+                print "<td>";
+                if (($i_int >= $Fs::first_meta{$ftype}) && ($it eq 'r')) {
+                    print "<a href=\"$url\" target=\"content\">$lcolor";
+                }
+                else {
+                    print "$color";
+                }
+                print "<tt>$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);
+            $cr = "$1&nbsp;$2"
+              if ($cr =~ /($::REG_DAY\s+$::REG_TIME)\s+($::REG_ZONE2)/o);
+
+            print "<td>$color$m</td>" . "<td>$sp</td>\n"
+              if ($Fs::has_mtime{$ftype});
+
+            print "<td>$color$a</td>" . "<td>$sp</td>\n";
+            print "<td>$color$c</td>" . "<td>$sp</td>\n"
+              if ($Fs::has_ctime{$ftype});
+            print "<td>$color$cr</td>" . "<td>$sp</td>\n"
+              if ($Fs::has_crtime{$ftype});
+
+            print "<td>$color$s</td>"
+              . "<td>$sp</td>\n"
+              . "<td>$color$g</td>"
+              . "<td>$sp</td>\n"
+              . "<td>$color$u</td>"
+              . "<td>$sp</td>\n";
+
+            print "<td>";
+            if ($i_int >= $Fs::first_meta{$ftype}) {
+                print "<a href=\"$iurl\" target=\"_top\">";
+                print "$lcolor$i</a>";
+            }
+            else {
+                print "$color$i";
+            }
+            print " (realloc)" if $r;
+            print "</td></tr>\n";
+        }
+        else {
+            print "Error Parsing File (invalid characters?)<br>: $_\n<br>";
+        }
+
+        $row++;
+    }
+    close(OUT);
+    print "</table>\n";
+
+    print "<center>No files found with that pattern</center>\n"
+      if ($row == 0);
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# display deleted files only
+#
+# Sorting should be added to this
+sub file_list_del {
+    Args::check_sort();
+    Args::check_dirmode();
+
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $mnt     = $Caseman::vol2mnt{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $meta    = $Fs::root_meta{$ftype};
+    my $sort    = Args::get_sort();
+    my $dirmode = Args::get_dirmode();
+
+    Print::print_html_header("Deleted files on $Caseman::vol2sname{$vol} $mnt");
+
+    my $tz = "";
+    $tz = "-z '$Caseman::tz'" unless ("$Caseman::tz" eq "");
+
+    my $sp = "&nbsp;&nbsp;";
+
+    Print::log_host_inv("$Caseman::vol2sname{$vol}: Listing all deleted files");
+
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/fls' -f $ftype -ldr $tz -s $Caseman::ts  -o $offset -i $imgtype $img $meta"
+    );
+
+    print "<b>All Deleted Files</b><p><hr>"
+      . "<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\" height=20 "
+      . "alt=\"File Name\">"
+      . "</td>\n"
+      . "<td>$sp</td>\n";
+
+    # Mod / Written
+    if ($Fs::has_mtime{$ftype}) {
+        print "  <td><img border=\"0\" "
+          . "src=\"pict/file_h_wr_link.jpg\" "
+          . "width=\"60\" "
+          . "alt=\"Written Time\">"
+          . "</td>\n"
+          . "<td>$sp</td>\n";
+    }
+
+    # Access
+    print "  <td><img border=\"0\" "
+      . "src=\"pict/file_h_acc_link.jpg\" "
+      . "width=\"66\" height=20 "
+      . "alt=\"Access Time\">"
+      . "</td>\n"
+      . "<td>$sp</td>\n";
+
+    # Change
+    if ($Fs::has_ctime{$ftype}) {
+        print "  <td><img border=\"0\" "
+          . "src=\"pict/file_h_chg_link.jpg\" "
+          . "width=\"62\" "
+          . "alt=\"Change Time\">"
+          . "</td>\n"
+          . "<td>$sp</td>\n";
+    }
+
+    # Create
+    if ($Fs::has_crtime{$ftype}) {
+        print "  <td><img border=\"0\" "
+          . "src=\"pict/file_h_cre_link.jpg\" "
+          . "width=\"59\" "
+          . "alt=\"Create Time\">"
+          . "</td>\n"
+          . "<td>$sp</td>\n";
+    }
+
+    # Size
+    print "  <td><img border=\"0\" "
+      . "src=\"pict/file_h_siz_link.jpg\" "
+      . "width=\"31\" height=20 "
+      . "alt=\"Size\">"
+      . "</td>\n"
+      . "<td>$sp</td>\n";
+
+    # UID
+    print "  <td><img border=\"0\" "
+      . "src=\"pict/file_h_uid_link.jpg\" "
+      . "width=\"27\" height=20 "
+      . "alt=\"UID\">"
+      . "</td>\n"
+      . "<td>$sp</td>\n";
+
+    # GID
+    print "  <td><img border=\"0\" "
+      . "src=\"pict/file_h_gid_link.jpg\" "
+      . "width=\"28\" height=20 "
+      . "alt=\"GID\">"
+      . "</td>\n"
+      . "<td>$sp</td>\n";
+
+    # Meta
+    print "  <td><img border=\"0\" "
+      . "src=\"pict/file_h_meta_link.jpg\" "
+      . "width=\"41\" height=20 "
+      . "alt=\"Meta\">"
+      . "</td>\n"
+      . "<td>$sp</td>\n";
+
+    my $row = 0;
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+
+        if (
+/^($::REG_MTYPE)\/($::REG_MTYPE)\s*(\*?)\s*($::REG_META)(\(realloc\))?:\t(.+?)\t($::REG_DATE)\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 $cr = $10;
+            my $s  = $11;
+            my $g  = $12;
+            my $u  = $13;
+
+            if ($n =~ /^\/(.*)/) {
+                $n = $1;
+            }
+            my $enc_n = Args::url_encode($n);
+            my $iurl  =
+"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_META&$Args::baseargs&meta=$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?mod=$::MOD_FILE&"
+                  . "view=$File::FILE_LIST&$Args::baseargs&meta=$i"
+                  . "&sort=$sort&dir=$enc_n&dirmode=$dirmode";
+
+                print "<td>";
+                if ($i_int >= $Fs::first_meta{$ftype}) {
+                    print "<a href=\"$url\" target=\"_self\">";
+                }
+                print "<font color=\"$::DEL_COLOR[$r]\"><tt>"
+                  . Print::html_encode($mnt . $n)
+                  . "</tt></td>"
+                  . "<td>$sp</td>\n";
+            }
+            else {
+                my $url =
+                    "$::PROGNAME?mod=$::MOD_FILE&view=$File::CONT_FR&"
+                  . "$Args::baseargs&meta=$i&sort=$sort&dir=$enc_n"
+                  . "&recmode=$File::REC_YES";
+
+                print "<td>";
+                if (($i_int >= $Fs::first_meta{$ftype}) && ($it eq 'r')) {
+                    print "<a href=\"$url\" target=\"content\">";
+                }
+                print "<font color=\"$::DEL_COLOR[$r]\"><tt>"
+                  . Print::html_encode($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);
+            $cr = "$1&nbsp;$2"
+              if ($cr =~ /($::REG_DAY\s+$::REG_TIME)\s+($::REG_ZONE2)/o);
+
+            print "<td><font color=\"$::DEL_COLOR[$r]\">$m</td>"
+              . "<td>$sp</td>\n"
+              if ($Fs::has_mtime{$ftype});
+
+            print "<td><font color=\"$::DEL_COLOR[$r]\">$a</td>"
+              . "<td>$sp</td>\n";
+            print "<td><font color=\"$::DEL_COLOR[$r]\">$c</td>"
+              . "<td>$sp</td>\n"
+              if ($Fs::has_ctime{$ftype});
+            print "<td><font color=\"$::DEL_COLOR[$r]\">$cr</td>"
+              . "<td>$sp</td>\n"
+              if ($Fs::has_crtime{$ftype});
+
+            print "<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 >= $Fs::first_meta{$ftype}) {
+                print "<a href=\"$iurl\" target=\"_top\">";
+            }
+            print "<font color=\"$::DEL_COLOR[$r]\">$i</a>";
+            print " (realloc)" if $r;
+            print "</td></tr>\n";
+        }
+        else {
+            print "Error Parsing File (invalid characters?)<br>: $_\n<br>";
+        }
+
+        $row++;
+    }
+    close(OUT);
+    print "</table>\n";
+
+    print "<center>None</center>\n"
+      if ($row == 0);
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# Content Frame
+# This creates two frames for the lower rhs frame
+#
+sub content_fr {
+    Print::print_html_header_frameset("");
+
+    my $meta    = Args::get_meta('meta');
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    print "<frameset rows=\"65,*\">\n";
+
+    my $recmode = $File::REC_NO;
+
+    if (exists $Args::enc_args{'recmode'}) {
+        $recmode = $Args::enc_args{'recmode'};
+    }
+    else {
+
+        # We need to get the allocation status of this structure
+        my $meta_int = $meta;
+        $meta_int = $1 if ($meta_int =~ /(\d+)-\d+(-\d+)?/);
+
+        local *OUT;
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/ils' -f $ftype -e  -o $offset -i $imgtype $img $meta_int"
+        );
+        while ($_ = Exec::read_pipe_line(*OUT)) {
+            chop;
+            next unless ($_ =~ /^$meta/);
+            if ($_ =~ /^$meta\|f/) {
+                $recmode = $File::REC_YES;
+            }
+            elsif ($_ =~ /^$meta\|a/) {
+                $recmode = $File::REC_NO;
+            }
+            else {
+                Print::print_check_err("Error parsing ils output: $_");
+            }
+        }
+    }
+    close(OUT);
+
+    # Get the file type so we can show the thumb nails automatically
+    if ($recmode == $File::REC_YES) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype -r  -o $offset -i $imgtype $img $meta | '$::FILE_EXE' -z -b -"
+        );
+    }
+    else {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype  -o $offset -i $imgtype $img $meta | '$::FILE_EXE' -z -b -"
+        );
+    }
+
+    my $apptype = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $apptype = "Error getting file type"
+      if ((!defined $apptype) || ($apptype eq ""));
+
+    # The menu for the different viewing options
+    print "<frame src=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::CONT_MENU&"
+      . "$Args::baseargs&dir=$Args::enc_args{'dir'}"
+      . "&meta=$Args::enc_args{'meta'}&sort=$FIL_SORT_ASC&recmode=$recmode\">\n";
+
+    # Print the image thumbnail
+    if (($apptype =~ /image data/) || ($apptype =~ /PC bitmap data/)) {
+        print "<frame src=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::CONT_IMG"
+          . "&$Args::baseargs&dir=$Args::enc_args{'dir'}"
+          . "&meta=$Args::enc_args{'meta'}"
+          . "&sort=$FIL_SORT_ASC&recmode=$recmode\" name=\"cont2\">\n</frameset>";
+    }
+    else {
+
+        # Where the actual content will be displayed
+        print "<frame src=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::CONT"
+          . "&$Args::baseargs&dir=$Args::enc_args{'dir'}"
+          . "&meta=$Args::enc_args{'meta'}"
+          . "&sort=$FIL_SORT_ASC&recmode=$recmode\" name=\"cont2\">\n</frameset>";
+    }
+
+    Print::print_html_footer_frameset();
+    return 0;
+}
+
+# This is the index for the lower rhs frame
+# Choose the content display type here
+sub content_menu {
+    Args::check_sort();
+    Args::check_recmode();
+
+    Print::print_html_header("");
+
+    my $meta    = Args::get_meta('meta');
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+    my $recmode = Args::get_recmode();
+
+    # Get the file type
+    if ($recmode == $File::REC_YES) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype -r  -o $offset -i $imgtype $img $meta | '$::FILE_EXE' -z -b -"
+        );
+    }
+    else {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype  -o $offset -i $imgtype $img $meta | '$::FILE_EXE' -z -b -"
+        );
+    }
+
+    my $apptype = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $apptype = "Error getting file type"
+      if ((!defined $apptype) || ($apptype eq ""));
+
+    # We already have the path in the content window below, so save space
+    # print "<center><tt>$mnt$Args::args{'dir'}</tt>\n";
+    print "<center>\n";
+
+    my $url =
+        "&$Args::baseargs&dir=$Args::enc_args{'dir'}"
+      . "&meta=$Args::enc_args{'meta'}&recmode=$recmode";
+
+    # Print the options for output display
+    print "<table cellspacing=\"0\" cellpadding=\"2\">\n<tr>\n"
+      . "<td>ASCII (<a href=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::CONT&"
+      . "sort=$FIL_SORT_ASC$url\" target=\"cont2\">display</a> - "
+      . "<a href=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::REPORT&"
+      . "sort=$FIL_SORT_ASC$url\" target=\"_blank\">report</a>)</td>\n"
+      . "<td>*</td>\n"
+      . "<td>Hex ("
+      . "<a href=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::CONT&"
+      . "sort=$FIL_SORT_HEX$url\" target=\"cont2\">display</a> - "
+      . "<a href=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::REPORT&"
+      . "sort=$FIL_SORT_HEX$url\" target=\"_blank\">report</a>)</td>\n"
+      . "<td>*</td>\n"
+      . "<td>ASCII Strings ("
+      . "<a href=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::CONT&"
+      . "sort=$FIL_SORT_STR$url\" target=\"cont2\">display</a> - "
+      . "<a href=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::REPORT&"
+      . "sort=$FIL_SORT_STR$url\" target=\"_blank\">report</a>)</td>\n"
+      . "<td>*</td>\n"
+      . "<td><a href=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::EXPORT&$url\">"
+      . "Export</a></td>\n";
+
+    # if the file is either image or HTML, then let them view it
+    if (   ($apptype =~ /image data/)
+        || ($apptype =~ /PC bitmap data/))
+    {
+        print "<td>*</td>\n<td><a href=\"$::PROGNAME?"
+          . "mod=$::MOD_FILE&view=$File::CONT_IMG$url\""
+          . "target=\"cont2\">View</a></td>\n";
+    }
+    elsif ($apptype =~ /HTML document text/) {
+        print "<td>*</td>\n<td><a href=\"$::PROGNAME?"
+          . "mod=$::MOD_APPVIEW&view=$Appview::CELL_FRAME$url\""
+          . "target=\"_blank\">View</a></td>\n";
+    }
+
+    print "<td>*</td>\n"
+      . "<td><a href=\"$::PROGNAME?mod=$::MOD_NOTES&view=$Notes::ENTER_FILE$url\" target=\"_blank\">"
+      . "Add Note</a></td>\n"
+      if ($::USE_NOTES == 1);
+
+    print "</tr></table>\n";
+
+    print "File Type: $apptype\n";
+    print
+      "<br><font color=\"$::DEL_COLOR[0]\">Deleted File Recovery Mode</font>\n"
+      if ($recmode == $File::REC_YES);
+    print "</center>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+#
+# Display the actual content here
+#
+# NOTE: This has a media type of raw text
+#
+sub content {
+    Args::check_sort();
+    Args::check_recmode();
+
+    Print::print_text_header();
+
+    my $sort    = Args::get_sort();
+    my $meta    = Args::get_meta('meta');
+    my $vol     = Args::get_vol('vol');
+    my $mnt     = $Caseman::vol2mnt{$vol};
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $recflag = "";
+    $recflag = " -r " if (Args::get_recmode() == $File::REC_YES);
+
+    my $fname = "$mnt$Args::args{'dir'}";
+    $fname =~ s/\/\//\//g;
+
+    local *OUT;
+    if ($sort == $FIL_SORT_ASC) {
+        Print::log_host_inv(
+            "$Caseman::vol2sname{$vol}: Viewing $fname ($meta) as ASCII");
+
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype $recflag -o $offset -i $imgtype $img $meta"
+        );
+
+        print "Contents Of File: $fname\n\n\n";
+        Print::print_output($_) while ($_ = Exec::read_pipe_data(*OUT, 1024));
+        close(OUT);
+    }
+    elsif ($sort == $FIL_SORT_HEX) {
+        Print::log_host_inv(
+            "$Caseman::vol2sname{$vol}: Viewing $fname ($meta) as Hex");
+
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype $recflag -o $offset -i $imgtype $img $meta"
+        );
+
+        print "Hex Contents Of File: $fname\n\n\n";
+        my $offset = 0;
+        while ($_ = Exec::read_pipe_data(*OUT, 1024)) {
+            Print::print_hexdump($_, $offset * 1024);
+            $offset++;
+        }
+        close(OUT);
+    }
+    elsif ($sort == $FIL_SORT_STR) {
+        Print::log_host_inv(
+            "$Caseman::vol2sname{$vol}: Viewing $fname ($meta) as strings");
+
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype $recflag -o $offset -i $imgtype $img $meta | '$::TSKDIR/srch_strings' -a"
+        );
+
+        print "ASCII String Contents Of File: $fname\n\n\n\n";
+        Print::print_output($_) while ($_ = Exec::read_pipe_line(*OUT));
+        close(OUT);
+    }
+
+    Print::print_text_footer();
+
+    return 0;
+}
+
+sub content_img {
+
+    Print::print_html_header("image content");
+
+    my $vol   = Args::get_vol('vol');
+    my $mnt   = $Caseman::vol2mnt{$vol};
+    my $fname = "$mnt$Args::args{'dir'}";
+    $fname =~ s/\/\//\//g;
+
+    my $url =
+        "&$Args::baseargs&meta=$Args::enc_args{'meta'}"
+      . "&dir=$Args::enc_args{'dir'}&"
+      . "cell_mode=2&recmode=$Args::enc_args{'recmode'}";
+
+    print "<tt>$fname</tt><br><br>\n"
+      . "<table><tr>\n"
+      . "<td width=250 align=\"center\">"
+      . "<b>Thumbnail:</b><br>"
+      . "<img src=\"$::PROGNAME?mod=$::MOD_APPVIEW&view=$Appview::CELL_CONT${url}\" width=\"200\"></td>\n"
+      . "<td valign=top>"
+      . "<a href=\"$::PROGNAME?mod=$::MOD_APPVIEW&view=$Appview::CELL_CONT${url}\" "
+      . "target=_blank>View Full Size Image</a><br>\n</td>\n"
+      . "</tr></table>\n";
+
+    Print::print_html_footer();
+
+    return 0;
+}
+
+# Export the contents of a file
+sub export {
+
+    my $meta = Args::get_meta('meta');
+    my $vol  = Args::get_vol('vol');
+    my $mnt  = $Caseman::vol2mnt{$vol};
+
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $fname = "$mnt$Args::args{'dir'}";
+    $fname =~ s/\/\//\//g;
+
+    my $recflag = "";
+
+    $recflag = " -r "
+      if ( (exists $Args::enc_args{'recmode'})
+        && ($Args::enc_args{'recmode'} == $File::REC_YES));
+
+    Print::log_host_inv(
+        "$Caseman::vol2sname{$vol}: Saving contents of $fname ($meta)");
+
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+        "'$::TSKDIR/icat' -f $ftype $recflag -o $offset -i $imgtype $img $meta"
+    );
+
+    # 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::print_oct_header("$vol-${fname}");
+
+    print "$_" while ($_ = Exec::read_pipe_data(*OUT, 1024));
+
+    Print::print_oct_footer();
+
+    return 0;
+}
+
+# Display a report for a file
+# This is intended to have its own window
+#
+sub report {
+    Args::check_sort();
+
+    my $sort = Args::get_sort();
+    my $vol  = Args::get_vol('vol');
+    my $meta = Args::get_meta('meta');
+    my $mnt  = $Caseman::vol2mnt{$vol};
+
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+    my $type;
+    my $fname = "$mnt$Args::args{'dir'}";
+    $fname =~ s/\/\//\//g;
+    my $tz = "";
+    $tz = "-z '$Caseman::tz'" unless ("$Caseman::tz" eq "");
+
+    my $recflag = "";
+
+    $recflag = " -r "
+      if ( (exists $Args::enc_args{'recmode'})
+        && ($Args::enc_args{'recmode'} == $File::REC_YES));
+
+    # 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::print_text_header("filename=$Args::args{'vol'}-${fname}.txt");
+
+    $fname = "$mnt$Args::args{'dir'}";
+    if ($sort == $FIL_SORT_ASC) {
+        Print::log_host_inv(
+"$Caseman::vol2sname{$vol}: Generating ASCII report for $fname ($meta)"
+        );
+        $type = "ASCII";
+    }
+    elsif ($sort == $FIL_SORT_HEX) {
+        Print::log_host_inv(
+            "$Args::args{'vol'}: Generating Hex report for $fname ($meta)");
+        $type = "Hex";
+    }
+    elsif ($sort == $FIL_SORT_STR) {
+        Print::log_host_inv(
+"$Args::args{'vol'}: Generating ASCII strings report for $fname ($meta)"
+        );
+        $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\n\n"
+      . "-" x 70 . "\n"
+      . "                   GENERAL INFORMATION\n\n"
+      . "File: $fname\n";
+
+    # Calculate the MD5 value
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype $recflag -o $offset -i $imgtype $img $meta | '$::MD5_EXE'"
+    );
+    my $md5 = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $md5 = "Error getting MD5 Value"
+      if ((!defined $md5) || ($md5 eq ""));
+
+    chomp $md5;
+    if ($recflag eq "") {
+        print "MD5 of file: $md5\n";
+    }
+    else {
+        print "MD5 of recovered file: $md5\n";
+    }
+
+    if ($::SHA1_EXE ne "") {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype $recflag -o $offset -i $imgtype $img $meta | '$::SHA1_EXE'"
+        );
+        my $sha1 = Exec::read_pipe_line(*OUT);
+        close(OUT);
+
+        $sha1 = "Error getting SHA-1 Value"
+          if ((!defined $sha1) || ($sha1 eq ""));
+
+        chomp $sha1;
+        if ($recflag eq "") {
+            print "SHA-1 of file: $sha1\n";
+        }
+        else {
+            print "SHA-1 of recovered file: $sha1\n";
+        }
+    }
+
+    if ($sort == $FIL_SORT_STR) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype $recflag -o $offset -i $imgtype $img $meta | '$::TSKDIR/srch_strings' -a | '$::MD5_EXE'"
+        );
+        $md5 = Exec::read_pipe_line(*OUT);
+        close(OUT);
+
+        $md5 = "Error getting MD5 Value"
+          if ((!defined $md5) || ($md5 eq ""));
+
+        chomp $md5;
+        print "MD5 of ASCII strings: $md5\n";
+
+        if ($::SHA1_EXE ne "") {
+            Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype $recflag -o $offset -i $imgtype $img $meta | '$::TSKDIR/srch_strings' -a | '$::SHA1_EXE'"
+            );
+            $sha1 = Exec::read_pipe_line(*OUT);
+            close(OUT);
+
+            $sha1 = "Error getting SHA-1 Value"
+              if ((!defined $sha1) || ($sha1 eq ""));
+
+            chomp $sha1;
+            print "SHA-1 of ASCII strings: $sha1\n";
+        }
+    }
+
+    print "\nImage: $Caseman::vol2path{$vol}\n";
+    if (($Caseman::vol2start{$vol} == 0) && ($Caseman::vol2end{$vol} == 0)) {
+        print "Offset: Full image\n";
+    }
+    elsif ($Caseman::vol2end{$vol} == 0) {
+        print "Offset: $Caseman::vol2start{$vol} to end\n";
+    }
+    else {
+        print "Offset: $Caseman::vol2start{$vol} to $Caseman::vol2end{$vol}\n";
+    }
+    print "File System Type: $ftype\n";
+
+    my $date = localtime();
+    print "\nDate Generated: $date\n"
+      . "Investigator: $Args::args{'inv'}\n\n"
+      . "-" x 70 . "\n"
+      . "                   META DATA INFORMATION\n\n";
+
+    # Get the meta details
+    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/istat' -f $ftype $tz -s $Caseman::ts -o $offset -i $imgtype $img $meta"
+    );
+    print $_ while ($_ = Exec::read_pipe_line(*OUT));
+    close(OUT);
+
+    # File Type
+    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype $recflag -o $offset -i $imgtype $img $meta | '$::FILE_EXE' -z -b -"
+    );
+    my $apptype = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $apptype = "Error getting file type"
+      if ((!defined $apptype) || ($apptype eq ""));
+
+    print "\nFile Type: $apptype";
+
+    print "\n" . "-" x 70 . "\n";
+    if ($sort == $FIL_SORT_ASC) {
+        print "           CONTENT (Non-ASCII data may not be shown)\n\n";
+    }
+    else {
+        print "                        CONTENT\n\n";
+    }
+
+    if ($sort == $FIL_SORT_ASC) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype $recflag -o $offset -i $imgtype $img $meta"
+        );
+        Print::print_output($_) while ($_ = Exec::read_pipe_data(*OUT, 1024));
+        close(OUT);
+    }
+    elsif ($sort == $FIL_SORT_HEX) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype $recflag -o $offset -i $imgtype $img $meta"
+        );
+        my $offset = 0;
+        while ($_ = Exec::read_pipe_data(*OUT, 1024)) {
+            Print::print_hexdump($_, $offset * 1024);
+            $offset++;
+        }
+        close(OUT);
+    }
+    elsif ($sort == $FIL_SORT_STR) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype $recflag -o $offset -i $imgtype $img $meta | '$::TSKDIR/srch_strings' -a"
+        );
+        Print::print_output($_) while ($_ = Exec::read_pipe_line(*OUT));
+        close(OUT);
+    }
+
+    print "\n"
+      . "-" x 70 . "\n"
+      . "                   VERSION INFORMATION\n\n"
+      . "Autopsy Version: $::VER\n";
+    print "The Sleuth Kit Version: " . ::get_tskver() . "\n";
+
+    Print::print_text_footer();
+    return 0;
+}
+
+# Generate the MD5 value for every file in a given directory and save
+# them to a text file
+sub md5list {
+    my $vol  = Args::get_vol('vol');
+    my $meta = Args::get_meta('meta');
+    my $mnt  = $Caseman::vol2mnt{$vol};
+
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $fname = "$mnt$Args::args{'dir'}";
+    $fname = 'root' if ($fname eq '/');
+    $fname =~ s/\/\//\//g;
+
+    # 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::print_text_header("filename=$fname.md5");
+
+    $fname = "$mnt$Args::args{'dir'}";
+    $fname =~ s/\/\//\//g;
+
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+        "'$::TSKDIR/fls' -f $ftype -Fu -o $offset -i $imgtype $img $meta");
+
+    print "MD5 Values for files in $fname ($Caseman::vol2sname{$vol})\n\n";
+
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+
+        # area for allocated files
+        if (   (/r\/[\w\-]\s+([\d\-]+):\s+(.*)$/)
+            || (/-\/r\s+([\d\-]+):\s+(.*)$/))
+        {
+            my $in   = $1;
+            my $name = $2;
+
+            local *OUT_MD5;
+            Exec::exec_pipe(*OUT_MD5,
+"'$::TSKDIR/icat' -f $ftype -r -o $offset -i $imgtype $img $in | '$::MD5_EXE'"
+            );
+            my $md5out = Exec::read_pipe_line(*OUT_MD5);
+
+            $md5out = "Error calculating MD5"
+              if ((!defined $md5out) || ($md5out eq ""));
+
+            chomp $md5out;
+            print "$md5out\t" . Print::html_encode($name) . "\n";
+            close(OUT_MD5);
+        }
+        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 file (invalid characters?): $_\n";
+        }
+    }
+    close(OUT);
+
+    Print::print_text_footer();
+
+    return 0;
+}
+
+# Blank Page
+sub blank {
+    Print::print_html_header("");
+    print "<br><center><h3>File Browsing Mode</h3><br>\n"
+      . "<p>In this mode, you can view file and directory contents.</p>\n"
+      . "<p>File contents will be shown in this window.<br>\n"
+      . "More file details can be found using the Metadata link at the end of the list (on the right).<br>\n"
+      . "You can also sort the files using the column headers</p>\n";
+    Print::print_html_footer();
+    return 0;
+}
+
diff --git a/lib/Filesystem.pm b/lib/Filesystem.pm
new file mode 100644
index 0000000000000000000000000000000000000000..935a22b11be3faf6597de212ee6944a91d0031f3
--- /dev/null
+++ b/lib/Filesystem.pm
@@ -0,0 +1,170 @@
+#
+# File system layer functions
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2005 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 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.
+
+# Updated 1/13
+
+package Filesystem;
+
+$Filesystem::STATS = 0;
+
+sub main {
+
+    # By default, show the main window
+    $Args::args{'view'} = $Args::enc_args{'view'} = $Filesystem::STATS
+      unless (exists $Args::args{'view'});
+
+    Args::check_view();
+    my $view = Args::get_view();
+
+    # Check Basic Args
+    Args::check_vol('vol');
+
+    # These windows don't need the meta data address
+    if ($view == $Filesystem::STATS) {
+        return stats();
+    }
+    else {
+        Print::print_check_err("Invalid File System View");
+    }
+}
+
+sub stats_disk {
+    Print::print_html_header("Disk Status");
+
+    my $vol     = Args::get_vol('vol');
+    my $img     = $Caseman::vol2path{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $dtype   = $Caseman::vol2dtype{$vol};
+
+    # Run 'mmls' on the image
+    Exec::exec_pipe(*OUT,
+        "'$::TSKDIR/mmls' -o $offset -i $imgtype -t $dtype -r $img");
+
+    # cycle through results and add each to table with file system type
+    print "<center><h3>Disk Image Details</h3></center>\n";
+    print "<b>PARTITION INFORMATION</b><p>\n";
+
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        print "<tt>$_</tt><br>\n";
+    }
+    return 0;
+
+}
+
+############ FILE SYSTEM ##################
+sub stats {
+
+    my $vol = Args::get_vol('vol');
+
+    return stats_disk() if ($Caseman::vol2cat{$vol} eq "disk");
+
+    Print::print_html_header("File System Status");
+
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    Print::log_host_inv(
+        "$Caseman::vol2sname{$vol}: Displaying file system details");
+    print "<center><h3>General File System Details</h3></center><p>\n";
+
+    my $fat = 0;
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+        "'$::TSKDIR/fsstat' -f $ftype -o $offset -i $imgtype $img");
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+
+        if (/\-\-\-\-\-\-\-\-\-\-/) {
+
+            # Ignore these and print them ahead of the headers
+        }
+
+        # need the space to prevent NTFS STD_INFORMATION from triggering it
+        elsif (/ INFORMATION/) {
+            print "<hr><b>$_</b><p>\n";
+        }
+        elsif (($ftype =~ /fat/) && ($_ =~ /FAT CONTENTS/)) {
+            print "<hr><b>$_</b><p>\n";
+
+            # Set the flag if we reach the FAT
+            $fat = 1;
+        }
+
+        # Special case for FAT
+        # We will be giving hyperlinks in the FAT table dump
+        elsif ($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?$Args::baseargs&mod=$::MOD_FRAME&submod=$::MOD_DATA&"
+                  . "block=$blk&len=$len\" target=\"_top\">$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>";
+        }
+    }
+    close(OUT);
+
+    Print::print_html_footer();
+    return 0;
+}
+
+1;
diff --git a/lib/Frame.pm b/lib/Frame.pm
new file mode 100644
index 0000000000000000000000000000000000000000..20e107f45741cc65956ffe58b3ed0edd685fd072
--- /dev/null
+++ b/lib/Frame.pm
@@ -0,0 +1,336 @@
+#
+# Functions to create the tabs and frame of the main browsing mode
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2005 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 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.
+
+package Frame;
+
+$Frame::IMG_FRAME = 0;
+$Frame::IMG_TABS  = 1;
+$Frame::IMG_BLANK = 2;
+
+sub main {
+    Args::check_vol('vol');
+
+    # By default, show the main frame
+    $Args::args{'view'} = $Args::enc_args{'view'} = $Frame::IMG_FRAME
+      unless (exists $Args::args{'view'});
+
+    Args::check_view();
+    my $view = Args::get_view();
+
+    if ($view == $Frame::IMG_FRAME) {
+        vol_browse_frame();
+    }
+    elsif ($view == $Frame::IMG_TABS) {
+        vol_browse_tabs();
+    }
+    elsif ($view == $Frame::IMG_BLANK) {
+        vol_browse_blank();
+    }
+    else {
+        Print::print_check_err("Invalid Frame View");
+    }
+
+    return 0;
+}
+
+# create the frame for the tabs on top and the generic message on the bottom
+sub vol_browse_frame {
+    Print::print_html_header_frameset(
+        "$Args::args{'case'}:$Args::args{'host'}:$Args::args{'vol'}");
+
+    my $submod = $::MOD_FRAME;
+    $submod = Args::get_submod() if (exists $Args::args{'submod'});
+
+    # Print the rest of the frames
+    my $str  = "";
+    my $view = "";
+
+    if ($submod == $::MOD_FILE) {
+        $str .= "&meta=$Args::args{'meta'}"   if (exists $Args::args{'meta'});
+        $str .= "&dir=$Args::args{'dir'}"     if (exists $Args::args{'dir'});
+        $str .= "&sort=$Args::args{'sort'}"   if (exists $Args::args{'sort'});
+        $str .= "&dmode=$Args::args{'dmode'}" if (exists $Args::args{'dmode'});
+    }
+    elsif ($submod == $::MOD_DATA) {
+        $str .= "&block=$Args::args{'block'}" if (exists $Args::args{'block'});
+        $str .= "&len=$Args::args{'len'}"     if (exists $Args::args{'len'});
+    }
+    elsif ($submod == $::MOD_META) {
+        $str .= "&meta=$Args::args{'meta'}" if (exists $Args::args{'meta'});
+    }
+    elsif ($submod == $::MOD_FRAME) {
+        $view = "&view=$Frame::IMG_BLANK";
+    }
+
+    print <<EOF;
+
+<frameset rows=\"40,*\">
+  <frame src=\"$::PROGNAME?mod=$::MOD_FRAME&view=$Frame::IMG_TABS&$Args::baseargs&submod=$submod\">
+
+  <frame src=\"$::PROGNAME?mod=$submod$view&$Args::baseargs$str\">
+</frameset>
+
+<NOFRAMES>
+  <center>
+    Autopsy requires a browser that supports frames.
+  </center>
+</NOFRAMES>
+
+EOF
+
+    Print::print_html_footer_frameset();
+    return 0;
+}
+
+# Display a message when the image is opened (below the tabs)
+sub vol_browse_blank {
+    Print::print_html_header("Main Message");
+
+    print <<EOF;
+
+<center>
+  <br><br><br><br><br><br><br>
+  To start analyzing this volume, choose an analysis mode from the tabs above.
+</center>
+
+EOF
+    Print::print_html_footer();
+    return 0;
+}
+
+sub vol_browse_tabs {
+    Args::check_submod();
+    Print::print_html_header_tabs("Mode Tabs");
+
+    my $submod = Args::get_submod();
+    my $vol    = Args::get_vol('vol');
+
+    my $special = 0;
+    $special = 1
+      unless (($Caseman::vol2cat{$vol} eq "part")
+        && ($Fs::is_fs{$Caseman::vol2ftype{$vol}} == 1));
+
+    #      if ( ($Caseman::vol2ftype{$vol} eq "strings")
+    #        || ($Caseman::vol2ftype{$vol} eq "blkls")
+    #        || ($Caseman::vol2ftype{$vol} eq "swap")
+    #        || ($Caseman::vol2ftype{$vol} eq "raw"));
+
+    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?mod=$::MOD_FRAME&submod=$::MOD_FILE&$Args::baseargs\""
+          . "target=\"_top\">";
+
+        # Current
+        if ($submod == $::MOD_FILE) {
+            print "<img border=0 "
+              . "src=\"pict/main_t_fil_cur.jpg\" "
+              . "width=116 height=38 "
+              . "alt=\"File Analysis (Current Mode)\"></a>";
+        }
+
+        # Link
+        else {
+            print "<img border=0 "
+              . "src=\"pict/main_t_fil_link.jpg\" "
+              . "width=116 height=38 "
+              . "alt=\"File Analysis\"></a>";
+        }
+    }
+
+    # non-link
+    else {
+        print "<img border=0 "
+          . "src=\"pict/main_t_fil_org.jpg\" "
+          . "width=116 height=38 "
+          . "alt=\"File Analysis (not available)\">";
+    }
+
+    # Search
+    print "</td>\n" . "<td align=\"center\" width=116>";
+
+    print
+"<a href=\"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_KWSRCH&$Args::baseargs\""
+      . " target=\"_top\">";
+
+    if ($submod == $::MOD_KWSRCH) {
+        print "<img border=0 "
+          . "src=\"pict/main_t_srch_cur.jpg\" "
+          . "width=116 height=38 "
+          . "alt=\"Keyword Search Mode (Current Mode)\"></a>";
+    }
+    else {
+        print "<img border=0 "
+          . "src=\"pict/main_t_srch_link.jpg\" "
+          . "width=116 height=38 "
+          . "alt=\"Keyword Search Mode\"></a>";
+    }
+
+    # File Type
+    print "</td>\n" . "<td align=\"center\" width=116>";
+
+    if (($special == 0) && ($::LIVE == 0)) {
+
+        print
+"<a href=\"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_APPSORT&$Args::baseargs\""
+          . " target=\"_top\">";
+
+        # Current
+        if ($submod == $::MOD_APPSORT) {
+            print "<img border=0 "
+              . "src=\"pict/main_t_ftype_cur.jpg\" "
+              . "width=116 height=38 "
+              . "alt=\"File Type (Current Mode)\"></a>";
+        }
+        else {
+            print "<img border=0 "
+              . "src=\"pict/main_t_ftype_link.jpg\" "
+              . "width=116 height=38 "
+              . "alt=\"File Type\"></a>";
+        }
+    }
+    else {
+        print "<img border=0 "
+          . "src=\"pict/main_t_ftype_org.jpg\" "
+          . "width=116 height=38 "
+          . "alt=\"File Type (not available)\">";
+    }
+
+    # Image Details
+    print "</td>\n" . "<td align=\"center\" width=116>";
+
+    if (($special == 0) || ($Caseman::vol2cat{$vol} eq "disk")) {
+
+        print
+"<a href=\"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_FS&$Args::baseargs\""
+          . " target=\"_top\">";
+
+        if ($submod == $::MOD_FS) {
+            print "<img border=0 "
+              . "src=\"pict/main_t_img_cur.jpg\" "
+              . "width=116 height=38 "
+              . "alt=\"Image Details Mode (Current Mode)\"></a>";
+        }
+        else {
+            print "<img border=0 "
+              . "src=\"pict/main_t_img_link.jpg\" "
+              . "width=116 height=38 "
+              . "alt=\"Image Details Mode\"></a>";
+        }
+    }
+    else {
+        print "<img border=0 "
+          . "src=\"pict/main_t_img_org.jpg\" "
+          . "width=116 height=38 "
+          . "alt=\"Image Details Mode (not available)\">";
+    }
+
+    # Meta Data
+    print "</td>\n" . "<td align=\"center\" width=116>";
+
+    if ($special == 0) {
+        print
+"<a href=\"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_META&$Args::baseargs\""
+          . " target=\"_top\">";
+
+        if ($submod == $::MOD_META) {
+            print "<img border=0 "
+              . "src=\"pict/main_t_met_cur.jpg\" "
+              . "width=116 height=38 "
+              . "alt=\"Meta Data Mode (Current Mode)\"></a>";
+        }
+        else {
+            print "<img border=0 "
+              . "src=\"pict/main_t_met_link.jpg\" "
+              . "width=116 height=38 "
+              . "alt=\"Meta Data Mode\"></a>";
+        }
+    }
+    else {
+        print "<img border=0 "
+          . "src=\"pict/main_t_met_org.jpg\" "
+          . "width=116 height=38 "
+          . "alt=\"Meta Data Mode (not available)\">";
+    }
+
+    # Data Units
+    print "</td>\n" . "<td align=\"center\" width=116>";
+
+    print
+"<a href=\"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_DATA&$Args::baseargs\""
+      . " target=\"_top\">";
+
+    # Current
+    if ($submod == $::MOD_DATA) {
+        print "<img border=0 "
+          . "src=\"pict/main_t_dat_cur.jpg\" "
+          . "width=116 height=38 "
+          . "alt=\"Data Units Mode (Current Mode)\"></a>";
+    }
+
+    # Link
+    else {
+        print "<img border=0 "
+          . "src=\"pict/main_t_dat_link.jpg\" "
+          . "width=116 height=38 "
+          . "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?mod=$::MOD_CASEMAN&"
+      . "view=$Caseman::VOL_OPEN&$Args::baseargs_novol\" target=\"_top\">"
+      . "<img border=0 src=\"pict/tab_close.jpg\" width=52 "
+      . "alt=\"Close Image\"></a></td>\n";
+
+    print "</tr></table>\n";
+
+    Print::print_html_footer_tabs();
+    return 0;
+}
diff --git a/lib/Fs.pm b/lib/Fs.pm
new file mode 100644
index 0000000000000000000000000000000000000000..cc188012b7be1661057590b6abb2307fb2707975
--- /dev/null
+++ b/lib/Fs.pm
@@ -0,0 +1,171 @@
+#
+package Fs;
+
+$Fs::types[0]  = "ext";
+$Fs::types[1]  = "fat";
+$Fs::types[2]  = "ntfs";
+$Fs::types[3]  = "ufs";
+$Fs::types[4]  = "iso9660";
+$Fs::types[5]  = "-----";
+$Fs::types[6]  = "fat12";
+$Fs::types[7]  = "fat16";
+$Fs::types[8]  = "fat32";
+$Fs::types[9]  = "bsdi";
+$Fs::types[10] = "freebsd";
+$Fs::types[11] = "openbsd";
+$Fs::types[12] = "solaris";
+$Fs::types[13] = "hfs";
+
+# These need to be updated as The Sleuth Kit supports more file systems
+#
+# addr_unit contains the addressable unit per filesystem type
+# first_meta contains the first usable meta address on a system
+# root_meta is the meta address for the root directory (diff than
+# first on ntfs)
+
+$Fs::addr_unit{'disk'}  = 'Sector';
+$Fs::first_addr{'disk'} = 0;
+$Fs::is_fs{'disk'}      = 0;
+
+$Fs::addr_unit{'blkls'}  = 'Unit';
+$Fs::first_addr{'blkls'} = 0;
+$Fs::is_fs{'blkls'}      = 0;
+
+# raw
+$Fs::addr_unit{'raw'}  = 'Unit';
+$Fs::first_addr{'raw'} = 0;
+$Fs::is_fs{'raw'}      = 0;
+
+# Swap
+$Fs::addr_unit{'swap'}  = 'Unit';
+$Fs::first_addr{'swap'} = 0;
+$Fs::is_fs{'swap'}      = 0;
+
+# BSDI
+$Fs::first_meta{'bsdi'} = $Fs::root_meta{'bsdi'} = 2;
+$Fs::first_addr{'bsdi'} = 0;
+$Fs::addr_unit{'bsdi'}  = 'Fragment';
+$Fs::has_ctime{'bsdi'}  = 1;
+$Fs::has_crtime{'bsdi'} = 0;
+$Fs::has_mtime{'bsdi'}  = 1;
+$Fs::meta_str{'bsdi'}   = "Inode";
+$Fs::is_fs{'bsdi'}      = 1;
+
+# FreeBSD
+$Fs::first_meta{'freebsd'} = $Fs::root_meta{'freebsd'} = 2;
+$Fs::first_addr{'freebsd'} = 0;
+$Fs::addr_unit{'freebsd'}  = 'Fragment';
+$Fs::has_ctime{'freebsd'}  = 1;
+$Fs::has_crtime{'freebsd'} = 0;
+$Fs::has_mtime{'freebsd'}  = 1;
+$Fs::meta_str{'freebsd'}   = "Inode";
+$Fs::is_fs{'freebsd'}      = 1;
+
+# OpenBSD
+$Fs::first_meta{'openbsd'} = $Fs::root_meta{'openbsd'} = 2;
+$Fs::first_addr{'openbsd'} = 0;
+$Fs::addr_unit{'openbsd'}  = 'Fragment';
+$Fs::has_ctime{'openbsd'}  = 1;
+$Fs::has_crtime{'openbsd'} = 0;
+$Fs::has_mtime{'openbsd'}  = 1;
+$Fs::meta_str{'openbsd'}   = "Inode";
+$Fs::is_fs{'openbsd'}      = 1;
+
+# Solaris
+$Fs::first_meta{'solaris'} = $Fs::root_meta{'solaris'} = 2;
+$Fs::first_addr{'solaris'} = 0;
+$Fs::addr_unit{'solaris'}  = 'Fragment';
+$Fs::has_ctime{'solaris'}  = 1;
+$Fs::has_crtime{'solaris'} = 0;
+$Fs::has_mtime{'solaris'}  = 1;
+$Fs::meta_str{'solaris'}   = "Inode";
+$Fs::is_fs{'solaris'}      = 1;
+
+# UFS
+$Fs::first_meta{'ufs'} = $Fs::root_meta{'ufs'} = 2;
+$Fs::first_addr{'ufs'} = 0;
+$Fs::addr_unit{'ufs'}  = 'Fragment';
+$Fs::has_ctime{'ufs'}  = 1;
+$Fs::has_crtime{'ufs'} = 0;
+$Fs::has_mtime{'ufs'}  = 1;
+$Fs::meta_str{'ufs'}   = "Inode";
+$Fs::is_fs{'ufs'}      = 1;
+
+# Linux
+$Fs::first_meta{'linux-ext2'} = $Fs::root_meta{'linux-ext2'} = 2;
+$Fs::first_addr{'linux-ext2'} = 0;
+$Fs::addr_unit{'linux-ext2'}  = 'Fragment';
+$Fs::has_ctime{'linux-ext2'}  = 1;
+$Fs::has_crtime{'linux-ext2'} = 0;
+$Fs::has_mtime{'linux-ext2'}  = 1;
+$Fs::meta_str{'linux-ext2'}   = "Inode";
+$Fs::is_fs{'linux-ext2'}      = 1;
+
+$Fs::first_meta{'linux-ext3'} = $Fs::root_meta{'linux-ext3'} = 2;
+$Fs::first_addr{'linux-ext3'} = 0;
+$Fs::addr_unit{'linux-ext3'}  = 'Fragment';
+$Fs::has_ctime{'linux-ext3'}  = 1;
+$Fs::has_crtime{'linux-ext3'} = 0;
+$Fs::has_mtime{'linux-ext3'}  = 1;
+$Fs::meta_str{'linux-ext3'}   = "Inode";
+$Fs::is_fs{'linux-ext3'}      = 1;
+
+$Fs::first_meta{'ext'} = $Fs::root_meta{'ext'} = 2;
+$Fs::first_addr{'ext'} = 0;
+$Fs::addr_unit{'ext'}  = 'Fragment';
+$Fs::has_ctime{'ext'}  = 1;
+$Fs::has_crtime{'ext'} = 0;
+$Fs::has_mtime{'ext'}  = 1;
+$Fs::meta_str{'ext'}   = "Inode";
+$Fs::is_fs{'ext'}      = 1;
+
+# FAT
+$Fs::first_meta{'fat'} = $Fs::first_meta{'fat12'} = $Fs::first_meta{'fat16'} =
+  $Fs::first_meta{'fat32'} = 1;
+$Fs::root_meta{'fat'}      = $Fs::root_meta{'fat12'} = $Fs::root_meta{'fat16'} =
+  $Fs::root_meta{'fat32'}  = 2;
+$Fs::first_addr{'fat'} = $Fs::first_addr{'fat12'} = $Fs::first_addr{'fat16'} =
+  $Fs::first_addr{'fat32'} = 0;
+$Fs::addr_unit{'fat'}      = $Fs::addr_unit{'fat12'} = $Fs::addr_unit{'fat16'} =
+  $Fs::addr_unit{'fat32'}  = 'Sector';
+$Fs::has_ctime{'fat'} = $Fs::has_ctime{'fat12'} = $Fs::has_ctime{'fat16'} =
+  $Fs::has_ctime{'fat32'} = 0;
+$Fs::has_crtime{'fat'} = $Fs::has_crtime{'fat12'} = $Fs::has_crtime{'fat16'} =
+  $Fs::has_crtime{'fat32'} = 1;
+$Fs::has_mtime{'fat'}      = $Fs::has_mtime{'fat12'} = $Fs::has_mtime{'fat16'} =
+  $Fs::has_mtime{'fat32'}  = 1;
+$Fs::meta_str{'fat'} = $Fs::meta_str{'fat12'} = $Fs::meta_str{'fat16'} =
+  $Fs::meta_str{'fat32'} = "Dir Entry";
+$Fs::is_fs{'fat'}        = $Fs::is_fs{'fat12'} = $Fs::is_fs{'fat16'} =
+  $Fs::is_fs{'fat32'}    = 1;
+
+# NTFS
+$Fs::first_meta{'ntfs'} = 0;
+$Fs::root_meta{'ntfs'}  = 5;
+$Fs::first_addr{'ntfs'} = 0;
+$Fs::addr_unit{'ntfs'}  = 'Cluster';
+$Fs::has_ctime{'ntfs'}  = 1;
+$Fs::has_crtime{'ntfs'} = 1;
+$Fs::has_mtime{'ntfs'}  = 1;
+$Fs::meta_str{'ntfs'}   = "MFT Entry";
+$Fs::is_fs{'ntfs'}      = 1;
+
+# ISO9660
+$Fs::first_meta{'iso9660'} = $Fs::root_meta{'iso9660'} = 0;
+$Fs::first_addr{'iso9660'} = 0;
+$Fs::addr_unit{'iso9660'}  = 'Block';
+$Fs::has_ctime{'iso9660'}  = 0;
+$Fs::has_crtime{'iso9660'} = 1;
+$Fs::has_mtime{'iso9660'}  = 0;
+$Fs::meta_str{'iso9660'}   = "Directory Entry";
+$Fs::is_fs{'iso9660'}      = 1;
+
+# HFS
+$Fs::first_meta{'hfs'} = $Fs::root_meta{'hfs'} = 2;
+$Fs::first_addr{'hfs'} = 0;
+$Fs::addr_unit{'hfs'}  = 'Block';
+$Fs::has_ctime{'hfs'}  = 1;
+$Fs::has_crtime{'hfs'} = 1;
+$Fs::has_mtime{'hfs'}  = 1;
+$Fs::meta_str{'hfs'}   = "Record";
+$Fs::is_fs{'hfs'}      = 1;
diff --git a/lib/Hash.pm b/lib/Hash.pm
new file mode 100644
index 0000000000000000000000000000000000000000..640e38548e0da1e2d27c783e5f52eac6f143bc09
--- /dev/null
+++ b/lib/Hash.pm
@@ -0,0 +1,947 @@
+#
+# Hash database and calculation functions
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2008 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 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.
+
+package Hash;
+
+$Hash::DB_MANAGER  = 1;
+$Hash::DB_LOOKUP   = 2;
+$Hash::DB_INDEX    = 3;
+$Hash::IMG_VERIFY  = 4;
+$Hash::IMG_CALC    = 5;
+$Hash::IMG_LIST_FR = 6;
+$Hash::IMG_LIST    = 7;
+$Hash::BLANK       = 8;
+
+sub main {
+
+    return if ($::LIVE == 1);
+
+    Args::check_view();
+    my $view = Args::get_view();
+
+    if ($view == $Hash::BLANK) {
+        blank();
+        return 0;
+    }
+    elsif ($view == $Hash::DB_MANAGER) {
+        return db_manager();
+    }
+    elsif ($view == $Hash::DB_LOOKUP) {
+        return db_lookup();
+    }
+    elsif ($view == $Hash::DB_INDEX) {
+        return db_index();
+    }
+    elsif ($view == $Hash::IMG_LIST_FR) {
+        return img_list_fr();
+    }
+    elsif ($view == $Hash::IMG_LIST) {
+        return img_list();
+    }
+
+    Args::check_vol('vol');
+    if ($view == $Hash::IMG_CALC) {
+        return img_calc();
+    }
+    elsif ($view == $Hash::IMG_VERIFY) {
+        return img_verify();
+    }
+    else {
+        Print::print_check_err("Invalid Hash View");
+    }
+
+}
+
+sub index_md5sum {
+    my $db = shift;
+    local *OUT;
+    Exec::exec_pipe(*OUT, "'$::TSKDIR/hfind' -i md5sum '$db'");
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        print "$_<br>\n";
+    }
+    close(OUT);
+}
+
+sub index_nsrl {
+    local *OUT;
+    Exec::exec_pipe(*OUT, "'$::TSKDIR/hfind' -i nsrl-md5 '$::NSRLDB'");
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        print "$_<br>\n";
+    }
+    close(OUT);
+}
+
+# Manager/status Window from HOST Manager
+sub db_manager {
+    Print::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 ($Caseman::alert_db eq "") {
+        print "Location: <tt>Not Configured</tt><br>\n";
+    }
+    elsif (-e "$Caseman::alert_db") {
+        print "Location: <tt>$Caseman::alert_db</tt><br>\n";
+        if (-e "$Caseman::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?mod=$::MOD_HASH&"
+          . "view=$Hash::DB_INDEX&hash_alert=1&$Args::baseargs\">"
+          . "<img src=\"pict/but_indexdb.jpg\" alt=\"Index DB\" "
+          . "width=116 height=20 border=\"0\">"
+          . "</a>\n";
+
+        # Lookup Button
+        if (-e "$Caseman::alert_db" . "-md5.idx") {
+            print "<p><b>Lookup</b><br>"
+              . "<form action=\"$::PROGNAME\" method=\"get\">"
+              . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_HASH\">\n"
+              . "<input type=\"hidden\" name=\"view\" value=\"$Hash::DB_LOOKUP\">\n"
+              . "<input type=\"hidden\" name=\"hash_alert\" value=\"1\">\n"
+              . Args::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\" "
+              . "width=116 height=20 border=\"0\">\n"
+              . "</td></tr>\n</table>\n"
+              . "</form>";
+        }
+    }
+    else {
+        print "Location: <tt>$Caseman::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 ($Caseman::exclude_db eq "") {
+        print "Location: <tt>Not Configured</tt><br>\n";
+    }
+    elsif (-e "$Caseman::exclude_db") {
+        print "Location: <tt>$Caseman::exclude_db</tt><br>\n";
+        if (-e "$Caseman::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?mod=$::MOD_HASH&view=$Hash::DB_INDEX&"
+          . "hash_exclude=1&$Args::baseargs\">"
+          . "<img src=\"pict/but_indexdb.jpg\" alt=\"Index DB\" "
+          . "width=116 height=20 border=\"0\">"
+          . "</a>\n";
+
+        # Lookup Button
+        if (-e "$Caseman::exclude_db" . "-md5.idx") {
+            print "<p><b>Lookup</b><br>"
+              . "<form action=\"$::PROGNAME\" method=\"get\">"
+              . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_HASH\">\n"
+              . "<input type=\"hidden\" name=\"view\" value=\"$Hash::DB_LOOKUP\">\n"
+              . "<input type=\"hidden\" name=\"hash_exclude\" value=\"1\">\n"
+              . Args::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\" "
+              . "width=116 height=20 border=\"0\">\n"
+              . "</td></tr>\n</table>\n"
+              . "</form>";
+        }
+    }
+    else {
+        print "Location: <tt>$Caseman::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 <U>bad</U>.  It is currently
+difficult to distinguish between known good and known bad, but the NSRL
+is used in Autopsy to ignore all known files.
+
+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?mod=$::MOD_HASH&view=$Hash::DB_INDEX&"
+          . "hash_nsrl=1&$Args::baseargs\">"
+          . "<img src=\"pict/but_indexdb.jpg\" alt=\"Index DB\" "
+          . "width=116 height=20 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=\"mod\" value=\"$::MOD_HASH\">\n"
+              . "<input type=\"hidden\" name=\"view\" value=\"$Hash::DB_LOOKUP\">\n"
+              . "<input type=\"hidden\" name=\"hash_nsrl\" value=\"1\">\n"
+              . Args::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=\"Lookup\" width=116 height=20 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?mod=$::MOD_CASEMAN&view=$Caseman::VOL_OPEN&$Args::baseargs\">
+    <img src=\"pict/menu_b_close.jpg\" alt=\"Close\" width=\"167\" height=20 border=\"0\">
+    </a>
+  </td>
+  <td align=center>
+    <a href=\"$::HELP_URL\" target=\"_blank\">
+    <img src=\"pict/menu_b_help.jpg\" alt=\"Help\" 
+    width=\"167\" height=20 border=0>
+    </a>
+  </td>
+</tr>
+</table>
+EOF4
+
+    Print::print_html_footer();
+    return 0;
+}
+
+sub db_index {
+    Print::print_html_header("Hash Database Indexing");
+
+    if (   (exists $Args::args{'hash_exclude'})
+        && ($Args::args{'hash_exclude'} == 1)
+        && ($Caseman::exclude_db ne ""))
+    {
+        Print::log_host_info("Exclude Database Re-Indexed");
+        print "<hr><b>Exclude Database Indexing</b><p>\n";
+        index_md5sum($Caseman::exclude_db);
+    }
+
+    if (   (exists $Args::args{'hash_alert'})
+        && ($Args::args{'hash_alert'} == 1)
+        && ($Caseman::alert_db ne ""))
+    {
+        Print::log_host_info("Alert Database Re-Indexed");
+        print "<hr><b>Alert Database Indexing</b><p>\n";
+        index_md5sum($Caseman::alert_db);
+    }
+
+    if (   (exists $Args::args{'hash_nsrl'})
+        && ($Args::args{'hash_nsrl'} == 1)
+        && ($::NSRLDB ne ""))
+    {
+        Print::log_host_info("NSRL Database Re-Indexed");
+        print "<hr><b>NSRL Database Indexing</b><p>\n";
+        index_nsrl();
+    }
+
+    print "<p>Indexing Complete<br>\n"
+      . "<hr><p>\n<a href=\"$::PROGNAME?mod=$::MOD_HASH&view=$Hash::DB_MANAGER&"
+      . "$Args::baseargs\">\n"
+      . "<img src=\"pict/menu_b_hashdb.jpg\" width=\"167\" "
+      . "height=20 alt=\"Hash Databases\" border=\"0\"></a>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# Lookup hashes in database
+sub db_lookup {
+    Print::print_html_header("Hash Database Lookup");
+
+    unless ((exists $Args::args{'md5'})
+        && ($Args::args{'md5'} =~ /^$::REG_MD5$/o))
+    {
+        Print::print_err("Invalid MD5 Argument");
+    }
+
+    if (   (exists $Args::args{'hash_nsrl'})
+        && ($Args::args{'hash_nsrl'} == 1)
+        && ($::NSRLDB ne ""))
+    {
+        print "<hr><b>NSRL Lookup</b><p>\n";
+
+        if (-e "$::NSRLDB") {
+            local *OUT;
+            Exec::exec_pipe(*OUT,
+                "'$::TSKDIR/hfind' '$::NSRLDB' $Args::args{'md5'}");
+            print "$_<br>\n" while ($_ = Exec::read_pipe_line(*OUT));
+            close(OUT);
+            Print::log_host_inv("NSRL Lookup ($Args::args{'md5'})");
+        }
+        else {
+            print "NSRL Database Missing<br>\n";
+            Print::log_host_inv(
+                "NSRL Lookup ($Args::args{'md5'}) - Database Missing");
+        }
+    }
+
+    if (   (exists $Args::args{'hash_exclude'})
+        && ($Args::args{'hash_exclude'} == 1)
+        && ($Caseman::exclude_db ne ""))
+    {
+        print "<hr><b>Exclude Database Lookup</b><p>\n";
+
+        if (-e "$Caseman::exclude_db") {
+            local *OUT;
+            Exec::exec_pipe(*OUT,
+                "'$::TSKDIR/hfind' '$Caseman::exclude_db' $Args::args{'md5'}");
+            print "$_<br>\n" while ($_ = Exec::read_pipe_line(*OUT));
+            close(OUT);
+            Print::log_host_inv("Exclude Database Lookup ($Args::args{'md5'})");
+        }
+        else {
+            print "Exclude Database Missing<br>\n";
+            Print::log_host_inv(
+"Exclude Database Lookup ($Args::args{'md5'}) - Database Missing"
+            );
+        }
+    }
+
+    if (   (exists $Args::args{'hash_alert'})
+        && ($Args::args{'hash_alert'} == 1)
+        && ($Caseman::alert_db ne ""))
+    {
+        print "<hr><b>Alert Database Lookup</b><p>\n";
+
+        if (-e "$Caseman::alert_db") {
+            local *OUT;
+            Exec::exec_pipe(*OUT,
+                "'$::TSKDIR/hfind' '$Caseman::alert_db' $Args::args{'md5'}");
+            print "$_<br>\n" while ($_ = Exec::read_pipe_line(*OUT));
+            close(OUT);
+            Print::log_host_inv("Alert Database Lookup ($Args::args{'md5'})");
+        }
+        else {
+            print "Alert Database Missing<br>\n";
+            Print::log_host_inv(
+                "Alert Database Lookup ($Args::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?mod=$::MOD_HASH&view=$Hash::DB_MANAGER&"
+      . "$Args::baseargs\" target=\"_top\">\n"
+      . "<img src=\"pict/menu_b_hashdb.jpg\" width=\"167\" "
+      . "height=20 alt=\"Hash Databases\" border=\"0\"></a>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+############ INTEGRITY CHECKS ##################
+
+# Special view 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>$Caseman::vol2sname{$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><td>"
+              . "<form action=\"$::PROGNAME\" method=\"get\" target=\"cont\">\n"
+              . "<input type=\"hidden\" name=\"vol\" value=\"$sort[$i]\">\n"
+              . Args::make_hidden()
+              . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_HASH\">\n"
+              . "<input type=\"hidden\" name=\"view\" value=\"$Hash::IMG_VERIFY\">\n"
+              . "<input type=\"image\" src=\"pict/int_b_valid.jpg\" "
+              . "alt=\"Validate\" border=\"0\">\n"
+              . "</form></td></tr>\n";
+        }
+
+        # we currenly only support integrity for raw and split image formats
+        elsif (($Caseman::vol2itype{$sort[$i]} ne "raw")
+            && ($Caseman::vol2itype{$sort[$i]} ne "split"))
+        {
+            print
+"<td colspan=2>Integrity checks for image type $Caseman::vol2itype{$sort[$i]} not yet supported</td></tr>\n";
+        }
+
+        # Generate New button
+        else {
+            print "<td>&nbsp;</td><td>"
+              . "<form action=\"$::PROGNAME\" method=\"get\" target=\"cont\">\n"
+              . "<input type=\"hidden\" name=\"vol\" value=\"$sort[$i]\">\n"
+              . Args::make_hidden()
+              . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_HASH\">\n"
+              . "<input type=\"hidden\" name=\"view\" value=\"$Hash::IMG_CALC\">\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.
+sub img_list_fr {
+    Print::print_html_header_frameset(
+        "$Args::args{'case'}:$Args::args{'host'} Integrity Check");
+
+    print "<frameset rows=\"80%,20%\">\n";
+
+    # Block List
+    print "<frame src=\"$::PROGNAME?mod=$::MOD_HASH&view=$Hash::IMG_LIST&"
+      . "$Args::baseargs\">\n"
+      . "<frame src=\"$::PROGNAME?mod=$::MOD_HASH&view=$Hash::BLANK&"
+      . "$Args::baseargs\" name=\"cont\">\n"
+      . "</frameset>\n";
+
+    Print::print_html_footer_frameset();
+    return 0;
+}
+
+# Reads the MD5 file to fill in the MENU list for the integrity
+# check mode
+sub img_list {
+    Print::print_html_header("Image Integrity Menu");
+
+    my %md5s;
+    my @blkls;
+    my @str;
+    my @img;
+    my @body;
+    my @tl;
+
+    # Read the known values if the file exists
+    if (open(FILE, "$::host_dir" . "/md5.txt")) {
+
+        # 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.txt: $_<br>\n";
+                return 1;
+            }
+        }
+        close(FILE);
+    }
+
+    # sort the images into the different types
+    foreach my $k (keys %Caseman::vol2cat) {
+        if ($Caseman::vol2cat{$k} eq "image") {
+            push @img, $k;
+        }
+        elsif ($Caseman::vol2ftype{$k} eq "blkls") {
+            push @blkls, $k;
+        }
+        elsif ($Caseman::vol2ftype{$k} eq "strings") {
+            push @str, $k;
+        }
+        elsif ($Caseman::vol2ftype{$k} eq "body") {
+            push @body, $k;
+        }
+        elsif ($Caseman::vol2ftype{$k} eq "timeline") {
+            push @tl, $k;
+        }
+    }
+
+    print "<center><table cellspacing=\"10\" cellpadding=\"2\">";
+
+    #  image files
+    if (scalar @img > 0) {
+        print "<tr><th colspan=3>"
+          . "<img src=\"pict/int_h_img.jpg\" alt=\"Image Files\">"
+          . "</th></tr>\n";
+        my @sort = sort { $a cmp $b } @img;
+        int_menu_print(\%md5s, \@sort);
+    }
+
+    # Unallocated (blkls) images
+    if (scalar @blkls > 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 } @blkls;
+        int_menu_print(\%md5s, \@sort);
+    }
+
+    # Strings files (of blkls 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?$Args::baseargs&mod=$::MOD_CASEMAN&view=$Caseman::VOL_OPEN\" target=\"_top\">
+    <img src=\"pict/menu_b_close.jpg\" alt=\"close\" 
+    width=\"167\" height=20 border=\"0\">
+  </a>
+  </td>
+  <td><a href=\"$::PROGNAME?$Args::baseargs&mod=$::MOD_HASH&view=$Hash::IMG_LIST_FR\" target=\"_top\">
+    <img src=\"pict/menu_b_ref.jpg\" alt=\"Refresh\" 
+    width=\"167\" height=20 border=\"0\">
+  </a>
+  </td>
+  <td align=center>
+    <a href=\"$::HELP_URL\" target=\"_blank\">
+    <img src=\"pict/menu_b_help.jpg\" alt=\"Help\" 
+    width=\"167\" height=20 border=0>
+  </a>
+  </td>
+</tr>
+</table>
+
+EOF
+    Print::print_html_footer();
+    return 0;
+}
+
+# Pass the relative path (images/xyz) of the file.  The MD5 is
+# returned (or NULL) (in all caps)
+sub lookup_md5 {
+    my $vol = shift;
+    my $md5 = "";
+
+    my $md5_file = "$::host_dir/md5.txt";
+
+    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 =~ /$vol$/) {
+                    $md5 = $m;
+                    $md5 =~ tr/[a-f]/[A-F]/;
+                    last;
+                }
+            }
+            else {
+                print "Error reading line $. of $md5_file: $_<br>\n";
+                return "";
+            }
+        }
+        close(FILE);
+    }
+
+    return $md5;
+}
+
+sub img_verify {
+
+    Print::print_html_header("Image Integrity Check");
+
+    my $vol = Args::get_vol('vol');
+
+    my $md5 = lookup_md5($vol);
+
+    if ($md5 eq "") {
+        print
+"The MD5 value of <tt>$Caseman::vol2sname{$vol}</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=\"mod\" value=\"$::MOD_HASH\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Hash::IMG_CALC\">\n"
+          . "<input type=\"hidden\" name=\"vol\" value=\"$vol\">\n"
+          . Args::make_hidden()
+          . "<input type=\"image\" src=\"pict/int_b_calc.jpg\" "
+          . "alt=\"Calculate\" border=\"0\">\n</form>";
+        return 1;
+    }
+
+    Print::log_host_inv("$Caseman::vol2sname{$vol}: Checking image integrity");
+
+    print "Original MD5: <tt>$md5</tt><br>\n";
+
+    # We have the original value, now get the new one
+    my $img = $Caseman::vol2path{$vol};
+
+    my $cur;
+    if ($Caseman::vol2itype{$vol} eq "split") {
+        $cur = calc_md5_split($img);
+    }
+    else {
+        $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";
+            Print::log_host_inv(
+                "$Caseman::vol2sname{$vol}: Image integrity check PASSED");
+        }
+        else {
+            print "<font color=\"$::DEL_COLOR[0]\">Fail: Restore from backup"
+              . "<br>\n";
+
+            Print::log_host_inv(
+                "$Caseman::vol2sname{$vol}: Image integrity check FAILED");
+        }
+        Print::print_html_footer();
+        return 0;
+    }
+    else {
+        print "$cur<br>\n";
+        Print::print_html_footer();
+        return 1;
+    }
+}
+
+# Calculate the MD5 value of a file (given the full path)
+# return the value in upper case
+# This one supports only single files - not split volumes
+sub calc_md5 {
+    my $img = shift;
+
+    my $hit_cnt = 0;
+    $SIG{ALRM} = sub {
+        if (($hit_cnt++ % 5) == 0) {
+            print "+";
+        }
+        else {
+            print "-";
+        }
+        alarm(5);
+    };
+
+    alarm(5);
+    local *OUT;
+    Exec::exec_pipe(*OUT, "'$::MD5_EXE' $img");
+
+    alarm(0);
+    $SIG{ALRM} = 'DEFAULT';
+    print "<br>\n"
+      if ($hit_cnt > 0);
+
+    my $out = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $out = "Error calculating MD5"
+      if ((!defined $out) || ($out eq ""));
+
+    if ($out =~ /^($::REG_MD5)\s+/) {
+        my $m = $1;
+        $m =~ tr/[a-f]/[A-F]/;
+        return $m;
+    }
+    else {
+        return $out;
+    }
+}
+
+# Same as the version above, but this one can do split images
+# it fails though if the file is not a multiple of 512
+sub calc_md5_split {
+    my $img = shift;
+
+    my $hit_cnt = 0;
+    $SIG{ALRM} = sub {
+        if (($hit_cnt++ % 5) == 0) {
+            print "+";
+        }
+        else {
+            print "-";
+        }
+        alarm(5);
+    };
+
+    alarm(5);
+    local *OUT;
+
+    # We use the blkls method so that we can handle split images
+    Exec::exec_pipe(*OUT, "'$::TSKDIR/blkls' -f raw -e $img | '$::MD5_EXE'");
+
+    alarm(0);
+    $SIG{ALRM} = 'DEFAULT';
+    print "<br>\n"
+      if ($hit_cnt > 0);
+
+    my $out = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $out = "Error calculating MD5"
+      if ((!defined $out) || ($out eq ""));
+
+    if ($out =~ /^($::REG_MD5)\s+/) {
+        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 $vol = shift;
+    my $img = $Caseman::vol2path{$vol};
+
+    my $m;
+    if (   (exists $Caseman::vol2itype{$vol})
+        && ($Caseman::vol2itype{$vol} eq "split"))
+    {
+        $m = calc_md5_split($img);
+    }
+    else {
+        $m = calc_md5($img);
+    }
+    Caseman::update_md5($vol, $m) if ($m =~ /^$::REG_MD5$/o);
+    return $m;
+}
+
+sub img_calc {
+    Print::print_html_header("Image Integrity Creation");
+    my $vol = Args::get_vol('vol');
+    print "Calculating MD5 value for <tt>$Caseman::vol2sname{$vol}</tt><br>\n";
+    Print::log_host_inv("$Caseman::vol2sname{$vol}: Calculating MD5 value");
+
+    my $m = int_create_wrap($vol);
+
+    print "MD5: <tt>$m</tt><br>\n";
+    print "<br>Value saved to host file<br><br>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# Conver the 'image' format to the 'volume' format
+# Make one central file
+sub convert {
+    my %img2vol = %{shift()};
+
+    Print::log_host_info("Converting format of MD5 hash files");
+
+    # Get out of here if there are no hash files
+    return 0
+      unless ((-e "$::host_dir" . "$::IMGDIR" . "/md5.txt")
+        || (-e "$::host_dir" . "$::DATADIR" . "/md5.txt"));
+
+    # We are going ot make a single file
+    my $md5_file_new = "$::host_dir" . "/md5.txt";
+    open MD5_NEW, ">$md5_file_new"
+      or die "Can't open writing file: $md5_file_new";
+
+    # Read the md5s for the image directory
+    my $md5_file = "$::host_dir" . "$::IMGDIR" . "/md5.txt";
+    if (open(FILE, $md5_file)) {
+
+        # Read the md5 values into a hash
+        while (<FILE>) {
+            s/^\s+//;
+            s/\s+$//;
+
+            if (/($::REG_MD5)\s+(.*)/o) {
+                my $md5 = $1;
+                my $img = $2;
+
+                unless (exists $img2vol{$img}) {
+                    print STDERR
+"Error finding image during hash file conversion: $img.  Skipping\n";
+                    next;
+                }
+                my $vol = $img2vol{$img};
+
+                print MD5_NEW "$md5 $vol\n";
+            }
+            else {
+                print MD5_NEW "$_";
+            }
+        }
+        close(FILE);
+        rename $md5_file, $md5_file . ".bak";
+    }
+
+    # Now do the data directory
+    $md5_file = "$::host_dir" . "$::DATADIR" . "/md5.txt";
+    if (open(FILE, $md5_file)) {
+
+        # Read the md5 values into a hash
+        while (<FILE>) {
+            s/^\s+//;
+            s/\s+$//;
+
+            if (/($::REG_MD5)\s+(.*)/o) {
+                my $md5 = $1;
+                my $img = $2;
+
+                unless (exists $img2vol{$img}) {
+                    print STDERR
+"Error finding image during hash file conversion: $img.  Skipping\n";
+                    next;
+                }
+                my $vol = $img2vol{$img};
+
+                print MD5_NEW "$md5 $vol\n";
+            }
+            else {
+                print MD5_NEW "$_";
+            }
+        }
+        close(FILE);
+        rename $md5_file, $md5_file . ".bak";
+    }
+
+    close(MD5_NEW);
+    return 0;
+}
+
+# Blank Page
+sub blank {
+    Print::print_html_header("");
+    print "<!-- This Page Intentionally Left Blank -->\n";
+    Print::print_html_footer();
+    return 0;
+}
diff --git a/lib/Kwsrch.pm b/lib/Kwsrch.pm
new file mode 100644
index 0000000000000000000000000000000000000000..a643bfa7bfa26f6a6f9be4277c2d1b135362906a
--- /dev/null
+++ b/lib/Kwsrch.pm
@@ -0,0 +1,954 @@
+#
+# Keyword search mode
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2005 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 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.
+
+package Kwsrch;
+
+require 'search.pl';
+
+$Kwsrch::ENTER      = 1;
+$Kwsrch::RESULTS_FR = 2;
+$Kwsrch::RUN        = 3;
+$Kwsrch::LOAD       = 4;
+$Kwsrch::BLANK      = 5;
+
+my $IMG_DETAILS = 0x80;
+
+sub main {
+
+    # By default, show the main frame
+    $Args::args{'view'} = $Args::enc_args{'view'} = $Kwsrch::ENTER
+      unless (exists $Args::args{'view'});
+
+    Args::check_view();
+    my $view = Args::get_view();
+
+    if ($view == $Kwsrch::BLANK) {
+        blank();
+        return 0;
+    }
+
+    # Check Basic Args
+    Args::check_vol('vol');
+
+    # These windows don't need the meta data address
+    if ($view == $Kwsrch::ENTER) {
+        return enter();
+    }
+    elsif ($view == $Kwsrch::RESULTS_FR) {
+        return results_fr();
+    }
+    elsif ($view == $Kwsrch::RUN) {
+        return run();
+    }
+    elsif ($view == $Kwsrch::LOAD) {
+        return load();
+    }
+    else {
+        Print::print_check_err("Invalid Keyword Search View");
+    }
+}
+
+my $CASE_INSENS = 1;
+my $CASE_SENS   = 0;
+
+my $REG_EXP = 1;
+my $STRING  = 0;
+
+# Form to enter search data
+sub enter {
+    my $vol = Args::get_vol('vol');
+
+    Print::print_html_header("Search on $Caseman::vol2sname{$vol}");
+    my $ftype = $Caseman::vol2ftype{$vol};
+
+    if ($ftype eq 'blkls') {
+        print "<center><h3>Keyword Search of Unallocated Space</h3>\n";
+    }
+    elsif ($ftype eq 'swap') {
+        print "<center><h3>Keyword Search of swap partition</h3>\n";
+    }
+    elsif ($ftype eq 'raw') {
+        print "<center><h3>Keyword Search of raw data</h3>\n";
+    }
+    elsif ($Caseman::vol2cat{$vol} eq "disk") {
+        print "<center><h3>Keyword Search of disk</h3>\n";
+    }
+    else {
+        print
+"<center><h3>Keyword Search of Allocated and Unallocated Space</h3>\n";
+    }
+
+    # @@@ Fix this - caused by writing all results to a file
+    if ($::LIVE == 1) {
+        Print::print_err(
+"Keyword searching is temporarily not available during live analysis mode"
+        );
+    }
+
+    print "<form action=\"$::PROGNAME\" method=\"get\">\n"
+      . "Enter the keyword string or expression to search for:<br> <input type=\"text\" name=\"str\"><br><br>\n"
+      . Args::make_hidden()
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_KWSRCH\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Kwsrch::RESULTS_FR\">\n"
+      . "<input type=\"hidden\" name=\"vol\" value=\"$vol\">\n";
+
+    print "<table width=400><tr>\n"
+      . "<td width=200 align=center><input type=\"checkbox\" name=\"ascii\" value=\"1\" CHECKED>"
+      . "ASCII \n</td>"
+      . "<td width=200 align=center><input type=\"checkbox\" name=\"unicode\" value=\"1\" CHECKED>"
+      . "Unicode</td></tr>\n"
+      . "<tr><td align=center><input type=\"checkbox\" name=\"srch_case\" value=\"$CASE_INSENS\">"
+      . "Case Insensitive</td>\n"
+      . "<td align=center><input type=\"checkbox\" name=\"regexp\" value=\"$REG_EXP\">\n"
+      . "<tt>grep</tt> Regular Expression</td></tr></table>\n"
+      . "<input type=\"image\" src=\"pict/but_search.jpg\" "
+      . "alt=\"Search\" border=\"0\">\n</form>\n";
+
+    if ($::LIVE == 0) {
+        print "<table width=600><tr>\n";
+
+        # If we are a non-blkls image and one exists - make a button to load it
+        if (($ftype ne 'blkls') && (exists $Caseman::vol2blkls{$vol})) {
+            print "<td align=center width=200>"
+              . "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
+              . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_FRAME\">\n"
+              . "<input type=\"hidden\" name=\"submod\" value=\"$::MOD_KWSRCH\">\n"
+              . "<input type=\"hidden\" name=\"vol\" value=\"$Caseman::vol2blkls{$vol}\">\n"
+              . Args::make_hidden()
+              . "<input type=\"image\" src=\"pict/srch_b_lun.jpg\" "
+              . "alt=\"Load Unallocated Image\" border=\"0\">\n<br></form></td>\n";
+        }
+
+        # If we are a blkls and the original exists - make a button to load it
+        elsif (($ftype eq 'blkls')
+            && (exists $Caseman::mod2vol{$vol}))
+        {
+            print "<td align=center width=200>"
+              . "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
+              . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_FRAME\">\n"
+              . "<input type=\"hidden\" name=\"submod\" value=\"$::MOD_KWSRCH\">\n"
+              . "<input type=\"hidden\" name=\"vol\" value=\"$Caseman::mod2vol{$vol}\">\n"
+              . Args::make_hidden()
+              . "<input type=\"image\" src=\"pict/srch_b_lorig.jpg\" "
+              . "alt=\"Load Original Image\" border=\"0\">\n<br></form></td>\n";
+        }
+
+        # Strings Button
+        if (   (!(exists $Caseman::vol2str{$vol}))
+            || (!(exists $Caseman::vol2uni{$vol})))
+        {
+
+            my $dest_vol = $vol;
+            $dest_vol = $Caseman::mod2vol{$vol}
+              if exists($Caseman::mod2vol{$vol});
+
+            print "<td align=center width=200>"
+              . "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
+              . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+              . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_DETAILS\">\n"
+              . "<input type=\"hidden\" name=\"vol\" value=\"$dest_vol\">\n"
+              . Args::make_hidden()
+              . "<input type=\"image\" src=\"pict/srch_b_str.jpg\" "
+              . "alt=\"Extract Strings\" border=\"0\">\n<br></form></td>\n";
+        }
+
+        # Unallocated Space Button
+        if (   ($Fs::is_fs{$ftype})
+            && (!(exists $Caseman::vol2blkls{$vol})))
+        {
+            print "<td align=center width=200>"
+              . "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
+              . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
+              . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_DETAILS\">\n"
+              . "<input type=\"hidden\" name=\"vol\" value=\"$vol\">\n"
+              . Args::make_hidden()
+              . "<input type=\"image\" src=\"pict/srch_b_un.jpg\" "
+              . "alt=\"Extract Unallocated Space\" border=\"0\">\n<br></form></td>\n";
+        }
+
+        print "</tr></table>\n";
+    }
+
+    print "<a href=\"help/grep.html\" target=\"_blank\">"
+      . "Regular Expression Cheat Sheet</a>\n<br><br>\n";
+
+    print "<p><font color=\"red\">NOTE:</font> The keyword search runs "
+      . "<tt>grep</tt> on the image.<br>\n"
+      . "A list of what will and "
+      . "what will not be found is available "
+      . "<a href=\"help/grep_lim.html\" target=\"_blank\">here</a>.<br>\n";
+
+    # Section for previous searches
+    if ($::LIVE == 0) {
+        my $srch_name = get_srch_fname(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_fname($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=\"mod\" value=\"$::MOD_KWSRCH\">\n"
+                  . "<input type=\"hidden\" name=\"view\" value=\"$Kwsrch::RESULTS_FR\">\n"
+                  . "<input type=\"hidden\" name=\"vol\" value=\"$vol\">\n"
+                  . "<input type=\"hidden\" name=\"srchidx\" value=\"$srch_idx\">\n"
+                  . Args::make_hidden();
+
+                print "<input type=\"SUBMIT\" value=\"".Print::html_encode($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 %Kwsrch::auto_srch) {
+
+        $Kwsrch::auto_srch_reg{$r} = 0
+          unless (defined $Kwsrch::auto_srch_reg{$r});
+        $Kwsrch::auto_srch_csense{$r} = 1
+          unless (defined $Kwsrch::auto_srch_csense{$r});
+
+        print "<tr>\n" if ($row_idx == 0);
+
+        # @@@ Make a unicode option in predefined
+
+        print "  <td align=center width=150>\n"
+          . "<form action=\"$::PROGNAME\" method=\"get\">\n"
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_KWSRCH\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Kwsrch::RESULTS_FR\">\n"
+          . "<input type=\"hidden\" name=\"vol\" value=\"$vol\">\n"
+          . "<input type=\"hidden\" name=\"str\" value=\"$Kwsrch::auto_srch{$r}\">\n"
+          . "<input type=\"hidden\" name=\"ascii\" value=\"1\">\n"
+          . Args::make_hidden();
+
+        if ($Kwsrch::auto_srch_reg{$r} == 1) {
+            print
+              "<input type=\"hidden\" name=\"regexp\" value=\"$REG_EXP\">\n";
+        }
+        if ($Kwsrch::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";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# MAIN WITH RESULTS
+# Page that makes frame with the results on left and data units on right
+sub results_fr {
+    my $vol = Args::get_vol('vol');
+
+    # A string was given for a new search
+    if (exists $Args::args{'str'}) {
+        Args::check_str();
+
+        Print::print_html_header_frameset(
+            "Search on $Caseman::vol2sname{$vol} for $Args::args{'str'}");
+
+        print "<frameset cols=\"35%,65%\">\n";
+
+        my $srch_case = "";
+        $srch_case = "&srch_case=$Args::args{'srch_case'}"
+          if (exists $Args::args{'srch_case'});
+
+        my $regexp = "";
+        $regexp = "&regexp=$Args::args{'regexp'}"
+          if (exists $Args::args{'regexp'});
+
+        my $ascii = "";
+        $ascii = "&ascii=$Args::args{'ascii'}"
+          if (exists $Args::args{'ascii'});
+
+        my $unicode = "";
+        $unicode = "&unicode=$Args::args{'unicode'}"
+          if (exists $Args::args{'unicode'});
+
+        # Block List
+        print "<frame src=\"$::PROGNAME?"
+          . "mod=$::MOD_KWSRCH&view=$Kwsrch::RUN&"
+          . "$Args::baseargs$srch_case$regexp&str=$Args::enc_args{'str'}$ascii$unicode\">\n";
+    }
+    elsif (exists $Args::args{'srchidx'}) {
+        Args::check_srchidx();
+
+        Print::print_html_header_frameset(
+"Search on $Caseman::vol2sname{$vol} for Index $Args::args{'srchidx'}"
+        );
+
+        print "<frameset cols=\"35%,65%\">\n";
+
+        # Block List
+        print "<frame src=\"$::PROGNAME?"
+          . "mod=$::MOD_KWSRCH&view=$Kwsrch::LOAD&"
+          . "$Args::baseargs&srchidx=$Args::enc_args{'srchidx'}\">\n";
+    }
+
+    # Block Contents
+    print "<frame src=\"$::PROGNAME?mod=$::MOD_KWSRCH&view=$Kwsrch::BLANK&"
+      . "$Args::baseargs\" name=\"content\">\n"
+      . "</frameset>\n";
+
+    Print::print_html_footer_frameset();
+    return 0;
+}
+
+# Find an empty file to save the keyword searches to
+sub find_srch_file {
+    my $vol = Args::get_vol('vol');
+
+    my $out_name = "$::host_dir" . "$::DATADIR/$Caseman::vol2sname{$vol}";
+    my $i;
+    for ($i = 0; -e "${out_name}-${i}.srch"; $i++) { }
+
+    return "${out_name}-${i}.srch";
+}
+
+# Pass the index
+# return the full path of the file returned
+sub get_srch_fname {
+    my $idx = shift;
+    my $vol = Args::get_vol('vol');
+    return "$::host_dir"
+      . "$::DATADIR"
+      . "/$Caseman::vol2sname{$vol}-${idx}.srch";
+}
+
+sub load {
+    Args::check_srchidx();
+
+    Print::print_html_header("");
+
+    if ($::LIVE == 1) {
+        print "Searches cannot be loaded during live analysis<br>\n";
+        return 1;
+    }
+
+    my $srch_name = get_srch_fname($Args::args{'srchidx'});
+
+    print "<b><a href=\"$::PROGNAME?mod=$::MOD_KWSRCH&view=$Kwsrch::ENTER&"
+      . "$Args::baseargs\" "
+      . "target=\"_parent\">New Search</a></b>\n<p>";
+
+    print_srch_results($srch_name);
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# performs actual search, saves hits to file, and calls method to print
+sub run {
+    Args::check_str();
+
+    Print::print_html_header("");
+
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $orig_str = Args::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?mod=$::MOD_KWSRCH&view=$Kwsrch::ENTER&"
+          . "$Args::baseargs\" target=\"_parent\">New Search</a></b>\n<p>";
+        return 1;
+    }
+
+    my $log = "";                   # Log entry string
+
+    my $ascii   = 0;
+    my $unicode = 0;
+
+    if ((exists $Args::args{'ascii'}) && ($Args::args{'ascii'} == 1)) {
+        $ascii = 1;
+        $log .= "ASCII, ";
+    }
+    if ((exists $Args::args{'unicode'}) && ($Args::args{'unicode'} == 1)) {
+        $unicode = 1;
+        $log .= "Unicode, ";
+    }
+
+    if (($ascii == 0) && ($unicode == 0)) {
+        print "You must choose either ASCII or Unicode to search<br>\n";
+        print "<b><a href=\"$::PROGNAME?mod=$::MOD_KWSRCH&view=$Kwsrch::ENTER&"
+          . "$Args::baseargs\" target=\"_parent\">New Search</a></b>\n<p>";
+        return 1;
+    }
+
+    my $grep_flag = "";    # Flags to pass to grep
+
+    # Check if search is case insensitive
+    my $case = 0;
+    if (   (exists $Args::args{'srch_case'})
+        && ($Args::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::args{'regexp'}) && ($Args::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;    # *
+             # We need to add ' to end begin and end of the search as well
+        if ($grep_str =~ /\'/) {
+            $grep_str =~ s/\'/\\\'/g;    # '
+            $grep_str = "'$grep_str'";
+        }
+        $grep_str =~ s/^\-/\\\-/;        # starting with - (mistakes for an arg)
+    }
+
+    Print::log_host_inv(
+        "$Caseman::vol2sname{$vol}: ${log}search for $grep_str");
+
+    # Get the addressable unit of image
+    my $bs = Args::get_unitsize();
+
+    # $norm_str is normalized to find the "hit" in the output
+    my $norm_str = $orig_str;
+
+    # make this lowercase if we are doing case insens
+    $norm_str =~ tr/[A-Z]/[a-z]/ if ($case == 1);
+
+    my $norm_str_len = length($norm_str);
+
+    # array to pass to printing method
+    my @results;
+
+    my $name_uni = "";
+    my $name_asc = "";
+
+    # round 0 is for ASCII and 1 is for Unicode
+    for (my $i = 0; $i < 2; $i++) {
+
+        next if (($i == 0) && ($ascii == 0));
+        next if (($i == 1) && ($unicode == 0));
+
+        @results = ();
+
+        local *OUT;
+
+        my $hit_cnt = 0;
+        $SIG{ALRM} = sub {
+            if (($hit_cnt++ % 5) == 0) {
+                print "+";
+            }
+            else {
+                print "-";
+            }
+            alarm(5);
+        };
+
+        alarm(5);
+
+        if ($i == 0) {
+            print "<b>Searching for ASCII</b>: ";
+        }
+        else {
+            print "<b>Searching for Unicode</b>: ";
+        }
+
+        # if the string is less than 4 chars, then it will not be in the
+        # strings file so it will be searched for the slow way
+        if (length($orig_str) < 4) {
+            my $ltmp = length($orig_str);
+
+            if ($i == 0) {
+                if (   (($ftype eq "raw") || ($ftype eq "swap"))
+                    && ($Caseman::vol2end{$vol} != 0))
+                {
+                    Exec::exec_pipe(*OUT,
+                            "'$::TSKDIR/blkls' -e -f $ftype -i $imgtype $img "
+                          . $Caseman::vol2start{$vol} . "-"
+                          . $Caseman::vol2end{$vol}
+                          . " | '$::TSKDIR/srch_strings' -a -t d -$ltmp | '$::GREP_EXE' $grep_flag '$grep_str'"
+                    );
+                }
+                else {
+                    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkls' -e -f $ftype -o $offset -i $imgtype $img | '$::TSKDIR/srch_strings' -a -t d -$ltmp | '$::GREP_EXE' $grep_flag '$grep_str'"
+                    );
+                }
+            }
+
+            else {
+                if (   (($ftype eq "raw") || ($ftype eq "swap"))
+                    && ($Caseman::vol2end{$vol} != 0))
+                {
+                    Exec::exec_pipe(*OUT,
+                            "'$::TSKDIR/blkls' -e -f $ftype -i $imgtype $img "
+                          . $Caseman::vol2start{$vol} . "-"
+                          . $Caseman::vol2end{$vol}
+                          . " | '$::TSKDIR/srch_strings' -a -t d -e l -$ltmp | '$::GREP_EXE' $grep_flag '$grep_str'"
+                    );
+                }
+                else {
+                    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkls' -e -f $ftype -o $offset -i $imgtype $img | '$::TSKDIR/srch_strings' -a -t d -e l -$ltmp | '$::GREP_EXE' $grep_flag '$grep_str'"
+                    );
+                }
+            }
+        }
+
+        # Use the strings file if it exists
+        elsif (($i == 0) && (defined $Caseman::vol2str{$vol})) {
+            my $str_vol = $Caseman::vol2path{$Caseman::vol2str{$vol}};
+            Exec::exec_pipe(*OUT,
+                "'$::GREP_EXE' $grep_flag '$grep_str' $str_vol");
+        }
+        elsif (($i == 1) && (defined $Caseman::vol2uni{$vol})) {
+            my $str_vol = $Caseman::vol2path{$Caseman::vol2uni{$vol}};
+            Exec::exec_pipe(*OUT,
+                "'$::GREP_EXE' $grep_flag '$grep_str' $str_vol");
+        }
+
+        # Run strings on the image first and then grep that
+        else {
+            if ($i == 0) {
+                if (   (($ftype eq "raw") || ($ftype eq "swap"))
+                    && ($Caseman::vol2end{$vol} != 0))
+                {
+                    Exec::exec_pipe(*OUT,
+                            "'$::TSKDIR/blkls' -e -f $ftype -i $imgtype $img "
+                          . $Caseman::vol2start{$vol} . "-"
+                          . $Caseman::vol2end{$vol}
+                          . " | '$::TSKDIR/srch_strings' -a -t d | '$::GREP_EXE' $grep_flag '$grep_str'"
+                    );
+                }
+                else {
+                    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkls' -e -f $ftype -o $offset -i $imgtype $img | '$::TSKDIR/srch_strings' -a -t d | '$::GREP_EXE' $grep_flag '$grep_str'"
+                    );
+                }
+            }
+            else {
+                if (   (($ftype eq "raw") || ($ftype eq "swap"))
+                    && ($Caseman::vol2end{$vol} != 0))
+                {
+                    Exec::exec_pipe(*OUT,
+                            "'$::TSKDIR/blkls' -e -f $ftype -i $imgtype $img "
+                          . $Caseman::vol2start{$vol} . "-"
+                          . $Caseman::vol2end{$vol}
+                          . " | '$::TSKDIR/srch_strings' -a -t d -e l | '$::GREP_EXE' $grep_flag '$grep_str'"
+                    );
+                }
+                else {
+                    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/blkls' -e -f $ftype -o $offset -i $imgtype $img | '$::TSKDIR/srch_strings' -a -t d -e l | '$::GREP_EXE' $grep_flag '$grep_str'"
+                    );
+                }
+            }
+        }
+
+        alarm(0);
+        $SIG{ALRM} = 'DEFAULT';
+
+        # Cycle through the results and put them in an array
+        while ($_ = Exec::read_pipe_line(*OUT)) {
+
+            # Parse out the byte offset and hit string
+            if (/^\s*(\d+)\s+(.+)$/) {
+                my $off          = $1;
+                my $hit_str_orig = $2;
+                my $idx          = 0;
+
+                # Make a copy that we can modify & play with
+                my $hit_str = $hit_str_orig;
+                $hit_str =~ tr/[A-Z]/[a-z]/ if ($case == 1);
+
+                # How long was the string that we hit?
+                my $hit_str_len = length($hit_str);
+
+                # 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 cycle through all of them
+                my $psize = scalar(@results);
+                while (($idx = index($hit_str, $norm_str, $idx)) > -1) {
+
+                    # 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 + $norm_str_len + 5;
+                    $sum_max = $hit_str_len if ($sum_max > $hit_str_len);
+
+                    my $sum_hit =
+                      substr($hit_str_orig, $sum_min, $sum_max - $sum_min);
+
+                    # remove new lines
+                    $sum_hit =~ s/\n/ /g;
+
+                    # The actual offset for Unicode is 2 bytes per char
+                    my $tmpidx = $idx;
+                    $tmpidx *= 2
+                      if ($i == 1);
+
+                    my $b = int(($off + $tmpidx) / $bs);
+                    my $o = int(($off + $tmpidx) % $bs);
+
+                    push @results, "${b}|${o}|$sum_hit";
+
+                    # advance index to find next hit
+                    $idx++;
+                }
+
+                # If we did not find a term, then just print what
+                # was found-this occurs bc index does not find it
+                # sometimes.
+                if ($psize == scalar(@results)) {
+
+                    my $b = int($off / $bs);
+                    my $o = int($off % $bs);
+
+                    # $hit =~ s/\n//g;
+                    push @results, "${b}|${o}|";
+                    next;
+                }
+            }
+
+            # A negative offset is common on FreeBSD with large images
+            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 grep result: $_<br>\n";
+            }
+        }
+        close(OUT);
+
+        print " <b>Done</b><br>";
+        my $cnt = scalar(@results);
+
+        my $srch_name = "";
+        if ($::LIVE == 0) {
+            print "<b>Saving</b>: ";
+
+            # Find a file to save the results to
+            $srch_name = find_srch_file();
+            unless (open(IDX, ">$srch_name")) {
+                print "Error opening $srch_name\n";
+                return (1);
+            }
+
+            # Print the header
+            if ($i == 0) {
+                print IDX "$cnt|${grep_flag}|${orig_str}|ascii\n";
+                $name_asc = $srch_name;
+            }
+            else {
+                print IDX "$cnt|${grep_flag}|${orig_str}|unicode\n";
+                $name_uni = $srch_name;
+            }
+
+            for (my $a = 0; $a < $cnt; $a++) {
+                print IDX "$results[$a]\n";
+            }
+            close(IDX);
+            print " <b>Done</b><br>\n";
+        }
+        if ($i == 0) {
+            print "$cnt hits";
+            print "- <a href=\"#ascii\">link to results</a>" if ($cnt > 0);
+            print "<br>\n";
+        }
+        else {
+            print "$cnt hits";
+            print "- <a href=\"#unicode\">link to results</a>" if ($cnt > 0);
+            print "<br>\n";
+        }
+        print "<hr>\n";
+    }
+
+    print "<b><a href=\"$::PROGNAME?mod=$::MOD_KWSRCH&view=$Kwsrch::ENTER&"
+      . "$Args::baseargs\" "
+      . "target=\"_parent\">New Search</a></b>\n<p>";
+
+    if ($::LIVE == 0) {
+        if ($ascii == 1) {
+            print_srch_results($name_asc);
+        }
+
+        if ($unicode == 1) {
+            print_srch_results($name_uni);
+        }
+    }
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# Args are search string, grep flags, and array of hits
+sub print_srch_results {
+
+    if (scalar(@_) != 1) {
+        print "Missing Args for print_srch_results()\n";
+        return 1;
+    }
+
+    my $srch_name = shift;
+    my $vol       = Args::get_vol('vol');
+    my $ftype     = $Caseman::vol2ftype{$vol};
+
+    my $addr_str = $Fs::addr_unit{$ftype};
+
+    unless (open(SRCH, "$srch_name")) {
+        print "Error opening search file: $srch_name\n";
+        return 1;
+    }
+
+    my @results;
+    my $grep_str  = "";
+    my $grep_flag = "";
+    my $cnt       = 0;
+    my $type      = 0;    # ASCII iis 0 and Unicode is 1
+
+    my $prev = -1;
+
+    while (<SRCH>) {
+
+        # The first line is a header
+        if ($. == 1) {
+            if (/^(\d+)\|(.*?)?\|(.*)$/) {
+                $cnt       = $1;
+                $grep_flag = $2;
+                $grep_str  = $3;
+                $type      = 0;
+            }
+            else {
+                print "Error pasing header of search file: $srch_name\n";
+                close(SRCH);
+                return 1;
+            }
+
+            if ($grep_str =~ /^(.*?)\|unicode$/) {
+                $grep_str = $1;
+                $type     = 1;
+            }
+            elsif ($grep_str =~ /^(.*?)\|ascii$/) {
+                $grep_str = $1;
+            }
+
+            my $grep_str_html = Print::html_encode($grep_str);
+            print "<hr>\n";
+            if ($type == 0) {
+                print "<a name=\"ascii\">\n";
+            }
+            else {
+                print "<a name=\"unicode\">\n";
+            }
+
+            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 ($type == 0) {
+                print "&nbsp;&nbsp;ASCII<br>\n";
+            }
+            else {
+                print "&nbsp;&nbsp;Unicode<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";
+
+            if ($cnt > 1000) {
+                print "There were more than <U>1000</U> hits.<br>\n";
+                print "Please revise the search to a managable amount.\n";
+                print
+                  "<p>The $cnt hits can be found in: <tt>$srch_name</tt><br>\n";
+                close(SRCH);
+                return 0;
+            }
+
+            next;
+        }
+
+        unless (/^(\d+)\|(\d+)\|(.*)?$/) {
+            print "Error parsing results: $_\n";
+            close(SRCH);
+            return 1;
+        }
+
+        my $blk = $1;
+        my $off = $2;
+        my $str = $3;
+
+        if ($blk != $prev) {
+            my $url =
+"$::PROGNAME?mod=$::MOD_DATA&view=$Data::CONT_MENU_FR&$Args::baseargs&block=$blk";
+
+            print "<br>\n$addr_str $blk (<a href=\"$url&sort=$Data::SORT_HEX\" "
+              . "target=content>Hex</a> - "
+              . "<a href=\"$url&sort=$Data::SORT_ASC\" target=content>"
+              . "Ascii</a>";
+
+            print
+" - <a href=\"$::PROGNAME?$Args::baseargs&mod=$::MOD_DATA&view=$Data::CONT_MENU_FR&"
+              . "mnt=$Args::enc_args{'mnt'}&vol=$Caseman::mod2vol{$vol}&"
+              . "btype=$Data::ADDR_BLKLS&block=$blk\" target=content>Original</a>"
+              if ( ($ftype eq 'blkls')
+                && (exists $Caseman::mod2vol{$vol}));
+
+            print ")<br>";
+            $prev = $blk;
+        }
+
+        my $occ = $. - 1;
+        if ($str ne "") {
+            $str = Print::html_encode($str);
+            print "$occ: $off (<tt>$str</tt>)<br>\n";
+        }
+        else {
+            print "$occ: $off<br>\n";
+        }
+    }
+
+    close(SRCH);
+    return 0;
+}
+
+# Blank Page
+sub blank {
+    Print::print_html_header("");
+    print "<!-- This Page Intentionally Left Blank -->\n";
+    Print::print_html_footer();
+    return 0;
+}
+
+1;
diff --git a/lib/Main.pm b/lib/Main.pm
new file mode 100644
index 0000000000000000000000000000000000000000..88c39f67a72a814b2936c82006889baa58371575
--- /dev/null
+++ b/lib/Main.pm
@@ -0,0 +1,357 @@
+#
+# Main.pm
+# Autopsy Forensic Browser
+#
+# This file requires The Sleuth Kit
+#    www.sleuthkit.org
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2005 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 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.
+#
+
+use lib './';
+use strict;
+
+use Appsort;
+use Appview;
+use Args;
+use Caseman;
+use Data;
+use Exec;
+use File;
+use Filesystem;
+use Frame;
+use Fs;
+use Hash;
+use Kwsrch;
+use Meta;
+use Notes;
+use Print;
+use Timeline;
+use Vs;
+
+require 'conf.pl';
+require 'define.pl';
+
+# Get rid of insecure settings
+$ENV{PATH} = "";
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
+
+# Formats for regular expressions
+# Year.Mon.Day Hr:Min:Sec (TZ)
+$::REG_DAY       = '\d\d\d\d\-\d\d\-\d\d';
+$::REG_TIME      = '\d\d:\d\d:\d\d';
+$::REG_ZONE_ARGS = '[\w\+\-\/\_]+';
+$::REG_ZONE2     = '\([\w\+\- ]*\)';
+$::REG_DATE  = "$::REG_DAY" . '\s+' . "$::REG_TIME" . '\s+' . "$::REG_ZONE2";
+$::REG_FTYPE = '[\w\-]+';
+$::REG_SKEW  = '[\+\-]?\d+';
+$::REG_MTYPE = '[\?bcdflprsvw-]';    # Type according to meta data
+
+$::REG_FILE     = '[\w\-\_\.]+';
+$::REG_CASE     = $::REG_FILE;
+$::REG_HOST     = '[\w\-\_\.]+';
+$::REG_INVESTIG = '[\w]+';
+
+$::REG_IMG           = "$::REG_FILE" . '/' . "$::REG_FILE";
+$::REG_IMG_PATH      = '/[\w\-\_\.\/]+';
+$::REG_IMG_PATH_WILD = '/[\w\-\_\.\/]+\*?';
+$::REG_IMG_CONFIG    = '[\w\-\_\.\/ ]+';
+$::REG_FNAME         = $::REG_FILE;
+$::REG_MNT           = '[\w\-\_\.\/\:\\\\]+';
+$::REG_SEQ_FILE      = '[\w\s\-\_\.\/\:\\\\]+';
+$::REG_HASHDB        = '[\w\-\_\.\,\/]+';
+$::REG_IMGTYPE       = '[\w\,]+';
+$::REG_INAME         = '[\w]+';
+$::REG_VNAME         = '[\w]+';
+
+$::REG_META = '[\d-]+';
+$::REG_MD5  = '[0-9a-fA-F]{32,32}';
+
+$::HELP_URL = "help/index.html";
+
+# host_dir and case_dir will end with a '/'
+$::host_dir = "";
+$::case_dir = "";
+
+################## NEW STUFF ##########################
+# MODULES
+
+# If the values of these are changed, or if new modules are added,
+# Then the below pseudo-binary sort algorithm must be changed as well
+$::MOD_CASEMAN = 0;
+$::MOD_FRAME   = 1;
+$::MOD_FILE    = 2;
+$::MOD_META    = 3;
+$::MOD_KWSRCH  = 4;
+$::MOD_DATA    = 5;
+$::MOD_TL      = 6;
+$::MOD_FS      = 7;
+$::MOD_APPSORT = 8;
+$::MOD_NOTES   = 9;
+$::MOD_HASH    = 10;
+$::MOD_APPVIEW = 11;
+
+# Main Menu
+#
+# Display the title page
+sub welcome {
+    Print::print_html_header_javascript("Autopsy Forensic Browser");
+
+    print "<center>\n";
+
+    # This problem has not been seen with the 1 second delay
+    if ((0) && ($] >= 5.008)) {
+        print
+"<p><font color=\"red\">Warning: You are using Perl v5.8.</font><br>\n"
+          . "  Some buffer problems have been reported with Autopsy and Perl 5.8 "
+          . "where output is not shown.<br>\n"
+          . "Perl 5.6 should be used if available.\n"
+          . "If data is missing, reload the page<br><hr>\n";
+    }
+
+    print <<EOF;
+<table cellspacing=0 cellpadding=2 width=600 height=350 border=0>
+
+<tr>
+  <td colspan=\"3\" align=\"center\" valign=\"MIDDLE\">
+    <b>Autopsy Forensic Browser  $::VER</b>
+  </td>
+</tr>
+<tr>
+  <td colspan=\"3\">&nbsp;</td>
+</tr>
+<tr>
+  <td colspan=\"3\" align=\"center\" valign=\"MIDDLE\">
+    <a href=\"./about\">
+      <img src=\"pict/logo.jpg\" border=0 alt="Logo">
+    </a>
+  </td>
+</tr>
+<tr>
+  <td colspan=\"3\">&nbsp;</td>
+</tr>
+<tr>
+  <td colspan=\"3\" align=\"center\" valign=\"MIDDLE\">
+    <a href="http://www.sleuthkit.org/autopsy/">
+      <tt>http://www.sleuthkit.org/autopsy/</tt>
+    </a>
+  </td>
+</tr>
+<tr><td colspan=3>&nbsp;</td></tr>
+<tr>
+  <td align=center width=200 valign=\"MIDDLE\">
+    <a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&view=$Caseman::CASE_OPEN\">
+      <img src=\"pict/menu_b_copen.jpg\" alt=\"Open Case\" width=176 height=20 border=0>
+    </a>
+  </td>
+  <td align=center width=200 valign=\"MIDDLE\">
+    <a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&view=$Caseman::CASE_NEW\">
+      <img src=\"pict/menu_b_cnew.jpg\" alt=\"New Case\" width=176 height=20 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 height=20 border=0>
+    </a>
+  </td>
+</tr>
+</table>
+
+EOF
+
+    Print::print_html_footer_javascript();
+    return 0;
+}
+
+sub get_tskver {
+    local *OUT;
+    Exec::exec_pipe(*OUT, "'$::TSKDIR/fls' -V");
+
+    my $ver = Exec::read_pipe_line(*OUT);
+    $ver = $1 if ($ver =~ /^The Sleuth Kit ver (.*)$/);
+    close(OUT);
+
+    return $ver;
+}
+
+# This function is called by the code in the 'autopy' file.
+# This will check for the basic module arguments and then host
+# and case accordingly.  The main function of each of the modules
+# is called from here.  Each of the modules will have to take care
+# of the detailed argument checking.
+
+sub main {
+
+    # Parse arguments
+    my $lcl_args = shift;
+    Args::parse_args($lcl_args);
+
+    # When autopsy is first run, no mod or arguments are given.
+    unless (exists $Args::args{'mod'}) {
+
+        # if we are not in live analysis mode, display the usual screen
+        if ($::LIVE == 0) {
+            return welcome();
+        }
+        else {
+
+            # If we are in live analysis mode, open up the window to select
+            # and image and supply basic host and case values.
+            $Args::args{'mod'}  = $Args::enc_args{'mod'}  = $::MOD_CASEMAN;
+            $Args::args{'view'} = $Args::enc_args{'view'} = $Caseman::VOL_OPEN;
+            $Args::args{'case'} = $Args::enc_args{'case'} = "live";
+            $Args::args{'host'} = $Args::enc_args{'host'} = "local";
+            $Args::args{'inv'}  = $Args::enc_args{'inv'}  = "unknown";
+        }
+    }
+
+    Args::check_mod();
+    my $module = Args::get_mod();
+
+    Args::make_baseargs();
+
+    # For live analysis, we need to change the regular expression
+    # for images because it can be a full path (to /dev/xxxxxxx)
+    $::REG_IMG = '/[\w\-\_\.\/]+'
+      if ($::LIVE == 1);
+
+    # The Case Management module is handled seperately because
+    # it may not have the host and case values
+    if ($module == $::MOD_CASEMAN) {
+        return Caseman::main();
+    }
+
+    # Check the minimum arguments
+    Args::check_case();
+    Args::check_host();
+
+    # Set the case and host variables
+    if ($::LIVE == 0) {
+        $::case_dir = "$::LOCKDIR/" . Args::get_case() . "/";
+        $::case_dir =~ s/\/\//\//g;
+        $::host_dir = "$::case_dir" . Args::get_host() . "/";
+        $::host_dir =~ s/\/\//\//g;
+    }
+    else {
+        $::host_dir = "";
+        $::case_dir = "";
+    }
+    Caseman::read_host_config();
+
+    # This is a partial binary sort method to reduce the number of checks
+
+    # 0 < mod < 6
+    if ($module < $::MOD_TL) {
+
+        # 0 < mod < 4
+        if ($module < $::MOD_KWSRCH) {
+
+            # mod == 1
+            if ($module == $::MOD_FRAME) {
+                return Frame::main();
+            }
+
+            # mod == 2
+            elsif ($module == $::MOD_FILE) {
+                return File::main();
+            }
+
+            # mod == 3
+            elsif ($module == $::MOD_META) {
+                return Meta::main();
+            }
+        }
+
+        # 4 <= mod < 6
+        else {
+
+            # mod == 4
+            if ($module == $::MOD_KWSRCH) {
+                return Kwsrch::main();
+            }
+
+            # mod == 5
+            elsif ($module == $::MOD_DATA) {
+                return Data::main();
+            }
+        }
+    }
+
+    # 6 <= mod
+    else {
+
+        # 6 <= mod < 9
+        if ($module < $::MOD_NOTES) {
+
+            # mod == 6
+            if ($module == $::MOD_TL) {
+                return Timeline::main();
+            }
+
+            # mod == 7
+            elsif ($module == $::MOD_FS) {
+                return Filesystem::main();
+            }
+
+            # mod == 8
+            elsif ($module == $::MOD_APPSORT) {
+                return Appsort::main();
+            }
+        }
+
+        # 9 <= mod
+        else {
+
+            # mod == 9
+            if ($module == $::MOD_NOTES) {
+                return Notes::main();
+            }
+
+            # mod == 10
+            elsif ($module == $::MOD_HASH) {
+                return Hash::main();
+            }
+
+            # mod == 11
+            elsif ($module == $::MOD_APPVIEW) {
+                return Appview::main();
+            }
+
+            # New modules can be added here
+
+        }
+    }
+    Print::print_check_err("Invalid Module");
+}
+
+1;
diff --git a/lib/Meta.pm b/lib/Meta.pm
new file mode 100644
index 0000000000000000000000000000000000000000..a0728c06b935707fa341118c94222fbf1a8bf851
--- /dev/null
+++ b/lib/Meta.pm
@@ -0,0 +1,789 @@
+#
+# Metadata mode
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2005 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 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.
+
+# Updated 1/13
+
+package Meta;
+
+$Meta::FRAME  = 0;
+$Meta::ENTER  = 1;
+$Meta::STATS  = 2;
+$Meta::EXPORT = 3;
+$Meta::FFIND  = 4;
+$Meta::LIST   = 5;
+$Meta::REPORT = 6;
+$Meta::BLANK  = 7;
+
+sub main {
+
+    # By default, show the main frame
+    $Args::args{'view'} = $Args::enc_args{'view'} = $Meta::FRAME
+      unless (exists $Args::args{'view'});
+
+    Args::check_view();
+    my $view = Args::get_view();
+
+    # Check Basic Args
+    Args::check_vol('vol');
+
+    # These windows don't need the meta data address
+    if ($view == $Meta::FRAME) {
+        return frame();
+    }
+    elsif ($view == $Meta::ENTER) {
+        return enter();
+    }
+    elsif ($view == $Meta::LIST) {
+        return list();
+    }
+    elsif ($view == $Meta::BLANK) {
+        return blank();
+    }
+
+    # These windows do need the meta data address
+    Args::check_meta('meta');
+    if ($view == $Meta::STATS) {
+        return stats();
+    }
+    elsif ($view == $Meta::FFIND) {
+        return findfile();
+    }
+
+    Args::check_recmode();
+    if ($view == $Meta::EXPORT) {
+        return export();
+    }
+    elsif ($view == $Meta::REPORT) {
+        return report();
+    }
+    else {
+        Print::print_check_err("Invalid Meta View");
+    }
+
+}
+
+# Print the two frames
+sub frame {
+
+    my $vol = Args::get_vol('vol');
+
+    Print::print_html_header_frameset(
+        "Meta Data Browse on $Caseman::vol2sname{$vol}");
+    print "<frameset cols=\"20%,80%\">\n";
+
+    # Print the frame where an addres can be entered and a frame for the
+    # contents
+    if (exists $Args::enc_args{'meta'}) {
+        print
+"<frame src=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::ENTER&$Args::baseargs"
+          . "&meta=$Args::enc_args{'meta'}\">\n"
+          . "<frame src=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::STATS&"
+          . "meta=$Args::enc_args{'meta'}&$Args::baseargs\" "
+          . "name=\"content\">\n</frameset>\n";
+    }
+    else {
+        print
+"<frame src=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::ENTER&$Args::baseargs\">\n"
+          . "<frame src=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::BLANK&$Args::baseargs\" "
+          . "name=\"content\">\n</frameset>\n";
+    }
+
+    Print::print_html_footer_frameset();
+    return 0;
+}
+
+# Generate the frame to enter the data into
+sub enter {
+    Print::print_html_header("");
+    my $vol   = Args::get_vol('vol');
+    my $ftype = $Caseman::vol2ftype{$vol};
+
+    # Address
+    print "<form action=\"$::PROGNAME\" method=\"get\" target=\"content\">\n"
+      . "<b>$Fs::meta_str{$ftype} Number:</b><br>&nbsp;&nbsp&nbsp;&nbsp;"
+      . "<input type=\"text\" name=\"meta\" size=12 maxlength=12";
+
+    print " value=\"$Args::enc_args{'meta'}\"" if exists($Args::args{'meta'});
+
+    print ">\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_META\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Meta::STATS\">\n"
+      . "<input type=\"hidden\" name=\"vol\" value=\"$vol\">\n"
+      . Args::make_hidden()
+      .
+
+      # View Button
+      "<p><input type=\"image\" src=\"pict/but_view.jpg\" "
+      . "width=45 height=22 alt=\"View\" border=\"0\"></form>\n";
+
+    # Allocation List
+    print "<hr><p>"
+      . "<a href=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::LIST&$Args::baseargs\" target=\"content\">"
+      . "<img src=\"pict/but_alloc_list.jpg\" border=\"0\" "
+      . "width=113 height=20 alt=\"Allocation List\">"
+      . "</a>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# Display the contents of meta
+sub stats {
+    Print::print_html_header("");
+
+    my $meta    = Args::get_meta('meta');
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $tz = "";
+    $tz = "-z '$Caseman::tz'" unless ("$Caseman::tz" eq "");
+
+    Print::log_host_inv(
+"$Caseman::vol2sname{$vol}: Displaying details of $Fs::meta_str{$ftype} $meta"
+    );
+
+    my $meta_int = $meta;
+    $meta_int = $1 if ($meta =~ /^(\d+)-\d+(-\d)?/);
+
+    my $prev = $meta_int - 1;
+    my $next = $meta_int + 1;
+
+    # We need to get the allocation status of this structure
+    my $recmode = $File::REC_NO;
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+        "'$::TSKDIR/ils' -f $ftype -e -o $offset -i $imgtype $img $meta_int");
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        chop;
+        next unless ($_ =~ /^$meta_int/);
+        if ($_ =~ /^$meta_int\|f/) {
+            $recmode = $File::REC_YES;
+        }
+        elsif ($_ =~ /^$meta_int\|a/) {
+            $recmode = $File::REC_NO;
+        }
+        else {
+            Print::print_err("Error parsing ils output: $_");
+        }
+    }
+    close(OUT);
+
+    print "<center>\n";
+    print
+"<a href=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::STATS&$Args::baseargs&meta=$prev\">"
+      . "<img src=\"pict/but_prev.jpg\" alt=\"previous\" "
+      . "width=\"89\" height=20 border=\"0\"></a>\n"
+      unless ($prev < $Fs::first_meta{$ftype});
+
+    print
+"<a href=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::STATS&$Args::baseargs&meta=$next\">"
+      . "<img src=\"pict/but_next.jpg\" alt=\"next\" "
+      . "width=\"89\" height=20 border=\"0\"></a>\n<br>";
+
+    # Report
+    print "<table cellspacing=\"0\" cellpadding=\"2\">\n<tr>"
+      . "<td><a href=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::REPORT"
+      . "&$Args::baseargs&meta=$meta&recmode=$recmode\""
+      . " target=\"_blank\">"
+      . "<img src=\"pict/but_report.jpg\" alt=\"report\" "
+      . "width=88 height=20 border=\"0\">"
+      . "</a></td>\n";
+
+    # View (File Mode)
+    print "<td><a href=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::CONT_FR"
+      . "&$Args::baseargs&meta=$meta&recmode=$recmode"
+      . "&dir=$vol-meta-$meta\" target=\"_blank\">"
+      . "<img src=\"pict/but_viewcont.jpg\" alt=\"view contents\" "
+      . "width=123 height=20 border=\"0\">"
+      . "</a></td>\n";
+
+    # Export
+    print "<td><a href=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::EXPORT"
+      . "&$Args::baseargs&meta=$meta&recmode=$recmode\">"
+      . "<img src=\"pict/but_export.jpg\" alt=\"export\" "
+      . "width=123 height=20 border=\"0\">"
+      . "</a></td>";
+
+    # Notes
+    print "<td><a href=\"$::PROGNAME?mod=$::MOD_NOTES&view=$Notes::ENTER_FILE"
+      . "&$Args::baseargs&meta=$meta&\" "
+      . "target=\"_blank\">"
+      . "<img src=\"pict/but_addnote.jpg\" alt=\"Add Note\" "
+      . "width=\"89\" height=20 border=\"0\">"
+      . "</a></td>"
+      if ($::USE_NOTES == 1);
+
+    print "</tr></table>\n</center>\n";
+
+    my $tmpr = $Caseman::vol2mnt{$vol};
+
+    if ($ftype =~ /fat/) {
+        print
+"<a href=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::FFIND&$Args::baseargs&"
+          . "meta=$meta\" target=\"_blank\">Search for File Name</a><br><br>";
+    }
+    else {
+
+        print "<b>Pointed to by file:</b><br>\n";
+
+        local *OUT;
+        Exec::exec_pipe(*OUT,
+            "'$::TSKDIR/ffind' -f $ftype -a -o $offset -i $imgtype $img $meta");
+        my $cnt = 0;
+        while ($_ = Exec::read_pipe_line(*OUT)) {
+            chop;
+            if (/^(\*)\s+\/*(.*)$/) {
+                Print::print_output("<tt><font color=\"$::DEL_COLOR[0]\">"
+                      . Print::html_encode($tmpr . $2)
+                      . "</font></tt> (deleted)<br><br>\n");
+            }
+            elsif (/^\/(.*)$/) {
+                Print::print_output("<tt>"
+                      . Print::html_encode($tmpr . $1)
+                      . "</tt><br><br>\n");
+            }
+            else {
+                Print::print_output(Print::html_encode($_) . "<br><br>\n");
+            }
+            $cnt++;
+        }
+        close(OUT);
+        if ($cnt == 0) {
+            print "<br>Invalid $Fs::meta_str{$ftype} value<br><br>\n";
+            return;
+        }
+    }
+
+    if ($recmode == $File::REC_YES) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype -r -o $offset -i $imgtype $img $meta | '$::FILE_EXE' -z -b -"
+        );
+    }
+    else {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype -o $offset -i $imgtype $img $meta | '$::FILE_EXE' -z -b -"
+        );
+    }
+    my $file_type = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $file_type = "Error getting file type"
+      if ((!defined $file_type) || ($file_type eq ""));
+
+    if ($recmode == $File::REC_YES) {
+        print "<b>File Type (Recovered):</b><br>$file_type<br>\n";
+    }
+    else {
+        print "<b>File Type:</b><br>$file_type<br><br>\n";
+    }
+
+    # MD5 Value
+    if ($recmode == $File::REC_YES) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype -r -o $offset -i $imgtype $img $meta | '$::MD5_EXE'"
+        );
+    }
+    else {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype -o $offset -i $imgtype $img $meta | '$::MD5_EXE'"
+        );
+    }
+
+    my $md5out = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $md5out = "Error getting MD5"
+      if ((!defined $md5out) || ($md5out eq ""));
+
+    chomp $md5out;
+    if ($recmode == $File::REC_YES) {
+        print "<b>MD5 of recovered content:</b><br><tt>$md5out</tt><br><br>\n";
+    }
+    else {
+        print "<b>MD5 of content:</b><br><tt>$md5out</tt><br><br>\n";
+    }
+
+    # Hash Database Lookups
+    if (
+        (
+               ($::NSRLDB ne "")
+            || ($Caseman::alert_db   ne "")
+            || ($Caseman::exclude_db ne "")
+        )
+        && ($md5out =~ /^$::REG_MD5$/o)
+      )
+    {
+
+        print "<form action=\"$::PROGNAME\" method=\"get\" target=\"_blank\">\n"
+          . Args::make_hidden()
+          . "<input type=\"hidden\" name=\"md5\" value=\"$md5out\">\n"
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_HASH\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Hash::DB_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 ($Caseman::alert_db ne "") {
+            print "<td align=\"left\">"
+              . "<input type=\"checkbox\" name=\"hash_alert\" value=\"1\" CHECKED>"
+              . "Alert Database</td>\n";
+        }
+        if ($Caseman::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_lookup.jpg\" "
+          . "width=116 height=20 alt=\"Ok\" border=\"0\">"
+          . "</td></tr></table>\n</form>\n";
+    }
+
+    # SHA-1 Value
+    if ($::SHA1_EXE ne "") {
+        if ($recmode == $File::REC_YES) {
+            Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype -r -o $offset -i $imgtype $img $meta | '$::SHA1_EXE'"
+            );
+        }
+        else {
+            Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype -o $offset -i $imgtype $img $meta | '$::SHA1_EXE'"
+            );
+        }
+
+        my $sha1out = Exec::read_pipe_line(*OUT);
+        close(OUT);
+
+        $sha1out = "Error getting SHA-1"
+          if ((!defined $sha1out) || ($sha1out eq ""));
+
+        chomp $sha1out;
+        if ($recmode == $File::REC_YES) {
+            print
+"<b>SHA-1 of recovered content:</b><br><tt>$sha1out</tt><br><br>\n";
+        }
+        else {
+            print "<b>SHA-1 of content:</b><br><tt>$sha1out</tt><br><br>\n";
+        }
+    }
+
+    # istat output
+    print "<b>Details:</b><br><br>\n";
+    my $mode  = 0;    # set to 1 when showing blocks
+    my $force = 0;    # set to 1 if size of meta is 0
+
+    my @output;
+    if (exists($Args::args{'force'})) {
+        my $f = Args::get_force();
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/istat' -f $ftype $tz -s $Caseman::ts -B $f -o $offset -i $imgtype $img $meta"
+        );
+    }
+    else {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/istat' -f $ftype $tz -s $Caseman::ts -o $offset -i $imgtype $img $meta"
+        );
+    }
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        if ($mode == 1) {
+            if (/^Indirect Blocks/) {
+                print "$_<br>\n";
+                next;
+            }
+            elsif (/^Recover/) {
+                print "$_<br>\n";
+                next;
+            }
+            elsif (/^Type: (\S+) \((\d+\-\d+)\) (.*)$/) {
+                print "$1 ("
+                  . "<a href=\"$::PROGNAME?mod=$::MOD_FILE&view=$File::CONT_FR&$Args::baseargs"
+                  . "&meta=$meta_int-$2&dir=$vol-meta-$meta_int-$2\" "
+                  . "target=\"_blank\">$2</a>) $3<br>\n";
+                next;
+            }
+
+            my $blk;
+            foreach $blk (split(/ /, $_)) {
+                if ($blk =~ /^\d+$/) {
+                    print
+"<a href=\"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_DATA&"
+                      . "$Args::baseargs&block=$blk\" target=\"_top\">$blk</a>  ";
+                }
+                else {
+                    print "$blk   ";
+                }
+            }
+            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:/);  # HFS gets messed up without ":"
+            $mode = 1 if (/^Data Fork Blocks:/); 
+
+            if ((/^size: (\d+)/) && ($1 == 0)) {
+                $force = 1;
+            }
+        }
+    }
+    close(OUT);
+
+    # display a text box to force X number of blocks to be displayed
+    if ($force == 1) {
+        print "<form action=\"$::PROGNAME\" method=\"get\">\n"
+          . Args::make_hidden()
+          . "<input type=\"hidden\" name=\"vol\" value=\"$vol\">\n"
+          . "<input type=\"hidden\" name=\"meta\" value=\"$meta\">\n"
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_META\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Meta::STATS\">\n";
+
+        print
+"Enter number of $Fs::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\" "
+          . "width=53 height=20 alt=\"Force\" border=\"0\"> (because the size is 0)\n</form>\n";
+    }
+
+    Print::print_html_footer();
+    return 0;
+}
+
+sub findfile {
+
+    Print::print_html_header("Find File");
+
+    my $meta    = Args::get_meta('meta');
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $tmpr    = $Caseman::vol2mnt{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    print "<b>Pointed to by file:</b><br>\n";
+
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+        "'$::TSKDIR/ffind' -f $ftype -a -o $offset -i $imgtype $img $meta");
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        chop;
+        if (/(\*)\s+\/*(.*)/) {
+            Print::print_output("<tt><font color=\"$::DEL_COLOR[0]\">"
+                  . Print::html_encode($tmpr . $2)
+                  . "</font></tt> (deleted)<br>\n");
+        }
+        elsif (/^\/(.*)$/) {
+            Print::print_output(
+                "<tt>" . Print::html_encode($tmpr . $1) . "</tt><br>\n");
+        }
+        else {
+            Print::print_output(Print::html_encode($_) . "<br>\n");
+        }
+    }
+    close(OUT);
+
+    Print::print_html_footer();
+    return 0;
+}
+
+sub export {
+    my $meta    = Args::get_meta('meta');
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+    my $recmode = Args::get_recmode();
+
+    Print::log_host_inv(
+"$Caseman::vol2sname{$vol}: Saving contents of $Fs::meta_str{$ftype} $meta"
+    );
+
+    Print::print_oct_header("$vol" . "-meta" . "$meta" . ".raw");
+
+    local *OUT;
+    if ($recmode == $File::REC_YES) {
+        Exec::exec_pipe(*OUT,
+            "'$::TSKDIR/icat' -f $ftype -r -o $offset -i $imgtype $img $meta");
+    }
+    else {
+        Exec::exec_pipe(*OUT,
+            "'$::TSKDIR/icat' -f $ftype -o $offset -i $imgtype $img $meta");
+    }
+
+    print "$_" while ($_ = Exec::read_pipe_data(*OUT, 512));
+    close(OUT);
+
+    Print::print_oct_footer();
+}
+
+sub report {
+
+    my $meta    = Args::get_meta('meta');
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+    my $recmode = Args::get_recmode();
+
+    my $tz = "";
+    $tz = "-z '$Caseman::tz'" unless ("$Caseman::tz" eq "");
+
+    Print::log_host_inv(
+"$Caseman::vol2sname{$vol}: Generating report for $Fs::meta_str{$ftype} $meta"
+    );
+
+    Print::print_text_header("filename=$vol-meta$meta.txt");
+
+    print "                 Autopsy $Fs::meta_str{$ftype} Report\n\n"
+      . "-" x 70 . "\n"
+      . "                    GENERAL INFORMATION\n\n"
+      . "$Fs::meta_str{$ftype}: $Args::args{'meta'}\n";
+
+    print "Pointed to by file(s):\n";
+    my $tmpr = $Caseman::vol2mnt{$vol};
+    local *OUT;
+
+    Exec::exec_pipe(*OUT,
+        "'$::TSKDIR/ffind' -f $ftype -a -o $offset -i $imgtype $img $meta");
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        chop;
+        if (/^(\*)\s+\/*(.*)$/) {
+            Print::print_output(
+                "  ${tmpr}${2} (deleted)\n");
+        }
+        elsif (/^\/(.*)$/) {
+            Print::print_output("  ${tmpr}${1}\n");
+        }
+        else {
+            Print::print_output("  $_\n");
+        }
+    }
+    close(OUT);
+
+    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/istat' -f $ftype $tz -s $Caseman::ts -o $offset -i $imgtype $img $meta | '$::MD5_EXE'"
+    );
+    my $md5 = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $md5 = "Error getting MD5 Value"
+      if ((!defined $md5) || ($md5 eq ""));
+
+    chop $md5;
+    print "MD5 of istat output: $md5\n";
+
+    if ($::SHA1_EXE ne "") {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/istat' -f $ftype $tz -s $Caseman::ts -o $offset -i $imgtype $img $meta | '$::SHA1_EXE'"
+        );
+        my $sha1 = Exec::read_pipe_line(*OUT);
+        close(OUT);
+
+        $sha1 = "Error getting SHA-1 Value"
+          if ((!defined $sha1) || ($sha1 eq ""));
+
+        chop $sha1;
+        print "SHA-1 of istat output: $sha1\n";
+    }
+
+    print "\nImage: $Caseman::vol2path{$vol}\n";
+    if (($Caseman::vol2start{$vol} == 0) && ($Caseman::vol2end{$vol} == 0)) {
+        print "Offset: Full image\n";
+    }
+    elsif ($Caseman::vol2end{$vol} == 0) {
+        print "Offset: $Caseman::vol2start{$vol} to end\n";
+    }
+    else {
+        print "Offset: $Caseman::vol2start{$vol} to $Caseman::vol2end{$vol}\n";
+    }
+    print "File System Type: $ftype\n";
+
+    my $date = localtime();
+    print "\nDate Generated: $date\n"
+      . "Investigator: $Args::args{'inv'}\n\n"
+      . "-" x 70 . "\n"
+      . "                   META DATA INFORMATION\n\n";
+
+    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/istat' -f $ftype $tz -s $Caseman::ts -o $offset -i $imgtype $img $meta"
+    );
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        print $_;
+    }
+    close(OUT);
+
+    if ($recmode == $File::REC_YES) {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype -r -o $offset -i $imgtype $img $meta | '$::FILE_EXE' -z -b -"
+        );
+    }
+    else {
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/icat' -f $ftype -o $offset -i $imgtype $img $meta | '$::FILE_EXE' -z -b -"
+        );
+    }
+
+    my $file_type = Exec::read_pipe_line(*OUT);
+    close(OUT);
+
+    $file_type = "Error getting file type"
+      if ((!defined $file_type) || ($file_type eq ""));
+
+    print "\nFile Type: $file_type";
+
+    print "\n"
+      . "-" x 70 . "\n"
+      . "                   VERSION INFORMATION\n\n"
+      . "Autopsy Version: $::VER\n";
+    print "The Sleuth Kit Version: " . ::get_tskver() . "\n";
+
+    Print::print_text_footer();
+
+    return 0;
+}
+
+# Display the meta Allocation Table
+sub list {
+    my $ILS_GAP = 500;
+
+    my $vol     = Args::get_vol('vol');
+    my $ftype   = $Caseman::vol2ftype{$vol};
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $min = 0;
+
+    $min = Args::get_min() if (exists $Args::args{'min'});
+    my $max = $min + $ILS_GAP - 1;
+
+    # Because we can not use metas 0 and 1 for most FS, set fmin to the
+    # minimum for this fs
+    my $fmin = $min;
+    $fmin = $Fs::first_meta{$ftype} if ($min < $Fs::first_meta{$ftype});
+
+    Print::print_html_header(
+        "$Fs::meta_str{$ftype} Allocation List $fmin -&gt $max");
+
+    Print::log_host_inv(
+"$Caseman::vol2sname{$vol}: $Fs::meta_str{$ftype} Allocation List for $min to $max"
+    );
+
+    print "<center><H2>$Fs::meta_str{$ftype}: $fmin - $max</H2>";
+
+    # Display next and previous links
+    my $tmp;
+    if ($min > $Fs::first_meta{$ftype}) {
+        $tmp = $min - $ILS_GAP;
+        print
+"<a href=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::LIST&$Args::baseargs&min=$tmp\">"
+          . "<img src=\"pict/but_prev.jpg\" alt=\"previous\" "
+          . "width=\"89\" height=20 border=\"0\"></a> ";
+    }
+    $tmp = $min + $ILS_GAP;
+    print
+" <a href=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::LIST&$Args::baseargs&min=$tmp\">"
+      . "<img src=\"pict/but_next.jpg\" alt=\"next\" "
+      . "width=\"89\" height=20 border=\"0\"></a><br>";
+    print "</center>\n";
+
+    # The list
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/ils' -e -s $Caseman::ts -f $ftype -o $offset -i $imgtype $img $fmin-$max"
+    );
+    while ($_ = Exec::read_pipe_line(*OUT)) {
+        if (/^($::REG_META)\|([af])\|\d+\|\d+\|\d+\|\d+\|\d+\|/o) {
+            print
+"<a href=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::STATS&$Args::baseargs&meta=$1\">"
+              . "$1:</a> ";
+            if ($2 eq "a") {
+                print "allocated<br>\n";
+            }
+            else {
+                print "<font color=\"$::DEL_COLOR[0]\">free</font><br>\n";
+            }
+        }
+    }
+    close(OUT);
+
+    # Display next and previous links
+    print "<center>\n";
+    if ($min > $Fs::first_meta{$ftype}) {
+        $tmp = $min - $ILS_GAP;
+        print
+"<a href=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::LIST&$Args::baseargs&min=$tmp\">"
+          . "<img src=\"pict/but_prev.jpg\" alt=\"previous\" "
+          . "width=\"89\" height=20 border=\"0\"></a> ";
+    }
+    $tmp = $min + $ILS_GAP;
+    print
+" <a href=\"$::PROGNAME?mod=$::MOD_META&view=$Meta::LIST&$Args::baseargs&min=$tmp\">"
+      . "<img src=\"pict/but_next.jpg\" alt=\"next\" "
+      . "width=\"89\" height=20 border=\"0\"></a><br>";
+    print "</center>\n";
+
+    Print::print_html_footer();
+    return 0;
+
+}
+
+# Blank Page
+sub blank {
+    Print::print_html_header("Metadata Blank Page");
+    my $vol   = Args::get_vol('vol');
+    my $ftype = $Caseman::vol2ftype{$vol};
+
+    print "<center><h3>Metadata Mode</h3><br>\n"
+      . "Here you can view the details about any $Fs::meta_str{$ftype} in the file system.<br>\n"
+      . "These are the data structures that store the file details.<br>\n"
+      . "Enter the address in the field on the left.\n";
+    Print::print_html_footer();
+    return 0;
+}
+
diff --git a/lib/Notes.pm b/lib/Notes.pm
new file mode 100644
index 0000000000000000000000000000000000000000..5f36f1ad3ed2d32016fb4c8676452306b58b65c7
--- /dev/null
+++ b/lib/Notes.pm
@@ -0,0 +1,1110 @@
+#
+# Notes and sequencer functions
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2005 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 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.
+
+package Notes;
+
+use POSIX;
+
+$Notes::ENTER_FILE    = 1;
+$Notes::ENTER_DATA    = 2;
+$Notes::WRITE_FILE    = 3;
+$Notes::WRITE_DATA    = 4;
+$Notes::WRITE_SEQ_MAN = 5;
+$Notes::READ_NORM     = 6;
+$Notes::READ_SEQ      = 7;
+
+sub main {
+
+    # There is no default for Notes
+    Args::check_view();
+
+    Print::print_check_error("Notes option is not enabled")
+      if ($::USE_NOTES == 0);
+
+    my $view = Args::get_view();
+
+    if ($view == $Notes::ENTER_FILE) {
+        return enter_file();
+    }
+    elsif ($view == $Notes::ENTER_DATA) {
+        return enter_data();
+    }
+    elsif ($view == $Notes::WRITE_FILE) {
+        return write_file();
+    }
+    elsif ($view == $Notes::WRITE_DATA) {
+        return write_data();
+    }
+    elsif ($view == $Notes::WRITE_SEQ_MAN) {
+        return write_seq_man();
+    }
+    elsif ($view == $Notes::READ_NORM) {
+        return read_norm();
+    }
+    elsif ($view == $Notes::READ_SEQ) {
+        return read_seq();
+    }
+    else {
+        Print::print_check_err("Invalid Notes View");
+    }
+}
+
+sub investig_notes_fname {
+    return "$::host_dir" . "$::LOGDIR/$Args::args{'inv'}.notes";
+}
+
+sub investig_seq_notes_fname {
+    return "$::host_dir" . "$::LOGDIR/$Args::args{'inv'}.seq.notes";
+}
+
+# window where user can enter a normal and sequencer note for a file
+# or meta data structure.
+sub enter_file {
+    Args::check_vol('vol');
+    Args::check_meta('meta');
+
+    my $vol   = Args::get_vol('vol');
+    my $ftype = $Caseman::vol2ftype{$vol};
+    my $mnt   = $Caseman::vol2mnt{$vol};
+    my $meta  = Args::get_meta('meta');
+
+    # A file will have a 'dir' argument and a meta structure will not
+    if (exists $Args::args{'dir'}) {
+        my $fname = "$mnt$Args::args{'dir'}";
+        Print::print_html_header("Notes for file $fname");
+        print "<center><b>Enter a note for <tt>$fname</tt> ($meta):</b>"
+          . "<br><br>\n";
+    }
+    else {
+        Print::print_html_header("Notes for $Fs::meta_str{$ftype} $meta");
+        print "<center><b>Enter a note for $Fs::meta_str{$ftype} $meta:</b>"
+          . "<br><br>\n";
+    }
+    print
+"A note works like a bookmark and allows you to later find this data more easily.<br><br>\n";
+
+    # Setup the form
+    print "<form action=\"$::PROGNAME\" method=\"get\">\n"
+      . "<textarea rows=10 cols=50 wrap=\"virtual\" name=\"note\">"
+      . "</textarea><br>\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_NOTES\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Notes::WRITE_FILE\">\n"
+      . "<input type=\"hidden\" name=\"vol\" value=\"$vol\">\n"
+      . "<input type=\"hidden\" name=\"meta\" value=\"$meta\">\n"
+      . Args::make_hidden();
+
+    print "<input type=\"hidden\" name=\"dir\" value=\"$Args::args{'dir'}\">\n"
+      if (exists $Args::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 - which requires the MAC times for the files
+    if ("$Caseman::tz" ne "") {
+        $ENV{TZ} = $Caseman::tz;
+      POSIX: tzset();
+    }
+
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $meta_int = $meta;
+    $meta_int = $1 if ($meta_int =~ /^(\d+)-\d+(-\d+)?$/);
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/ils' -s $Caseman::ts -f $ftype -e  -o $offset -i $imgtype $img $meta_int"
+    );
+
+    # Get the fourth line
+    my $tmp = Exec::read_pipe_line(*OUT);
+    $tmp = Exec::read_pipe_line(*OUT);
+    $tmp = Exec::read_pipe_line(*OUT);
+    $tmp = Exec::read_pipe_line(*OUT);
+    close(OUT);
+    unless ((defined $tmp)
+        && ($tmp =~ /^$::REG_META\|\w\|\d+\|\d+\|(\d+)\|(\d+)\|(\d+)\|/o))
+    {
+        Print::print_err("Error parsing 'ils' output");
+    }
+
+    my $mtime = $1;
+    my $atime = $2;
+    my $ctime = $3;
+
+    $mtime = localtime($mtime);
+    $atime = localtime($atime);
+    $ctime = localtime($ctime);
+
+    # Print the Times
+    print "<br><hr><b>Add a Sequencer Event:</b><br><br>\n"
+      . "A sequencer event will be sorted based on the time so that event reconstruction will be easier<br><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><hr><br>\n";
+
+    # The OK Button
+    print "<br><input type=\"image\" src=\"pict/but_ok.jpg\" "
+      . "width=43 height=20 alt=\"Ok\" border=\"0\">\n</form>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# data unit comment
+sub enter_data {
+    Args::check_vol('vol');
+
+    my $vol   = Args::get_vol('vol');
+    my $ftype = $Caseman::vol2ftype{$vol};
+    my $block = Args::get_block();
+    my $len   = Args::get_len();
+
+    Print::print_html_header("Notes for $Fs::addr_unit{$ftype} $block");
+
+    print
+      "<center><b>Enter a note for $Fs::addr_unit{$ftype} $block</b><br><br>\n"
+      . "A note works like a bookmark and allows you to later find this data more easily.<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=\"mod\" value=\"$::MOD_NOTES\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Notes::WRITE_DATA\">\n"
+      . "<input type=\"hidden\" name=\"vol\" value=\"$vol\">\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"
+      . Args::make_hidden()
+      . "<br><input type=\"image\" src=\"pict/but_ok.jpg\" "
+      . "width=43 height=20 alt=\"Ok\" border=\"0\">\n</form>\n";
+
+    Print::print_html_footer();
+    return 0;
+
+}
+
+# Write the note to the note file
+sub write_data {
+    Args::check_vol('vol');
+    Args::check_block();
+    Args::check_len();
+    Args::check_note();
+
+    Print::print_html_header("Write a note");
+
+    my $vol    = Args::get_vol('vol');
+    my $ftype  = $Caseman::vol2ftype{$vol};
+    my $img_sh = $Caseman::vol2sname{$vol};
+    my $block  = Args::get_block();
+    my $len    = Args::get_len();
+
+    Print::log_host_inv(
+        "$img_sh: Creating note for $Fs::addr_unit{$ftype} $block");
+
+    my $notes_file = investig_notes_fname();
+    open NOTES, ">>$notes_file" or die "Can't open log: $notes_file";
+    print "Note added to $notes_file:<p>\n\n";
+
+    # Date
+    my $tmp = localtime();
+    print NOTES "$tmp\n";
+    print "$tmp<br>\n";
+
+    print NOTES "Volume: $vol  $Fs::addr_unit{$ftype}: $block  Len: $len\n";
+    print "Volume: $vol  $Fs::addr_unit{$ftype}: $block  Len: $len<br>\n";
+
+    # The actual notes and a line at the bottom
+    print NOTES "\n$Args::args{'note'}\n\n" . "-" x 70 . "\n";
+    print "<p>".Print::html_encode($Args::args{'note'})."<p>";
+    close(NOTES);
+
+    print "<hr>\n"
+      . "You can view the notes from the Host Manager View<p>"
+      . "<a href=\"$::PROGNAME?${Args::baseargs_novol}&mod=$::MOD_NOTES&view=$Notes::READ_NORM\">"
+      . "<img border=0 src=\"pict/menu_b_note.jpg\" "
+      . "width=\"167\" height=20 alt=\"View Notes\"></a>\n";
+
+    Print::print_html_footer();
+
+    return 0;
+}
+
+sub write_file {
+    Args::check_vol('vol');
+    Args::check_meta('meta');
+    Args::check_note();
+
+    # Get rid of carriage returns that Netscape adds
+    $Args::args{'note'} =~ tr/\r//d;
+
+    my $vol = Args::get_vol('vol');
+    my $mnt = $Caseman::vol2mnt{$vol};
+
+    my $ftype  = $Caseman::vol2ftype{$vol};
+    my $img_sh = $Caseman::vol2sname{$vol};
+    my $meta   = Args::get_meta('meta');
+
+    my $img     = $Caseman::vol2path{$vol};
+    my $offset  = $Caseman::vol2start{$vol};
+    my $imgtype = $Caseman::vol2itype{$vol};
+
+    my $fname = "";
+    my $type  = "";
+
+    if (exists $Args::args{'dir'}) {
+        $Args::args{'dir'} .= "/"
+          if ($Args::args{'dir'} eq "");
+        $fname = "$mnt$Args::args{'dir'}";
+
+        if (($Args::args{'dir'} =~ /\/$/) || ($Args::args{'dir'} eq "")) {
+            Print::log_host_inv(
+                "$img_sh: Creating note for directory $fname ($meta)");
+            $type = "dir";
+        }
+        else {
+            Print::log_host_inv(
+                "$img_sh: Creating note for file $fname ($meta)");
+            $type = "file";
+        }
+    }
+
+    else {
+        Print::log_host_inv(
+            "$img_sh: Creating note for $Fs::meta_str{$ftype} $meta");
+        $type = "$Fs::meta_str{$ftype}";
+    }
+
+    Print::print_html_header("Writing a note / event");
+
+    # Get the times for the meta
+    # Set the timezone to the host zone
+    if ("$Caseman::tz" ne "") {
+        $ENV{TZ} = "$Caseman::tz";
+        POSIX::tzset();
+    }
+
+    my $meta_int = $meta;
+    $meta_int = $1 if ($meta_int =~ /^(\d+)-\d+(-\d+)?$/);
+    local *OUT;
+    Exec::exec_pipe(*OUT,
+"'$::TSKDIR/ils' -s $Caseman::ts -f $ftype -e -o $offset -i $imgtype $img $meta_int"
+    );
+
+    # Skip to the fourth line
+    my $tmp = Exec::read_pipe_line(*OUT);
+    $tmp = Exec::read_pipe_line(*OUT);
+    $tmp = Exec::read_pipe_line(*OUT);
+    $tmp = Exec::read_pipe_line(*OUT);
+    unless ((defined $tmp)
+        && ($tmp =~ /^$::REG_META\|\w\|\d+\|\d+\|(\d+)\|(\d+)\|(\d+)\|/o))
+    {
+        Print::print_err("Error parsing 'ils' output");
+    }
+    my $mtime = $1;
+    my $atime = $2;
+    my $ctime = $3;
+    close(OUT);
+
+    # Create a "normal" note
+    if ((exists $Args::args{'norm_note'}) && ($Args::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:<p>\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<br>\n";
+            }
+            else {
+                print NOTES "File: $fname\n";
+                print "File: $fname<br>\n";
+            }
+        }
+        if ($meta ne "") {
+            print NOTES "Volume: $vol  Meta: $meta\n";
+            print "Volume: $vol  Meta: $meta<br>\n";
+        }
+        print NOTES "M-time: " . localtime($mtime) . "\n";
+        print "M-time: " . localtime($mtime) . "<br>\n";
+        print NOTES "A-time: " . localtime($atime) . "\n";
+        print "A-time: " . localtime($atime) . "<br>\n";
+        print NOTES "C-time: " . localtime($ctime) . "\n";
+        print "C-time: " . localtime($ctime) . "<br>\n";
+
+        # The actual notes and a line at the bottom
+        print NOTES "\n$Args::args{'note'}\n\n" . "-" x 70 . "\n";
+        print "<p>".Print::html_encode($Args::args{'note'})."<p>";
+
+        close(NOTES);
+    }
+
+    # Create a sequencer event - if there are any
+    unless (((exists $Args::args{'mtime'}) && ($Args::args{'mtime'} == 1))
+        || ((exists $Args::args{'atime'}) && ($Args::args{'atime'} == 1))
+        || ((exists $Args::args{'ctime'}) && ($Args::args{'ctime'} == 1)))
+    {
+
+        print "<hr>\n"
+          . "You can view the notes from the Host Manager View<p>"
+          . "<a href=\"$::PROGNAME?${Args::baseargs_novol}&mod=$::MOD_NOTES&view=$Notes::READ_NORM\">"
+          . "<img border=0 src=\"pict/menu_b_note.jpg\" "
+          . "width=\"167\" height=20 alt=\"View Notes\"></a>\n";
+
+        Print::print_html_footer();
+
+        return 0;
+    }
+
+    # Get rid of the carriage returns
+    $Args::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";
+
+    if ((exists $Args::args{'mtime'}) && ($Args::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::args{'host'}','$vol','$fname','$meta','',"
+          . "'$type','[M-Time]$Args::args{'note'}'\n";
+
+        Print::log_host_inv(
+            "$img_sh: M-Time note added for meta $Args::args{'meta'}");
+        print "M-Time sequence event added<br>\n";
+    }
+
+    if ((exists $Args::args{'atime'}) && ($Args::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::args{'host'}','$vol','$fname','$meta','',"
+          . "'$type','[A-Time]$Args::args{'note'}'\n";
+
+        Print::log_host_inv(
+            "$img_sh: A-Time note added for meta $Args::args{'meta'}");
+        print "A-Time sequence event added<br>\n";
+    }
+
+    if ((exists $Args::args{'ctime'}) && ($Args::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::args{'host'}','$vol','$fname','$meta','',"
+          . "'$type','[C-Time]$Args::args{'note'}'\n";
+
+        Print::log_host_inv(
+            "$img_sh: C-Time note added for meta $Args::args{'meta'}");
+        print "C-Time sequence event added<br>\n";
+    }
+
+    close(NOTES);
+
+    print "<p><hr>\n"
+      . "You can view the notes and events from the Host Manager View<p>";
+
+    if ((exists $Args::args{'norm_note'}) && ($Args::args{'norm_note'} == 1)) {
+        print
+"<a href=\"$::PROGNAME?${Args::baseargs_novol}&mod=$::MOD_NOTES&view=$Notes::READ_NORM\">"
+          . "<img border=0 src=\"pict/menu_b_note.jpg\" "
+          . "width=\"167\" height=20 alt=\"View Notes\"></a>\n";
+    }
+
+    print
+"<a href=\"$::PROGNAME?${Args::baseargs_novol}&mod=$::MOD_NOTES&view=$Notes::READ_SEQ\">"
+      . "<img border=0 src=\"pict/menu_b_seq.jpg\" width=\"167\" height=\"20\" "
+      . " alt=\"Event Sequencer\"></a>\n";
+
+    Print::print_html_footer();
+
+    return 0;
+}
+
+# Display the contents of the "normal" notes file
+sub read_norm {
+    Print::print_html_header("Contents of Notes File");
+
+    my $notes_file = investig_notes_fname();
+
+    Print::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"
+          . "They can be entered using the <i>Add Note</i> link within each analysis mode.<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 Print::html_encode($_);
+        }
+
+        if (/^Volume: ($::REG_VNAME)   Meta: ([0-9\-]+)/o) {
+            $vol  = $1;
+            $meta = $2;
+            next unless (exists $Caseman::vol2cat{$vol});
+
+            # file note
+            if ($file ne "") {
+
+                # extract the prepended mnt value
+                my $mnt   = $Caseman::vol2mnt{$vol};
+                my $fname = "";
+                $fname = $1 if ($file =~ /^$mnt\/?(.*)$/);
+                print "<a href=\"$::PROGNAME?$Args::baseargs_novol"
+                  . "&mod=$::MOD_FILE&view=$File::CONT_FR"
+                  . "&vol=$vol&meta=$meta&dir=$fname\" target=\"_blank\">"
+                  . "<img src=\"pict/but_view.jpg\" alt=\"view\" "
+                  . "width=45 height=22 alt=\"View\" border=\"0\"></a><br>\n";
+            }
+
+            # directory note
+            elsif ($dir ne "") {
+
+                # extract the prepended mnt value
+                my $mnt   = $Caseman::vol2mnt{$vol};
+                my $fname = "";
+                $fname = $1 if ($dir =~ /^$mnt\/?(.*)$/);
+                print "<a href=\"$::PROGNAME?$Args::baseargs_novol"
+                  . "&mod=$::MOD_FRAME&submod=$::MOD_FILE&vol=$vol&"
+                  . "&meta=$meta&dir=$fname\" target=\"_blank\">"
+                  . "<img src=\"pict/but_view.jpg\" alt=\"view\" "
+                  . "width=45 height=22 alt=\"View\" border=\"0\"></a><br>\n";
+
+            }
+
+            # meta note
+            else {
+                print "<a href=\"$::PROGNAME?$Args::baseargs_novol"
+                  . "&mod=$::MOD_FRAME&submod=$::MOD_META&vol=$vol"
+                  . "&meta=$meta\" target=\"_blank\">"
+                  . "<img src=\"pict/but_view.jpg\" alt=\"view\" "
+                  . "width=45 height=22 alt=\"View\" border=\"0\"></a><br>\n";
+
+            }
+        }
+
+        # block note
+        elsif (/^Volume: ($::REG_VNAME)   \w+: ([0-9]+)  Len: (\d+)/o) {
+            $vol = $1;
+            $blk = $2;
+            $len = $3;
+            next unless (exists $Caseman::vol2cat{$vol});
+
+            print "<a href=\"$::PROGNAME?$Args::baseargs_novol"
+              . "&mod=$::MOD_FRAME&submod=$::MOD_DATA&vol=$vol"
+              . "&block=$blk&len=$len\" target=\"_blank\">"
+              . "<img src=\"pict/but_view.jpg\" alt=\"view\" "
+              . "width=45 height=22 alt=\"View\" border=\"0\"></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?mod=$::MOD_CASEMAN&view=$Caseman::VOL_OPEN&$Args::baseargs\">"
+      . "<img border=0 src=\"pict/menu_b_close.jpg\" width=167 height=20 alt=\"close\"></a>\n"
+      . "</td><td width=300 align=center>\n"
+      . "<a href=\"$::PROGNAME?mod=$::MOD_NOTES&view=$Notes::READ_NORM&$Args::baseargs\">"
+      . "<img border=0 src=\"pict/menu_b_ref.jpg\" width=167 height=20 alt=\"refresh\"></a>\n"
+      . "</td></tr></table>\n";
+
+    close(NOTES);
+
+    Print::print_html_footer();
+
+    return 0;
+}
+
+#########################################################################
+# Sequencer Code
+
+# Write a sequence event that was manually entered
+sub write_seq_man {
+
+    Args::check_note();
+
+    Print::print_html_header("Writing Sequencer Event");
+
+    # Get rid of carriage returns that Netscape adds
+    $Args::args{'note'} =~ tr/\r//d;
+    $Args::args{'note'} =~ s/\n/<br>/gs;
+
+    if ($Args::args{'note'} eq "") {
+        print(  "A comment must be given for the event<br>\n"
+              . "<p><a href=\"$::PROGNAME?mod=$::MOD_NOTES&view=$Notes::READ_SEQ&$Args::baseargs\">"
+              . "<img border=0 src=\"pict/menu_b_ok.jpg\" "
+              . "width=167 height=20></a>");
+        Print::print_err("\n");
+    }
+
+    # Check the args and add them to the final string that will be written
+    my $str = "";
+    unless ((exists $Args::args{'year'})
+        && ($Args::args{'year'} =~ /^(\d\d\d\d)$/))
+    {
+        Print::print_err("Invalid year");
+    }
+    $str .= "'$1',";
+
+    unless ((exists $Args::args{'mon'}) && ($Args::args{'mon'} =~ /^(\d\d?)$/))
+    {
+        Print::print_err("Invalid month");
+    }
+    $str .= "'$1',";
+
+    unless ((exists $Args::args{'day'}) && ($Args::args{'day'} =~ /^(\d\d?)$/))
+    {
+        Print::print_err("Invalid day");
+    }
+    $str .= "'$1',";
+
+    unless ((exists $Args::args{'hour'})
+        && ($Args::args{'hour'} =~ /^(\d\d?)$/))
+    {
+        Print::print_err("Invalid hour");
+    }
+    $str .= "'$1',";
+
+    unless ((exists $Args::args{'min'}) && ($Args::args{'min'} =~ /^(\d\d?)$/))
+    {
+        Print::print_err("Invalid min");
+    }
+    $str .= "'$1',";
+
+    unless ((exists $Args::args{'sec'}) && ($Args::args{'sec'} =~ /^(\d\d?)$/))
+    {
+        Print::print_err("Invalid sec");
+    }
+    $str .= "'$1',";
+
+    # There are no image, meta, file name, or data unit for this type
+    $str .= "'$Args::args{'host'}','','','','',";
+
+    unless ((exists $Args::args{'src'}) && ($Args::args{'src'} =~ /^(\w+)$/)) {
+        Print::print_err("Invalid src");
+    }
+    $str .= "'$1','$Args::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::args{'mon'}] $Args::args{'day'}, $Args::args{'year'} "
+      . "$Args::args{'hour'}:$Args::args{'min'}:$Args::args{'sec'}<br><br>\n"
+      . Print::html_encode($Args::args{'note'})."<br>\n"
+      . "<p><a href=\"$::PROGNAME?mod=$::MOD_NOTES&view=$Notes::READ_SEQ&$Args::baseargs&"
+      . "year=$Args::enc_args{'year'}&mon=$Args::enc_args{'mon'}&day=$Args::enc_args{'day'}&"
+      . "hour=$Args::enc_args{'hour'}&min=$Args::enc_args{'min'}&sec=$Args::enc_args{'sec'}\">"
+      . "<img border=0 src=\"pict/but_ok.jpg\" alt=\"Ok\" "
+      . "width=43 height=20></a>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# View the sequencer file
+sub read_seq {
+
+    Print::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,
+        @vol,  @fname, @meta, @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_VNAME)?'?,'?(.*?)'?,'?($::REG_META)?'?,'?(\d+)?'?,'?([\w\s]+)'?,'?(.*?)'?$/
+              )
+            {
+                Print::print_err("Error parsing sequence event entry: $_");
+            }
+
+            $year[$cnt]  = $1;
+            $mon[$cnt]   = $2;
+            $day[$cnt]   = $3;
+            $hour[$cnt]  = $4;
+            $min[$cnt]   = $5;
+            $sec[$cnt]   = $6;
+            $host[$cnt]  = $7;
+            $vol[$cnt]   = $8;
+            $fname[$cnt] = "";
+            $fname[$cnt] = $9 if (defined $9);
+            $meta[$cnt]  = "";
+            $meta[$cnt]  = $10 if (defined $10);
+            $data[$cnt]  = "";
+            $data[$cnt]  = $11 if (defined $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>"
+              . "<td align=left valign=top>\n";
+
+            # If there is as name, then we will show it
+            # @@@ Why does an error message come up from here:
+            # Use of uninitialized value in string ne at
+            if ($fname[$i] ne "") {
+
+                if (   (exists $vol[$i])
+                    && (defined $vol[$i])
+                    && ($vol[$i] ne "")
+                    && (exists $Caseman::vol2mnt{$vol[$i]})
+                    && (exists $meta[$i]))
+                {
+
+                    # extract the prepended mnt value
+                    my $mnt   = $Caseman::vol2mnt{$vol[$i]};
+                    my $fname = "";
+                    $fname = $1 if ($fname[$i] =~ /^$mnt\/?(.*)$/);
+
+                    # Check if it is a directory
+                    if ($type[$i] eq 'dir') {
+                        print "<a href=\"$::PROGNAME?mod=$::MOD_FRAME&"
+                          . "submod=$::MOD_FILE&vol=$vol[$i]&$Args::baseargs&meta=$meta[$i]&dir=$fname\" "
+                          . "target=\"_blank\">\n"
+                          . "<tt>$fname[$i]</tt></a>\n";
+                    }
+                    else {
+                        print "<a href=\"$::PROGNAME?mod=$::MOD_FILE&"
+                          . "view=$File::CONT_FR&vol=$vol[$i]&$Args::baseargs&meta=$meta[$i]&dir=$fname\" "
+                          . "target=\"_blank\">\n"
+                          . "<tt>$fname[$i]</tt></a>\n";
+                    }
+                }
+                else {
+                    print "<tt>$fname[$i]</tt>\n";
+                }
+            }
+
+            # Display the meta value if there was no name
+            elsif (($vol[$i] ne "") && (defined $meta[$i]) && ($meta[$i] ne ""))
+            {
+                my $ftype = $Caseman::vol2ftype{$vol[$i]};
+
+                # Include a link if we can
+                if (exists $Caseman::vol2mnt{$vol[$i]}) {
+                    print "<a href=\"$::PROGNAME?mod=$::MOD_FRAME&"
+                      . "submod=$::MOD_META&vol=$vol[$i]"
+                      . "&$Args::baseargs&meta=$meta[$i]\" target=\"_blank\">\n"
+                      . "$Fs::meta_str{$ftype}: $meta[$i]</a>\n";
+                }
+                else {
+                    print "$Fs::meta_str{$ftype}: $meta[$i]\n";
+                }
+            }
+
+            # Otherwise, just give the source type
+            else {
+                print "$type[$i]\n";
+            }
+            print "</td>\n";
+
+            # Print the actual note
+            $note[$i] = Print::html_encode($note[$i]);
+            $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?mod=$::MOD_CASEMAN&"
+      . "view=$Caseman::VOL_OPEN&$Args::baseargs\">"
+      . "<img border=0 src=\"pict/menu_b_close.jpg\" width=167 height=20 alt=\"close\"></a>\n"
+      . "</td><td width=300 align=center>\n"
+      . "<a href=\"$::PROGNAME?mod=$::MOD_NOTES&"
+      . "view=$Notes::READ_SEQ&$Args::baseargs\">"
+      . "<img border=0 src=\"pict/menu_b_ref.jpg\" width=167 height=20 alt=\"refresh\"></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=\"mod\" value=\"$::MOD_NOTES\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Notes::WRITE_SEQ_MAN\">\n"
+      . Args::make_hidden();
+
+    # Month
+    print "<table><tr><td align=\"left\">\n";
+    print "<p>Date: " . "<select name=\"mon\" size=\"1\">\n";
+
+    my $prev = 1;
+    $prev = $Args::args{'mon'}
+      if ((exists $Args::args{'mon'}) && ($Args::args{'mon'} =~ /^\d+$/));
+
+    for my $i (1 .. 12) {
+        if ($i == $prev) {
+            print "<option value=$i selected>$::d2m[$i]</option>\n";
+        }
+        else {
+            print "<option value=\"$i\">$::d2m[$i]</option>\n";
+        }
+    }
+
+    print "</select>\n";
+
+    # Day
+    print "&nbsp;<select name=\"day\" size=\"1\">\n";
+
+    $prev = 1;
+    $prev = $Args::args{'day'}
+      if ((exists $Args::args{'day'}) && ($Args::args{'day'} =~ /^\d+$/));
+
+    for my $i (1 .. 31) {
+        my $dstr = $i;
+        $dstr = "0$i" if ($i < 10);
+
+        if ($prev eq $dstr) {
+            print "<option value=\"$dstr\" selected>$dstr</option>\n";
+        }
+        else {
+            print "<option value=\"$dstr\">$dstr</option>\n";
+        }
+    }
+    print "</select>\n";
+
+    # Year
+    $prev = 1900 + (localtime())[5];
+    $prev = $Args::args{'year'}
+      if ((exists $Args::args{'year'}) && ($Args::args{'year'} =~ /^\d+$/));
+
+    print "&nbsp;<input type=\"text\" value=\"$prev\" "
+      . "name=\"year\" size=\"6\">\n";
+
+    # Hour
+    print "&nbsp;&nbsp;<select name=\"hour\" size=\"1\">\n";
+    $prev = 0;
+    $prev = $Args::args{'hour'}
+      if ((exists $Args::args{'hour'}) && ($Args::args{'hour'} =~ /^\d+$/));
+
+    for my $i (0 .. 23) {
+        my $hstr = $i;
+        $hstr = "0$i" if ($i < 10);
+
+        if ($prev eq $hstr) {
+            print "<option value=\"$hstr\" selected>$hstr</option>\n";
+        }
+        else {
+            print "<option value=\"$hstr\">$hstr</option>\n";
+        }
+    }
+    print "</select>\n";
+
+    # Min
+    print ":<select name=\"min\" size=\"1\">\n";
+    $prev = 0;
+    $prev = $Args::args{'min'}
+      if ((exists $Args::args{'min'}) && ($Args::args{'min'} =~ /^\d+$/));
+
+    for my $i (0 .. 59) {
+        my $mstr = $i;
+        $mstr = "0$i" if ($i < 10);
+        if ($prev eq $mstr) {
+            print "<option value=\"$mstr\" selected>$mstr</option>\n";
+        }
+        else {
+            print "<option value=\"$mstr\">$mstr</option>\n";
+        }
+    }
+    print "</select>\n";
+
+    # Sec
+    print ":<select name=\"sec\" size=\"1\">\n";
+    $prev = 0;
+    $prev = $Args::args{'sec'}
+      if ((exists $Args::args{'sec'}) && ($Args::args{'sec'} =~ /^\d+$/));
+
+    for my $i (0 .. 59) {
+        my $sstr = $i;
+        $sstr = "0$i" if ($i < 10);
+
+        if ($prev eq $sstr) {
+            print "<option value=\"$sstr\" selected>$sstr</option>\n";
+        }
+        else {
+            print "<option value=\"$sstr\">$sstr</option>\n";
+        }
+    }
+    print "</select></td></tr>\n" . "<tr><td>&nbsp;</td></tr>\n";
+
+    # Type
+    print "<tr><td align=\"left\">Event Source: <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></td></tr>\n"
+      . "<tr><td>&nbsp;</td></tr>\n";
+
+    print
+"<tr><td align=\"center\"><input type=\"image\" src=\"pict/menu_b_add.jpg\" "
+      . "width=167 height=20 alt=\"Add\" border=\"0\">\n</form></td></tr></table>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# Conver the 'image' format to the 'volume' format
+sub convert {
+    my %img2vol = %{shift()};
+
+    my @invs = Caseman::read_invest();
+    if (scalar @invs == 0) {
+        push @invs, "unknown";
+    }
+
+    foreach $i (@invs) {
+        my $notes_file = "$::host_dir" . "$::LOGDIR/$i.notes";
+
+        if ((!(-e "$notes_file")) || (-z "$notes_file")) {
+            next;
+        }
+        Print::log_host_info(
+            "Converting format of notes file for $i ($notes_file)");
+
+        open NOTES, "<$notes_file" or die "Can't open log: $notes_file";
+
+        my $notes_file_new = $notes_file . ".new";
+        open NOTES_NEW, ">$notes_file_new"
+          or die "Can't open writing log: $notes_file_new";
+
+        while (<NOTES>) {
+
+            if (/Image: ($::REG_IMG)\s+(.*)$/) {
+                my $img  = $1;
+                my $addr = $2;
+
+                unless (exists $img2vol{$img}) {
+                    print STDERR
+"Error finding image during notes conversion: $img.  Not converting\n";
+                    next;
+                }
+                my $vol = $img2vol{$img};
+
+                # Convert old description to last versions
+                $addr =~ s/Inode:/Meta:/;
+                print NOTES_NEW "Volume: $vol   $addr\n";
+            }
+            else {
+                print NOTES_NEW $_;
+            }
+        }
+
+        close(NOTES);
+        close(NOTES_NEW);
+        rename $notes_file,     $notes_file . ".bak";
+        rename $notes_file_new, $notes_file;
+    }
+
+    # NOw do sequence notes
+    foreach $i (@invs) {
+        my $notes_file = "$::host_dir" . "$::LOGDIR/$i.seq.notes";
+        if ((!(-e "$notes_file")) || (-z "$notes_file")) {
+            next;
+        }
+
+        open NOTES, "$notes_file" or die "Can't open log: $notes_file";
+
+        $notes_file_new = $notes_file . ".new";
+        open NOTES_NEW, ">$notes_file_new"
+          or die "Can't open log for updating: $notes_file_new";
+
+        while (<NOTES>) {
+
+            # No image in entry
+            if (/^'\d+','\d+','\d+','\d+','\d+','\d+','$::REG_HOST','','/) {
+                print NOTES_NEW $_;
+            }
+            elsif (
+/^('\d+','\d+','\d+','\d+','\d+','\d+','$::REG_HOST',')($::REG_IMG)(','.*)$/
+              )
+            {
+                my $pre  = $1;
+                my $img  = $2;
+                my $post = $3;
+                unless (exists $img2vol{$img}) {
+                    print STDERR
+"Error finding image during notes conversion: $img.  Not converting\n";
+                    next;
+                }
+                my $vol = $img2vol{$img};
+                print NOTES_NEW $pre . $vol . $post . "\n";
+            }
+            else {
+                print NOTES_NEW "$_";
+                return;
+            }
+        }
+
+        close(NOTES);
+        close(NOTES_NEW);
+        rename $notes_file,     $notes_file . ".bak";
+        rename $notes_file_new, $notes_file;
+    }
+
+    return 0;
+}
diff --git a/lib/Print.pm b/lib/Print.pm
new file mode 100644
index 0000000000000000000000000000000000000000..417caa70f4646bd8fb4e8367473ee2c6f2be5652
--- /dev/null
+++ b/lib/Print.pm
@@ -0,0 +1,390 @@
+package Print;
+
+#
+# Utilities to print information
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2005 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 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.
+
+# Escape HTML entities
+# Converts \n to <br>\n
+sub html_encode {
+    my $text = shift;
+    $text =~ s/&/&amp;/gs;
+    $text =~ s/</&lt;/gs;
+    $text =~ s/>/&gt;/gs;
+    $text =~ s/\"/&quot;/gs;
+    $text =~ s/\n/<br>\n/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;
+}
+
+# remove control chars from printout
+# this does not escape HTML entities, so you can pass this HTML code
+sub print_output {
+    my $out = shift;
+    print "$out";
+
+    while (my $out = shift) {
+        foreach $_ (split(//, $out)) {
+            if (   ($_ eq "\n")
+                || ($_ eq "\r")
+                || ($_ eq "\f")
+                || ($_ eq "\t"))
+            {
+                print "$_";
+            }
+            elsif ((ord($_) < 0x20) && (ord($_) >= 0x00)) {
+                print "^" . ord($_);
+            }
+            else {
+                print "$_";
+            }
+        }
+    }
+}
+
+# Added to provide output in hexdump format
+# function gets called on a per-icat basis,
+# The offset value is the byte offset that this data
+# starts at, since the File.pm code calls it in 1024
+# byte chunks)
+sub print_hexdump {
+    my $out    = shift;    # data to output
+    my $offset = shift;    # starting byte offset in file
+    my $buf    = "";
+
+    foreach $i (split(//, $out)) {
+        my $idx = $offset % 16;
+
+        if ($idx == 0) {
+            printf("%08X:  ", $offset);
+        }
+
+        printf("%02X", ord($i));
+        if (($idx % 2) == 1) {
+            printf(" ");
+        }
+
+        $buf[$idx] = $i;
+
+        if ($idx == 15) {
+            print "   ";
+            for (my $j = 0; $j < 16; $j++) {
+                if ($buf[$j] =~ m/[ -~]/) {
+                    print $buf[$j];
+                }
+                else {
+                    print ".";
+                }
+                $buf[$j] = 0;
+            }
+            print "\n";
+        }
+        $offset++;
+    }
+
+    # print out last line if < 16 bytes long
+    my $l = $offset % 16;
+
+    if ($l) {
+        my $t = (16 - $l) * 2 + (16 - $l) / 2;
+        for (my $j = 0; $j < $t; $j++) {
+            print " ";
+        }
+        print "   ";
+        for (my $j = 0; $j < $l; $j++) {
+            if ($buf[$j] =~ m/[ -~]/) {
+                print $buf[$j];
+            }
+            else {
+                print ".";
+            }
+        }
+        print "\n";
+    }
+}
+
+############################################
+#
+# HTTP/HTML Headers and Footers
+
+# 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; charset=utf-8$::HTTP_NL$::HTTP_NL";
+
+    my $time = localtime();
+
+    print <<EOF;
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Autopsy ver. $::VER Forensic Browser -->
+<!-- Page created at: $time -->
+<head>
+  <title>$text</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <link rel="stylesheet" href="global.css">
+</head>
+
+EOF
+}
+
+sub print_html_footer_frameset {
+    print "\n</html>\n" . "$::HTTP_NL$::HTTP_NL";
+}
+
+# Create the header information with the body tag
+sub print_html_header {
+    print_html_header_frameset(shift);
+    print "<body bgcolor=\"$::BACK_COLOR\">\n\n";
+    print "<link rel=\"SHORTCUT ICON\" href=\"pict/favicon.ico\">\n";
+}
+
+sub print_html_footer {
+    print "\n</body>\n</html>\n" . "$::HTTP_NL$::HTTP_NL";
+}
+
+# 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";
+    print "<link rel=\"SHORTCUT ICON\" href=\"pict/favicon.ico\">\n";
+    $is_body = 1;
+}
+
+sub print_html_footer_tabs {
+    print "\n</body>\n</html>\n" . "$::HTTP_NL$::HTTP_NL";
+}
+
+# Header for front page to warn about java script
+sub print_html_header_javascript {
+    my $text = shift;
+    print "Content-Type: text/html; charset=utf-8$::HTTP_NL$::HTTP_NL";
+
+    my $time = localtime();
+
+    # The write line has to stay on one line
+    print <<EOF;
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Autopsy ver. $::VER Forensic Browser -->
+<!-- Page created at: $time -->
+<head>
+  <title>$text</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <link rel="stylesheet" href="global.css">
+  <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\">
+<link rel=\"SHORTCUT ICON\" href=\"pict/favicon.ico\">
+
+EOF
+}
+
+sub print_html_footer_javascript {
+    print "\n</body>\n</html>\n" . "$::HTTP_NL$::HTTP_NL";
+}
+
+# For raw text outputs (Pass the name of a file if it is being saved)
+sub print_text_header {
+    print "Content-Type: text/plain; charset=utf-8$::HTTP_NL";
+    if (scalar @_ > 0) {
+        my $fname = shift();
+        print "Content-Disposition: inline; " . "filename=$fname;$::HTTP_NL";
+    }
+    print "$::HTTP_NL";
+}
+
+sub print_text_footer {
+    print "$::HTTP_NL$::HTTP_NL";
+}
+
+# For forced save outputs
+sub print_oct_header {
+    print "Content-Type: application/octet-stream$::HTTP_NL";
+    if (scalar @_ > 0) {
+        my $fname = shift();
+        print "Content-Disposition: inline; " . "filename=$fname;$::HTTP_NL";
+    }
+    print "$::HTTP_NL";
+}
+
+sub print_oct_footer {
+}
+
+# Error message that is used when an HTTP/HTML header is needed
+# This escapes the characters that chould be HTML entities.
+# it will also replace \n with <br> and other things that html_encode()
+# can do. Do not send arbitrary HTML to this function.
+sub print_check_err {
+    print_html_header("");
+    print html_encode(shift()) . "<br>\n";
+    print_html_footer();
+    sleep(1);
+    exit 1;
+}
+
+# Error message when header already exists
+# This escapes the characters that chould be HTML entities.
+# it will also replace \n with <br> and other things that html_encode()
+# can do. Do not send arbitrary HTML to this function.
+sub print_err {
+    print html_encode(shift()) . "<br>\n";
+    sleep(1);
+    print_html_footer();
+    exit 1;
+}
+
+##################################################################
+#
+# Logging
+#
+#
+
+sub investig_log_fname {
+    return "" unless (defined $::host_dir       && $::host_dir        ne "");
+    return "" unless (exists $Args::args{'inv'} && $Args::args{'inv'} ne "");
+
+    return "$::host_dir" . "$::LOGDIR/$Args::args{'inv'}.log";
+}
+
+sub investig_exec_log_fname {
+    return "" unless (defined $::host_dir       && $::host_dir        ne "");
+    return "" unless (exists $Args::args{'inv'} && $Args::args{'inv'} ne "");
+
+    return "$::host_dir" . "$::LOGDIR/$Args::args{'inv'}.exec.log";
+}
+
+sub host_log_fname {
+    return "" unless (defined $::host_dir && $::host_dir ne "");
+
+    return "$::host_dir" . "$::LOGDIR/host.log";
+}
+
+sub case_log_fname {
+    return "" unless (defined $::case_dir && $::case_dir ne "");
+
+    return "$::case_dir" . "case.log";
+}
+
+# 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();
+    return if ($fname eq "");
+
+    open HOSTLOG, ">>$fname" or die "Can't open log: $fname";
+    print HOSTLOG "$date: $str\n";
+    close(HOSTLOG);
+
+    return;
+}
+
+sub log_host_inv_exec {
+    return unless ($::USE_LOG == 1);
+    my $str = shift;
+    chomp $str;
+
+    my $date  = localtime;
+    my $fname = investig_exec_log_fname();
+    return if ($fname eq "");
+
+    open HOSTLOG, ">>$fname" or die "Can't open log: $fname";
+    print HOSTLOG "$date: $str\n";
+    close(HOSTLOG);
+
+    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();
+    return if ($fname eq "");
+
+    open HOSTLOG, ">>$fname" or die "Can't open log: $fname";
+    print HOSTLOG "$date: $str\n";
+    close(HOSTLOG);
+
+    return;
+}
+
+sub log_case_info {
+    return unless ($::USE_LOG == 1);
+    my $str = shift;
+    chomp $str;
+    my $date  = localtime;
+    my $fname = case_log_fname();
+    return if ($fname eq "");
+
+    open CASELOG, ">>$fname" or die "Can't open log: $fname";
+    print CASELOG "$date: $str\n";
+    close(CASELOG);
+
+    return;
+}
+
+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;
+}
+
+1;
diff --git a/lib/Timeline.pm b/lib/Timeline.pm
new file mode 100644
index 0000000000000000000000000000000000000000..4cd676af939859892f2e9a60a9c2f29054e9791c
--- /dev/null
+++ b/lib/Timeline.pm
@@ -0,0 +1,1425 @@
+#
+# Timeline functions
+#
+# Brian Carrier [carrier@sleuthkit.org]
+# Copyright (c) 2001-2005 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 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.
+
+package Timeline;
+
+use POSIX;    # needed for tzset
+
+# Changing the order of this may affect the main function ordering
+
+$Timeline::BLANK      = 0;
+$Timeline::FRAME      = 1;
+$Timeline::TABS       = 2;
+$Timeline::BODY_ENTER = 3;
+$Timeline::BODY_RUN   = 4;
+$Timeline::TL_ENTER   = 5;
+$Timeline::TL_RUN     = 6;
+$Timeline::VIEW_FR    = 7;
+$Timeline::VIEW_MENU  = 8;
+$Timeline::VIEW_IDX   = 9;
+$Timeline::VIEW_SUM   = 10;
+$Timeline::VIEW       = 11;
+
+# Types of modes for fname (i.e. can we overwrite it if it exists)
+my $FNAME_MODE_INIT = 0;
+my $FNAME_MODE_OVER = 1;
+
+sub main {
+
+    return if ($::LIVE == 1);
+
+    # By default, show the main frame
+    $Args::args{'view'} = $Args::enc_args{'view'} = $Timeline::FRAME
+      unless (exists $Args::args{'view'});
+
+    Args::check_view();
+    my $view = Args::get_view();
+
+    if ($view < $Timeline::VIEW_FR) {
+        if ($view == $Timeline::BLANK) {
+            return blank();
+        }
+        elsif ($view == $Timeline::FRAME) {
+            return frame();
+        }
+        elsif ($view == $Timeline::TABS) {
+            return tabs();
+        }
+        elsif ($view == $Timeline::BODY_ENTER) {
+            return body_enter();
+        }
+        elsif ($view == $Timeline::BODY_RUN) {
+            return body_run();
+        }
+        elsif ($view == $Timeline::TL_ENTER) {
+            return tl_enter();
+        }
+        elsif ($view == $Timeline::TL_RUN) {
+            return tl_run();
+        }
+    }
+    else {
+        if ($view == $Timeline::VIEW_FR) {
+            return view_fr();
+        }
+        elsif ($view == $Timeline::VIEW_MENU) {
+            return view_menu();
+        }
+        elsif ($view == $Timeline::VIEW_IDX) {
+            return view_idx();
+        }
+        elsif ($view == $Timeline::VIEW_SUM) {
+            return view_sum();
+        }
+        elsif ($view == $Timeline::VIEW) {
+            return view();
+        }
+    }
+    Print::print_check_err("Invalid Timeline View");
+}
+
+# Call the appropriate function based on the value of sort
+sub frame {
+    Print::print_html_header_frameset(
+        "Timeline: $Args::args{'case'}:$Args::args{'host'}");
+
+    print "<frameset rows=\"38,*\">\n";
+
+    my $submod = $Timeline::BLANK;
+    $submod = Args::get_submod() if (exists $Args::args{'submod'});
+
+    # Listing
+    print "<frame src=\"$::PROGNAME?mod=$::MOD_TL&view=$Timeline::TABS&"
+      . "$Args::baseargs&submod=$submod\">\n";
+
+    my $str = "";
+
+    # Contents
+    if ($submod == $Timeline::BLANK) {
+        print
+"<frame src=\"$::PROGNAME?mod=$::MOD_TL&view=$Timeline::BLANK&$Args::baseargs\" "
+          . "name=\"content\">\n</frameset>\n";
+        return;
+    }
+    elsif ($submod == $Timeline::TL_ENTER) {
+        $str .= "&body=$Args::args{'body'}" if (exists $Args::args{'body'});
+    }
+    elsif ($submod == $Timeline::VIEW_FR) {
+        $str .= "&tl=$Args::args{'tl'}" if (exists $Args::args{'tl'});
+    }
+
+    print
+"<frame src=\"$::PROGNAME?mod=$::MOD_TL&view=$submod&$Args::baseargs$str\" "
+      . "name=\"content\">\n</frameset>\n";
+
+    Print::print_html_footer_frameset();
+    return 0;
+}
+
+# The tabs / button images in timeline view
+sub tabs {
+    Args::check_submod();
+    Print::print_html_header_tabs("Timeline Mode Tabs");
+
+    my $submod = Args::get_submod();
+
+    print "<center><table width=\"800\" border=\"0\" "
+      . "cellspacing=\"0\" cellpadding=\"0\"><tr>\n";
+
+    # Create Datafile
+    print "<td align=\"center\" width=174>"
+      . "<a href=\"$::PROGNAME?mod=$::MOD_TL&view=$Timeline::FRAME&"
+      . "submod=$Timeline::BODY_ENTER&$Args::baseargs\" target=\"_top\">";
+
+    if ($submod == $Timeline::BODY_ENTER) {
+        print "<img border=0 "
+          . "src=\"pict/tl_t_data_cur.jpg\" "
+          . "width=174 height=38 "
+          . "alt=\"Create Data File (Current Mode)\"></a>\n";
+    }
+    else {
+        print "<img border=0 "
+          . "src=\"pict/tl_t_data_link.jpg\" "
+          . "width=174 height=38 "
+          . "alt=\"Create Data File\"></a>\n";
+    }
+
+    print "</td>\n"
+      . "<td align=\"center\" width=174>"
+      . "<a href=\"$::PROGNAME?mod=$::MOD_TL&view=$Timeline::FRAME&"
+      . "submod=$Timeline::TL_ENTER&$Args::baseargs\" "
+      . "target=\"_top\">";
+
+    # Create Timeline
+    if ($submod == $Timeline::TL_ENTER) {
+        print "<img border=0 "
+          . "src=\"pict/tl_t_tl_cur.jpg\" "
+          . "width=174 height=38 "
+          . "alt=\"Create Timeline (Current Mode)\"></a>\n";
+    }
+    else {
+        print "<img border=0 "
+          . "src=\"pict/tl_t_tl_link.jpg\" "
+          . "width=174 height=38 "
+          . "alt=\"Create Timeline\"></a>\n";
+    }
+    print "</td>\n"
+      . "<td align=\"center\" width=174>"
+      . "<a href=\"$::PROGNAME?mod=$::MOD_TL&view=$Timeline::FRAME&"
+      . "submod=$Timeline::VIEW_MENU&$Args::baseargs\" "
+      . "target=\"_top\">";
+
+    # View Timeline
+    if (($submod == $Timeline::VIEW_FR) || ($submod == $Timeline::VIEW_MENU)) {
+        print "<img border=0 "
+          . "src=\"pict/tl_t_view_cur.jpg\" "
+          . "width=174 height=38 "
+          . "alt=\"View Timeline (Current Mode)\"></a>\n";
+    }
+    else {
+        print "<img border=0 "
+          . "src=\"pict/tl_t_view_link.jpg\" "
+          . "width=174 height=38 "
+          . "alt=\"View Timeline\"></a>\n";
+    }
+
+    # Notes
+    print "</td>\n" . "<td align=\"center\" width=174>";
+    if ($::USE_NOTES == 1) {
+        print
+"<a href=\"$::PROGNAME?mod=$::MOD_NOTES&view=$Notes::READ_NORM&$Args::baseargs_novol\" "
+          . "target=\"_blank\">"
+          . "<img border=0 "
+          . "src=\"pict/tl_t_notes_link.jpg\" "
+          . "width=174 height=38 "
+          . "alt=\"View Notes\"></a></td>\n";
+    }
+    else {
+        print "<img border=0 "
+          . "src=\"pict/tl_t_notes_org.jpg\" "
+          . "width=174 height=38 "
+          . "alt=\"View Notes\"></a></td>\n";
+    }
+
+    # Help - set to current submod
+    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?mod=$::MOD_CASEMAN&"
+      . "view=$Caseman::VOL_OPEN&$Args::baseargs\" target=\"_top\">"
+      . "<img border=0 src=\"pict/tab_close.jpg\" width=52 "
+      . "alt=\"Exit to Host Manager\"></a></td>\n"
+      . "</tr></table>\n";
+
+    Print::print_html_footer_tabs();
+    return 0;
+}
+
+sub body_enter {
+    Print::print_html_header("Enter Data to Make Body File");
+
+    my $i;
+    my %mnt2img;
+
+    # Cycle through each image we read from fsmorgue
+    foreach $i (keys %Caseman::vol2mnt) {
+        next
+          unless ($Caseman::vol2cat{$i} eq "part");
+        next
+          if ( ($Caseman::vol2ftype{$i} eq "swap")
+            || ($Caseman::vol2ftype{$i} eq "raw"));
+        $mnt2vol{"$Caseman::vol2mnt{$i}--$i"} = $i;
+    }
+
+# sort via parent volume, then starting location, and then mount point (which includes the name)
+    my @mnt = sort {
+        ($Caseman::vol2par{$mnt2vol{$a}} cmp $Caseman::vol2par{$mnt2vol{$b}})
+          or ($Caseman::vol2start{$mnt2vol{$a}} <=>
+            $Caseman::vol2start{$mnt2vol{$b}})
+          or (lc($a) cmp lc($b))
+    } keys %mnt2vol;
+
+    print "<form action=\"$::PROGNAME\" method=\"get\">\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_TL\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Timeline::BODY_RUN\">\n"
+      . Args::make_hidden()
+      . "<p>Here  we will process the file system images, collect the temporal data, and save the data to a single file."
+      . "<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 $vol = $mnt2vol{$mnt[$i]};
+
+        print "<tr><td><input type=\"checkbox\" name=\"$vol\" value=\"1\">"
+          . "</td><td><tt>$Caseman::vol2mnt{$vol}</tt></td><td><tt>$Caseman::vol2sname{$vol}</tt></td>"
+          . "<td>$Caseman::vol2ftype{$vol}</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>"
+      . "</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\" "
+      . "width=43 height=20 alt=\"Ok\" border=\"0\"></form>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+sub body_run {
+    Args::check_fname();
+    Args::check_fname_mode();
+    Print::print_html_header("Make Body File");
+
+    my $fname_rel = Args::get_fname_rel();
+    my $fname     = Args::get_fname();
+
+    my $fname_mode = $Args::args{'fname_mode'};
+
+    if ((-e "$fname") && ($FNAME_MODE_INIT == $fname_mode)) {
+        print "File Already Exists: $fname_rel\n";
+
+        my $hidden = Args::make_hidden();
+
+        $hidden .=
+            "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_TL\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Timeline::BODY_RUN\">\n";
+
+        my $i;
+        foreach $i (%Caseman::vol2mnt) {
+            $hidden .= "<input type=\"hidden\" name=\"$i\" value=\"1\">\n"
+              if (exists $Args::args{$i});
+        }
+
+        $hidden .=
+            "<input type=\"hidden\" name=\"al_file\" "
+          . "value=\"$Args::args{'al_file'}\">\n"
+          if (exists $Args::args{'al_file'});
+        $hidden .=
+            "<input type=\"hidden\" name=\"unal_file\" "
+          . "value=\"$Args::args{'unal_file'}\">\n"
+          if (exists $Args::args{'unal_file'});
+        $hidden .=
+            "<input type=\"hidden\" name=\"md5\" "
+          . "value=\"$Args::args{'md5'}\">\n"
+          if (exists $Args::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\" "
+          . "width=79 height=20 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\" "
+          . "width=66 height=20 alt=\"Replace\" border=\"0\"><br>\n"
+          . "<input type=\"hidden\" name=\"fname\" value=\"$Args::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  = "";
+
+    # What kind of data are we collecting?
+    my $al_file = 0;
+    if (exists $Args::args{'al_file'}) {
+        $al_file = $Args::args{'al_file'};
+        $log_type .= "Allocated Files";
+    }
+
+    my $unal_file = 0;
+    if (exists $Args::args{'unal_file'}) {
+        $unal_file = $Args::args{'unal_file'};
+        $log_type .= ", " if ($log_type ne "");
+        $log_type .= "Unallocated Files";
+    }
+
+    if (($unal_file == 0) && ($al_file == 0)) {
+        print
+          "No data types were selected.  You must select at least one.<br>\n";
+        return 1;
+    }
+
+    my $tz = "";
+    $tz = "-z '$Caseman::tz'" unless ("$Caseman::tz" eq "");
+
+    my $i;
+    my $found = 0;
+    local *OUT;
+
+    # Analyze each image - the image names are passed as an argument
+    foreach $i (keys %Caseman::vol2mnt) {
+        if (exists $Args::args{$i}) {
+
+            $found = 1;
+            my $ftype   = $Caseman::vol2ftype{$i};
+            my $img     = $Caseman::vol2path{$i};
+            my $offset  = $Caseman::vol2start{$i};
+            my $imgtype = $Caseman::vol2itype{$i};
+            my $mnt     = $Caseman::vol2mnt{$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";
+                Exec::exec_pipe(*OUT,
+"'$::TSKDIR/fls' $tz -s $Caseman::ts -m '$mnt' -f $ftype -r -o $offset -i $imgtype $img >> '$fname'"
+                );
+                print "$_<br>\n" while ($_ = Exec::read_pipe_line(*OUT));
+                close(OUT);
+            }
+            elsif ($al_file) {
+                print "Running <tt>fls -ru -m</tt> on <tt>$i</tt><br>\n";
+                Exec::exec_pipe(*OUT,
+"'$::TSKDIR/fls' $tz -s $Caseman::ts -m '$mnt' -f $ftype -ru -o $offset -i $imgtype $img >> '$fname'"
+                );
+                print "$_<br>\n" while ($_ = Exec::read_pipe_line(*OUT));
+                close(OUT);
+            }
+            elsif ($unal_file) {
+                print "Running <tt>fls -rd -m</tt> on <tt>$i</tt><br>\n";
+                Exec::exec_pipe(*OUT,
+"'$::TSKDIR/fls' $tz -s $Caseman::ts -m '$mnt' -f $ftype -rd -o $offset -i $imgtype $img >> '$fname'"
+                );
+                print "$_<br>\n" while ($_ = Exec::read_pipe_line(*OUT));
+                close(OUT);
+            }
+        }
+    }
+
+    unless ($found) {
+        print
+"No images were given for analysis.  At least one must be selected.<br>\n";
+        return 1;
+    }
+
+    Print::log_host_inv(
+        "Saving timeline data for $log_type for $log_files to $fname_rel");
+
+    # append to  host config
+    my $bod_vol = Caseman::add_vol_host_config("body", $fname_rel);
+    $Caseman::vol2cat{$bod_vol}   = "timeline";
+    $Caseman::vol2ftype{$bod_vol} = "body";
+    $Caseman::vol2itype{$bod_vol} = "raw";
+    $Caseman::vol2path{$bod_vol}  = $fname;
+    $Caseman::vol2start{$bod_vol} = 0;
+    $Caseman::vol2end{$bod_vol}   = 0;
+    $Caseman::vol2sname{$bod_vol} = $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::args{'md5'}) && ($Args::args{'md5'} == 1)) {
+        print "Calculating MD5 Value<br><br>\n";
+        my $m = Hash::int_create_wrap($bod_vol);
+        print "MD5 Value: <tt>$m</tt><br><br>\n";
+    }
+
+    print "<p>The next step is to sort the data into a timeline."
+      . "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
+      . "<input type=\"hidden\" name=\"body\" value=\"$bod_vol\">\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_TL\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Timeline::FRAME\">\n"
+      . "<input type=\"hidden\" name=\"submod\" value=\"$Timeline::TL_ENTER\">\n"
+      . Args::make_hidden()
+      . "<input type=\"image\" src=\"pict/but_ok.jpg\" "
+      . "width=43 height=20 alt=\"Ok\" border=\"0\">\n</form>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+my $OTYPE_NORM   = 1;
+my $OTYPE_HOURLY = 2;
+my $OTYPE_DAILY  = 3;
+
+sub tl_enter {
+    Print::print_html_header("Enter data for timeline");
+
+    my @body;
+
+    # Find the body files if we will be looking for them
+    unless ((exists $Args::args{'body'})
+        && (exists $Caseman::vol2cat{$Args::args{'body'}}))
+    {
+        foreach my $k (keys %Caseman::vol2cat) {
+            if (   ($Caseman::vol2cat{$k} eq "timeline")
+                && ($Caseman::vol2ftype{$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?$Args::baseargs&"
+              . "mod=$::MOD_TL&view=$Timeline::FRAME&"
+              . "submod=$Timeline::BODY_ENTER\">"
+              . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
+              . "width=\"43\" height=20 border=\"0\">"
+              . "</a>\n";
+            return 1;
+        }
+    }
+    print "Now we will sort the data and save it to a timeline.<p>\n"
+      . "<form action=\"$::PROGNAME\" method=\"get\">\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_TL\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Timeline::TL_RUN\">\n"
+      . Args::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::args{'body'}) {
+        print "<tr><td><input type=\"radio\" name=\"body\" "
+          . "value=\"$Args::args{'body'}\" CHECKED>"
+          . "</td><td>$Caseman::vol2sname{$Args::args{'body'}}</td>\n";
+    }
+    else {
+        my @body_sort = sort { lc($a) cmp lc($b) } @body;
+        my $chk = " CHECKED";
+        for (my $i = 0; $i <= $#body_sort; $i++) {
+            print "<tr><td><input type=\"radio\" name=\"body\" "
+              . "value=\"$body_sort[$i]\" $chk></td><td>$Caseman::vol2sname{$body_sort[$i]}</td>\n";
+            $chk = "";
+        }
+    }
+
+    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\" value=\"timeline.txt\"><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_vol = "";
+    foreach my $i (keys %Caseman::vol2ftype) {
+        my $f = $Caseman::vol2ftype{$i};
+
+        next
+          unless (($f =~ /^ext/)
+            || ($f =~ /^ufs/)
+            || ($f =~ /^linux/)
+            || ($f =~ /bsd$/)
+            || ($f =~ /^solaris$/)
+            || ($f =~ /^bsdi$/));
+
+        push @unix_vols, $i;
+
+        # Keep a reference to an image with '/' as the mounting point
+        $root_vol = $i
+          if ($Caseman::vol2mnt{$i} eq '/');
+    }
+
+    my $cnt = 5;
+    if (scalar @unix_vols > 0) {
+
+        print
+"<p>$cnt.  Select the UNIX image that contains the /etc/passwd and /etc/group files:<br>\n";
+        $cnt++;
+
+        print "<select name=\"pw_vol\">\n";
+
+        # If we did not find an image that has a / mounting point, then
+        # we will use none as the default.
+        if ($root_vol eq "") {
+            print "<option value=\"\" selected>None</option>\n";
+        }
+        else {
+            print "<option value=\"\">None</option>\n";
+        }
+
+        foreach my $vol (@unix_vols) {
+            if ($root_vol eq $vol) {
+                print
+"<option value=\"$vol\" selected>$Caseman::vol2sname{$vol} ($Caseman::vol2mnt{$vol})"
+                  . "</option>\n";
+            }
+            else {
+                print
+"<option value=\"$vol\">$Caseman::vol2sname{$vol} ($Caseman::vol2mnt{$vol})</option>\n";
+            }
+        }
+
+        print "</select>\n";
+    }
+
+    print "<p>$cnt. Choose the output format:<br>\n";
+    $cnt++;
+    print
+"&nbsp;&nbsp;<input type=\"radio\" name=\"sort\" value=\"$OTYPE_NORM\" CHECKED>Tabulated (normal)<br>\n"
+      . "&nbsp;&nbsp;<input type=\"radio\" name=\"sort\" value=\"$OTYPE_HOURLY\">Comma delimited with hourly summary<br>\n"
+      . "&nbsp;&nbsp;<input type=\"radio\" name=\"sort\" value=\"$OTYPE_DAILY\">Comma delimited with daily summary<br>\n";
+
+    print "<p>$cnt.  Generate MD5 Value? ";
+    $cnt++;
+
+    print "<input type=\"checkbox\" name=\"md5\" value=\"1\" CHECKED>\n";
+
+    # Create Button
+    print "<p><input type=\"image\" src=\"pict/but_ok.jpg\" "
+      . "width=43 height=20 alt=\"Ok\" border=\"0\">\n</form>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+sub tl_run {
+    Args::check_fname();
+    Args::check_body();
+    Args::check_sort();
+
+    Print::print_html_header("Make Timeline");
+
+    my $body      = Args::get_body();
+    my $fname     = Args::get_fname();
+    my $fname_rel = Args::get_fname_rel();
+    my $otype     = Args::get_sort();
+
+    my $fname_mode = $Args::args{'fname_mode'};
+
+    if ((-e "$fname") && ($FNAME_MODE_INIT == $fname_mode)) {
+        print "File Already Exists: <tt>$fname_rel</tt><br>\n";
+
+        my $hidden =
+          "<input type=\"hidden\" name=\"body\" value=\"$Args::args{'body'}\">"
+          . Args::make_hidden();
+
+        $hidden .=
+            "<input type=\"hidden\" name=\"st_none\" "
+          . "value=\"$Args::args{'st_none'}\">\n"
+          if (exists $Args::args{'st_none'});
+        $hidden .=
+            "<input type=\"hidden\" name=\"st_year\" "
+          . "value=\"$Args::args{'st_year'}\">\n"
+          if (exists $Args::args{'st_year'});
+        $hidden .=
+            "<input type=\"hidden\" name=\"st_day\" "
+          . "value=\"$Args::args{'st_day'}\">\n"
+          if (exists $Args::args{'st_day'});
+        $hidden .=
+            "<input type=\"hidden\" name=\"st_mon\" "
+          . "value=\"$Args::args{'st_mon'}\">\n"
+          if (exists $Args::args{'st_mon'});
+        $hidden .=
+            "<input type=\"hidden\" name=\"end_none\" "
+          . "value=\"$Args::args{'end_none'}\">\n"
+          if (exists $Args::args{'end_none'});
+        $hidden .=
+            "<input type=\"hidden\" name=\"end_year\" "
+          . "value=\"$Args::args{'end_year'}\">\n"
+          if (exists $Args::args{'end_year'});
+        $hidden .=
+            "<input type=\"hidden\" name=\"end_day\" "
+          . "value=\"$Args::args{'end_day'}\">\n"
+          if (exists $Args::args{'end_day'});
+        $hidden .=
+            "<input type=\"hidden\" name=\"end_mon\" "
+          . "value=\"$Args::args{'end_mon'}\">\n"
+          if (exists $Args::args{'end_mon'});
+        $hidden .=
+            "<input type=\"hidden\" name=\"tz\" "
+          . "value=\"$Args::args{'tz'}\">\n"
+          if (exists $Args::args{'tz'});
+        $hidden .=
+            "<input type=\"hidden\" name=\"pw_vol\" "
+          . "value=\"$Args::args{'pw_vol'}\">\n"
+          if (exists $Args::args{'pw_vol'});
+        $hidden .=
+            "<input type=\"hidden\" name=\"md5\" "
+          . "value=\"$Args::args{'md5'}\">\n"
+          if (exists $Args::args{'md5'});
+        $hidden .=
+            "<input type=\"hidden\" name=\"sort\" "
+          . "value=\"$Args::args{'sort'}\">\n"
+          if (exists $Args::args{'sort'});
+
+        # 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=\"mod\" value=\"$::MOD_TL\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Timeline::TL_RUN\">\n"
+          . "<input type=\"hidden\" name=\"fname_mode\" value=\"$FNAME_MODE_INIT\">\n"
+          . "$hidden\n"
+          . "<input type=\"image\" src=\"pict/but_new_name.jpg\" "
+          . "width=79 height=20 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\" "
+          . "width=66 height=20 alt=\"Replace\" border=\"0\"><br>\n"
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_TL\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Timeline::TL_RUN\">\n"
+          . "<input type=\"hidden\" name=\"fname\" value=\"$Args::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::args{'st_none'}) && ($Args::args{'st_none'} == 1)) {
+
+        if (exists $Args::args{'st_mon'}) {
+            Args::check_st_mon();
+            $mon = Args::get_st_mon();
+            if (($mon < 1) || ($mon > 12)) {
+                print("Invalid starting month\n");
+                return 1;
+            }
+            if ($mon < 10) {
+                $mon = "0" . $mon;
+            }
+        }
+        if (exists $Args::args{'st_year'}) {
+            Args::check_st_year();
+            $year = Args::get_st_year();
+            if (($year < 1970) || ($year > 2020)) {
+                print("Invalid starting year\n");
+                return 1;
+            }
+        }
+        if (   (exists $Args::args{'st_day'})
+            && ($Args::args{'st_day'} =~ /^(\d\d?)$/))
+        {
+            $day = $1;
+            if (($day < 1) || ($day > 31)) {
+                print("Invalid starting day\n");
+                return 1;
+            }
+            if ($day < 10) {
+                $day = "0" . $day;
+            }
+        }
+        else {
+            print("Invalid start day\n");
+            return 1;
+        }
+
+        $date = "$year-$mon-$day";
+    }
+
+    unless ((exists $Args::args{'end_none'}) && ($Args::args{'end_none'} == 1))
+    {
+
+        if ($date eq "") {
+            print "Begin date must be given if ending date is given<br>";
+            return 1;
+        }
+
+        if (   (exists $Args::args{'end_mon'})
+            && ($Args::args{'end_mon'} =~ /^(\d\d?)$/))
+        {
+            $mon = $1;
+            if (($mon < 1) || ($mon > 12)) {
+                print("Invalid end month\n");
+                return 1;
+            }
+            if ($mon < 10) {
+                $mon = "0" . $mon;
+            }
+        }
+        else {
+            print("Invalid end month\n");
+            return 1;
+        }
+        if (   (exists $Args::args{'end_year'})
+            && ($Args::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::args{'end_day'})
+            && ($Args::args{'end_day'} =~ /^(\d\d?)$/))
+        {
+            $day = $1;
+            if (($day < 1) || ($day > 31)) {
+                print("Invalid end day\n");
+                return 1;
+            }
+            if ($day < 10) {
+                $day = "0" . $day;
+            }
+        }
+        else {
+            print("Invalid end day\n");
+            return 1;
+        }
+
+        $date .= "..$year-$mon-$day";
+    }
+
+    # temp strings for the password and group files
+    my $pw_tmp   = "";
+    my $gr_tmp   = "";
+    my $mac_args = "";
+    my $log      = "";
+
+    local *OUT;
+
+    # Password and Group Files
+    if ((exists $Args::args{'pw_vol'}) && ($Args::args{'pw_vol'} ne "")) {
+        Args::check_vol('pw_vol');
+        my $pw_vol = Args::get_vol('pw_vol');
+
+        my $ftype   = $Caseman::vol2ftype{$pw_vol};
+        my $img     = $Caseman::vol2path{$pw_vol};
+        my $offset  = $Caseman::vol2start{$pw_vol};
+        my $imgtype = $Caseman::vol2itype{$pw_vol};
+
+        $log .= "Password & Group File ($pw_vol) ";
+
+        # Get the passwd file meta and copy the file
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/ifind' -f $ftype -n 'etc/passwd' -o $offset -i $imgtype $img"
+        );
+        my $pwi = Exec::read_pipe_line(*OUT);
+        close(OUT);
+
+        $pwi = "Error getting meta for passwd"
+          if ((!defined $pwi) || ($pwi eq ""));
+
+        # Do the Taint Checking
+        if ($pwi =~ /^($::REG_META)$/) {
+            $pwi = $1;
+
+            $log .= "Password Meta Address ($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;
+                }
+            }
+
+            Exec::exec_sys(
+"'$::TSKDIR/icat' -f $ftype -o $offset -i $imgtype $img $pwi > '$pw_tmp'"
+            );
+            $mac_args .= " -p \'$pw_tmp\' ";
+
+        }
+        else {
+            print(
+"Error finding /etc/passwd meta in $Caseman::vol2sname{$pw_vol} ($pwi)<br>"
+            );
+            Print::log_host_inv(
+"$Caseman::vol2sname{$pw_vol}: /etc/passwd file not found for timeline"
+            );
+        }
+
+        # Get the group file meta and copy the file
+        Exec::exec_pipe(*OUT,
+"'$::TSKDIR/ifind' -f $ftype -n 'etc/group' -o $offset -i $imgtype $img"
+        );
+        my $gri = Exec::read_pipe_line(*OUT);
+        close(OUT);
+
+        $gri = "Error getting meta for group"
+          if ((!defined $gri) || ($gri eq ""));
+
+        # Do the Taint Checking
+        if ($gri =~ /^($::REG_META)$/) {
+            $gri = $1;
+
+            $log .= "Group Meta Address ($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;
+                }
+            }
+            Exec::exec_sys(
+"'$::TSKDIR/icat' -f $ftype -o $offset -i $imgtype $img $gri > '$gr_tmp'"
+            );
+            $mac_args .= " -g \'$gr_tmp\' ";
+        }
+        else {
+            print(
+"Error finding /etc/group meta in $Caseman::vol2sname{$pw_vol} ($gri)<br>"
+            );
+            Print::log_host_inv(
+"$Caseman::vol2sname{$pw_vol}: /etc/group file not found for timeline"
+            );
+        }
+    }
+
+    if ($date eq "") {
+        print
+          "Creating Timeline using all dates (Time Zone: $Caseman::tz)<br>\n";
+        Print::log_host_inv(
+"$Caseman::vol2sname{$body}: Creating timeline using all dates (TZ: $Caseman::tz) ${log}to $fname_rel"
+        );
+    }
+    else {
+        print "Creating Timeline for $date (Time Zone: $Caseman::tz)<br>\n";
+        Print::log_host_inv(
+"$Caseman::vol2sname{$body}: Creating timeline for $date (TZ: $Caseman::tz) ${log}to $fname_rel"
+        );
+    }
+
+    my $tz = "";
+    $tz = "-z '$Caseman::tz'" unless ("$Caseman::tz" eq "");
+
+    # mactime needs the path to run the 'date' command
+    $ENV{PATH} = "/bin:/usr/bin";
+    local *OUT;
+    if ($otype == $OTYPE_NORM) {
+        Exec::exec_pipe(*OUT,
+"LANG=C LC_ALL=C '$::TSKDIR/mactime' -b $Caseman::vol2path{$body} $tz -i day '${fname}.sum' $mac_args $date > '$fname'"
+        );
+    }
+    elsif ($otype == $OTYPE_HOURLY) {
+        Exec::exec_pipe(*OUT,
+"LANG=C LC_ALL=C '$::TSKDIR/mactime' -b $Caseman::vol2path{$body} $tz  -d -i hour '${fname}.sum' $mac_args $date > '$fname'"
+        );
+    }
+    elsif ($otype == $OTYPE_DAILY) {
+        Exec::exec_pipe(*OUT,
+"LANG=C LC_ALL=C '$::TSKDIR/mactime' -b $Caseman::vol2path{$body} $tz -d -i day '${fname}.sum' $mac_args $date > '$fname'"
+        );
+    }
+    else {
+        Print::print_err("Unknown output type");
+    }
+
+    print "$_<br>\n" while ($_ = Exec::read_pipe_line(*OUT));
+    close(OUT);
+    $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 if a normal timeline
+    if ($otype == $OTYPE_NORM) {
+        my $tl_vol = Caseman::add_vol_host_config("timeline", $fname_rel);
+        print "Entry added to host config file<br><br>\n";
+
+        $Caseman::vol2cat{$tl_vol}   = "timeline";
+        $Caseman::vol2ftype{$tl_vol} = "timeline";
+        $Caseman::vol2itype{$tl_vol} = "raw";
+        $Caseman::vol2path{$tl_vol}  = "$fname";
+        $Caseman::vol2start{$tl_vol} = 0;
+        $Caseman::vol2end{$tl_vol}   = 0;
+        $Caseman::vol2sname{$tl_vol} = $fname_rel;
+
+        # Calculate MD5
+        if ((exists $Args::args{'md5'}) && ($Args::args{'md5'} == 1)) {
+            print "Calculating MD5 Value<br><br>\n";
+            my $m = Hash::int_create_wrap($tl_vol);
+            print "MD5 Value: <tt>$m</tt><br><br>\n";
+        }
+
+        print "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
+          . "<input type=\"hidden\" name=\"tl\" value=\"$tl_vol\">\n"
+          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_TL\">\n"
+          . "<input type=\"hidden\" name=\"view\" value=\"$Timeline::FRAME\">\n"
+          . "<input type=\"hidden\" name=\"submod\" value=\"$Timeline::VIEW_FR\">\n"
+          . Args::make_hidden()
+          . "<input type=\"image\" src=\"pict/but_ok.jpg\" "
+          . "width=43 height=20 alt=\"Ok\" border=\"0\">\n</form>\n"
+          . "(NOTE: It is easier to view the timeline in a text editor than here)";
+    }
+    else {
+        print
+          "Comma delimited files cannot be viewed from within Autopsy.<br>\n"
+          . "Open it in a spreadsheet or other data processing tool.<br>\n";
+    }
+    Print::print_html_footer();
+    return 0;
+}
+
+sub view_menu {
+    Print::print_html_header("View Timeline Menu");
+
+    my @tl;
+
+    # Find the timelines in the images hash
+    foreach my $k (keys %Caseman::vol2cat) {
+        if (   ($Caseman::vol2cat{$k} eq "timeline")
+            && ($Caseman::vol2ftype{$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?$Args::baseargs&mod=$::MOD_TL&view=$Timeline::FRAME&"
+          . "submod=$Timeline::TL_ENTER\">"
+          . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
+          . "width=\"43\" height=20 border=\"0\">"
+          . "</a>\n";
+
+        return 1;
+    }
+
+    print "<form action=\"$::PROGNAME\" method=\"get\">\n"
+      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_TL\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Timeline::VIEW_FR\">\n"
+      . Args::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++) {
+        print "<tr><td><input type=\"radio\" name=\"tl\" "
+          . "value=\"$tl_sort[$i]\"></td><td>$Caseman::vol2sname{$tl_sort[$i]}</td>\n";
+    }
+
+    print "</table>\n"
+      . "<input type=\"image\" src=\"pict/but_ok.jpg\" "
+      . "width=43 height=20 alt=\"Ok\" border=\"0\">\n</form>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+sub view_fr {
+    Args::check_tl();
+
+    Print::print_html_header_frameset("");
+    my $tl_vol = Args::get_tl();
+    my $tl     = $Caseman::vol2path{$tl_vol};
+    my $url    = "";
+
+    unless (exists $Args::args{'st_mon'}) {
+
+        unless (open(TL, $tl)) {
+            print("Error opening $tl");
+            return (1);
+        }
+
+        my $beg_mon;
+        my $beg_year;
+        my $cnt = 0;
+        while (<TL>) {
+            $cnt++;
+            if (/^(?:\w\w\w )?(\w\w\w)\s+\d\d\s+(\d\d\d\d)\s+\d\d:\d\d:\d\d/) {
+                $url = "tl=$tl_vol&st_mon=$::m2d{$1}&st_year=$2";
+
+            }
+            last;
+        }
+        close(TL);
+
+        if ($cnt == 0) {
+            print "Empty timeline<br>\n";
+            return 1;
+        }
+        if ($url eq "") {
+            print "Invalid Timeline<br>\n";
+            return 1;
+        }
+    }
+    else {
+        $url =
+            "tl=$tl_vol&st_mon=$Args::enc_args{'st_mon'}&"
+          . "st_year=$Args::enc_args{'st_year'}";
+    }
+
+    print "<frameset rows=\"65,*\">\n"
+      . "<frame src=\"$::PROGNAME?$Args::baseargs&mod=$::MOD_TL&"
+      . "view=$Timeline::VIEW_IDX&$url\">\n"
+      . "<frame src=\"$::PROGNAME?$Args::baseargs&mod=$::MOD_TL&"
+      . "view=$Timeline::VIEW&$url\">\n</frameset>";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+sub view_idx {
+    Args::check_st_mon();
+    Args::check_st_year();
+    Args::check_tl();
+
+    Print::print_html_header("View Timeline Index");
+
+    my $mon    = Args::get_st_mon();
+    my $year   = Args::get_st_year();
+    my $tl_vol = Args::get_tl();
+    my $tl     = $Caseman::vol2path{$tl_vol};
+
+    print "<center>";
+    my $url =
+        "$::PROGNAME?$Args::baseargs&mod=$::MOD_TL&view=$Timeline::VIEW_FR&"
+      . "tl=$tl_vol";
+
+    # 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?$Args::baseargs&"
+          . "mod=$::MOD_TL&view=$Timeline::VIEW_SUM&"
+          . "tl=$tl_vol\" 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=\"mod\" value=\"$::MOD_TL\">\n"
+      . "<input type=\"hidden\" name=\"view\" value=\"$Timeline::VIEW_FR\">\n"
+      . "<input type=\"hidden\" name=\"tl\" value=\"$tl_vol\">\n"
+      . Args::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\" "
+      . "width=43 height=20 border=\"0\"></td>\n"
+      . "</tr></table></form>\n";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# Display the contents of the summary file (hits per day) and show
+# it as hits per month
+sub view_sum {
+    Args::check_tl();
+
+    Print::print_html_header("View Timeline Summary");
+
+    my $tl_vol = Args::get_tl();
+    my $tl     = $Caseman::vol2path{$tl_vol};
+
+    $tl .= ".sum";
+
+    open(TL, "<$tl") or die "Can not open $tl";
+    my $url =
+        "$::PROGNAME?$Args::baseargs&mod=$::MOD_TL&"
+      . "view=$Timeline::VIEW_FR&tl=$tl_vol";
+
+    print "<p>This page provides a monthly summary of activity.<br>"
+      . "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);
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# display a given month of the timeline
+sub view {
+    Args::check_tl();
+    Args::check_st_mon();
+    Args::check_st_year();
+
+    my $tl_vol  = Args::get_tl();
+    my $tl      = $Caseman::vol2path{$tl_vol};
+    my $st_mon  = Args::get_st_mon();
+    my $st_year = Args::get_st_year();
+
+    Print::print_html_header("View $st_mon, $st_year of Timeline");
+
+    unless (open(TL, "$tl")) {
+        print("Error opening $tl");
+        return (1);
+    }
+
+    Print::log_host_inv(
+        "$Args::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+([macb\.]+)\s+([-\/\?\w]+)\s+([\d\w\/]+)\s+([\d\w\/]+)\s+($::REG_META)\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 meta <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>"
+                  . Print::html_encode($f)
+                  . "</td></tr>\n";
+
+                $row++;
+            }
+        }
+        else {
+            print "Error parsing timeline: "
+              . Print::html_encode($_)
+              . "<br>\n";
+        }
+    }
+    close(TL);
+    print "</table>";
+
+    Print::print_html_footer();
+    return 0;
+}
+
+# Blank Page
+sub blank {
+    Print::print_html_header("");
+    print "<center><h3>File Activity Timelines</h3>\n"
+      . "Here you can create a timeline of file activity.<br>\n"
+      . "This process requires two steps:<p>\n"
+      . "1.  <b>Create Data File</b> from file system data&nbsp;&nbsp;->"
+      . "&nbsp;&nbsp;2.  <b>Create Timeline</b> from the data file\n"
+      . "<p>Use the tabs above to start.\n";
+    Print::print_html_footer();
+    return 0;
+}
diff --git a/lib/Vs.pm b/lib/Vs.pm
new file mode 100644
index 0000000000000000000000000000000000000000..2ce43f3fb0b5407f8835f63a2c7c906871ece200
--- /dev/null
+++ b/lib/Vs.pm
@@ -0,0 +1,8 @@
+package Vs;
+
+# These need to be updated as The Sleuth Kit supports more volume systems
+$Vs::type{'dos'} = 1;
+$Vs::type{'bsd'} = 1;
+$Vs::type{'gpt'} = 1;
+$Vs::type{'mac'} = 1;
+$Vs::type{'sun'} = 1;
diff --git a/lib/define.pl b/lib/define.pl
new file mode 100644
index 0000000000000000000000000000000000000000..9bce1fa80507702ff2e9f6fbdb280e8e4e3fb478
--- /dev/null
+++ b/lib/define.pl
@@ -0,0 +1,39 @@
+#
+$VER = '2.24';
+
+$HTTP_NL    = "\x0a";
+$notes_file = "";
+
+$PICTDIR       = "$INSTALLDIR/pict/";
+$SANITIZE_TAG  = 'AutopsySanitized';
+$SANITIZE_PICT = 'sanitized.jpg';
+
+$PROGNAME = 'autopsy';
+
+# Default directory names
+$MKDIR_MASK = 0775;
+$IMGDIR     = 'images';
+$DATADIR    = 'output';
+$LOGDIR     = 'logs';
+$REPDIR     = 'reports';
+
+# Colors
+$BACK_COLOR       = "#CCCC99";
+$BACK_COLOR_TABLE = "#CCCCCC";
+$DEL_COLOR[0]     = "red";
+$DEL_COLOR[1] = "#800000";  # used when meta data structure has been reallocated
+$NORM_COLOR   = "";
+$LINK_COLOR   = "blue";
+
+$YEL_PIX = "pict/back_pix.jpg";
+
+%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
+);
+@d2m = (
+    "",    "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
+    "Aug", "Sep", "Oct", "Nov", "Dec"
+);
+
+1;
diff --git a/lib/search.pl b/lib/search.pl
new file mode 100644
index 0000000000000000000000000000000000000000..4ea1b363d1a72de1e2377d4f535302569ceb08f8
--- /dev/null
+++ b/lib/search.pl
@@ -0,0 +1,51 @@
+#
+# This file contains pre-defined search strings.  A button for each will
+# be displayed in the Search Mode.
+#
+# The $auto_srch{} hash is filled in with the search string
+# The index into the hash is the name of the search.
+#
+# For example, $auto_srch{'foo'} = "bar"; would search for the string
+# bar
+#
+# If the search is case sensitive, then set $auto_srch_csense to 1 (this
+# is the default value if not specified.  Set to 0 for insensitive
+#
+# If the search is a regular expression, set $auto_srch_reg to 1, else
+# 0 (the default)
+#
+#
+# If you develop patterns that you think will be useful to others, email
+# them to me and I will include them in the next version (carrier@sleuthkit.org)
+#
+
+# Date / syslog search of month and date
+$auto_srch{'Date'} =
+"((jan)|(feb)|(mar)|(apr)|(may)|(june?)|(july?)|(aug)|(sept?)|(oct)|(nov)|(dec))([[:space:]]+[[:digit:]])?";
+$auto_srch_reg{'Date'}    = 1;
+$auto_srch_csense{'Date'} = 0;
+
+# IP Address
+$auto_srch{'IP'} =
+'[0-2]?[[:digit:]]{1,2}\.[0-2]?[[:digit:]]{1,2}\.[0-2]?[[:digit:]]{1,2}\.[0-2]?[[:digit:]]{1,2}';
+$auto_srch_reg{'IP'}    = 1;
+$auto_srch_csense{'IP'} = 0;
+
+# SSN in the pattern of 123-12-1234 - from Jerry Shenk
+$auto_srch{'SSN1'}        = '[0-9][0-9][0-9]\-[0-9]]0-9]\-[0-9][0-9][0-9][0-9]';
+$auto_srch_reg{'SSN1'}    = 1;
+$auto_srch_csense{'SSN1'} = 0;
+
+# SSN in the pattern of 123121234 - from Jerry Shenk
+$auto_srch{'SSN2'}        = '[0-9][0-9][0-9][0-9]]0-9][0-9][0-9][0-9][0-9]';
+$auto_srch_reg{'SSN2'}    = 1;
+$auto_srch_csense{'SSN2'} = 0;
+
+# CC # - from Jerry Shenk
+$auto_srch{'CC'} =
+  '[0-9][0-9][0-9][0-9]]0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]]0-9]';
+$auto_srch_reg{'CC'}    = 1;
+$auto_srch_csense{'CC'} = 0;
+
+# This must be the last value
+1;
diff --git a/man/man1/autopsy.1 b/man/man1/autopsy.1
new file mode 100755
index 0000000000000000000000000000000000000000..39f983d6a7e7367c1e09b0e4483d8dd18fc8a7ff
--- /dev/null
+++ b/man/man1/autopsy.1
@@ -0,0 +1,163 @@
+.TH AUTOPSY 1 "MAR 2005" "User Manuals"
+.SH NAME
+autopsy \- Autopsy Forensic Browser
+.SH SYNOPSIS
+.B autopsy [-c] [-C] [-d
+.I evid_locker
+.B ] [-i 
+device filesystem mnt
+.B ] [-p
+.I port
+.B ]
+.I [addr]
+.SH DESCRIPTION
+By default, 
+.B autopsy
+starts the Autopsy Forensic Browser server on port 9999 and and accepts 
+connections from the localhost.  If 
+.I -p port
+is given, then the server opens on that port and if 
+.I addr
+is given, then connections are only accepted from that host.
+When the 
+.I -i
+argument is given, then autopsy goes into live analysis mode.
+
+The arguments are as follows:
+.IP "-c"
+Force the program to use cookies even for localhost.
+.IP "-C"
+Force the program to not use cookies even for remote hosts.
+.IP "-d evid_locker"
+Directory where cases and hosts are stored.
+This overrides the 
+.B LOCKDIR 
+value in 
+.I conf.pl.
+The path must be a full path (i.e. start with /).
+.IP "-i device filesystem mnt"
+Specify the information for the live analysis mode.  This can be specified
+as many times as needed.  The 
+.I device
+field is for the raw file system device, the 
+.I filesystem
+field is for the file system type, and the
+.I mnt
+field is for the mounting point of the file system.  
+.IP "-p port"
+TCP port for server to listen on.
+.IP addr
+IP address or host name of where investigator is located.  
+If localhost is used, then 'localhost' must be used in the URL.
+If you use the actual hostname or IP, it will be rejected.
+.PP
+When started, the program will display a URL to paste into an
+HTML browser.  The browser must support frames and forms.   The
+Autopsy Forensic Browser will allow an investigator to analyze
+images generated by
+.BR dd(1)
+for evidence.  The program allows the images to be analyzed by
+browsing files, blocks, inodes, or by searching the blocks.
+The program also generates Autopsy reports that include collection
+time, investigators name, and MD5 hash values.
+.SH VARIABLES
+The following variables can be set in 
+.I conf.pl. 
+
+.I USE_STIMEOUT
+.RS 
+When set to 1 (default is 0), the server will exit after 
+.B STIMEOUT
+seconds of inactivity (default is 3600).  This setting is recommended if 
+cookies are not used.
+.RE
+.I BASEDIR
+.RS 
+Directory where cases and forensic images are located.  
+The images must have simple
+names with only letters, numbers, '_', '-', and '.'.  (See FILES).
+.RE
+.I TSKDIR
+.RS
+Directory where The Sleuth Kit binaries are located.
+.RE
+.I NSRLDB
+.RS
+Location of the NIST National Software Reference Library (NSRL).
+.RE
+.I INSTALLDIR
+.RS 
+Directory where Autopsy was installed.
+.RE
+.I GREP_EXE
+.RS
+Location of 
+.BR grep(1)
+binary.
+.RE
+.I STRINGS_EXE
+.RS
+Location of 
+.BR strings(1)
+binary.
+.RE
+.SH FILES
+.I Evidence Locker
+.RS
+The Evidence Locker is where all cases and hosts will be saved to.  It
+is a directory that will have a directory for each case.  Each case
+directory will have a directory for each host.  
+
+.RE
+.I <CASE_DIR>/case.aut
+.RS
+This file is the case configuration file for the case.  It contains the
+description of the case and default subdirectories for the hosts.  
+
+.RE
+.I <CASE_DIR>/investigators.txt
+.RS
+This file contains the list of investigators that will use this case.  These
+are used for logging only, not authentication.  
+
+.RE
+.I <HOST_DIR>/host.aut
+.RS
+This file is where the host configuration details are saved.  It
+is similar to the 'fsmorgue' file from previous versions of Autopsy.
+It has an entry for each file in the host and contains the host
+description.
+
+
+.RE
+.I md5.txt
+.RS
+Some directories will have this file in it.  It contains MD5 values for 
+important files in the directory.  This makes it easy to validate the
+integrity of images.  
+
+.SH EXAMPLE
+# ./autopsy -p 8888 10.1.34.19
+.SH "SEE ALSO"
+.BR dd (1),
+.BR fls (1),
+.BR ffind (1),
+.BR ifind (1),
+.BR grep (1),
+.BR icat (1)
+.BR md5 (1),
+.BR strings (1),
+.SH REQUIREMENTS
+The Autopsy Forensic Browser requires
+.B The Sleuth Kit 
+<www.sleuthkit.org/sleuthkit>
+
+.SH HISTORY
+.BR "autopsy" " first appeared in " "Autopsy" " v1.0."
+.SH LICENSE
+This software is distributed under the GNU Public License.
+
+.SH AUTHOR
+Brian Carrier <carrier at sleuthkit dot org>
+
+Send documentation updates to <doc-updates at sleuthkit dot org>
diff --git a/pict/back_pix.jpg b/pict/back_pix.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..1a5da64c9bda1ad2cec4418a7c7b055b97e2f7da
Binary files /dev/null and b/pict/back_pix.jpg differ
diff --git a/pict/but_addnote.jpg b/pict/but_addnote.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..0946f296f4a91ab4ea595689ccd02031f38c1b15
Binary files /dev/null and b/pict/but_addnote.jpg differ
diff --git a/pict/but_alloc_list.jpg b/pict/but_alloc_list.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..525fd081f3ff28dd75136354110695c71f43986d
Binary files /dev/null and b/pict/but_alloc_list.jpg differ
diff --git a/pict/but_export.jpg b/pict/but_export.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..4cbc75a024be2c929a5f8acdad048169b7d2573c
Binary files /dev/null and b/pict/but_export.jpg differ
diff --git a/pict/but_force.jpg b/pict/but_force.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..2a92475c71feecd87e414c36c993dba5eaea0966
Binary files /dev/null and b/pict/but_force.jpg differ
diff --git a/pict/but_indexdb.jpg b/pict/but_indexdb.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5e51b780546e75ec6d474bdeec4f29dd7e5b6b47
Binary files /dev/null and b/pict/but_indexdb.jpg differ
diff --git a/pict/but_lookup.jpg b/pict/but_lookup.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..b6bd6daf9fb7701f56d040a09e485e7246a13deb
Binary files /dev/null and b/pict/but_lookup.jpg differ
diff --git a/pict/but_new_name.jpg b/pict/but_new_name.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5a24bb42ea857421da071bb977e95469751b65a2
Binary files /dev/null and b/pict/but_new_name.jpg differ
diff --git a/pict/but_next.jpg b/pict/but_next.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..c5639baeb50091ab6043b3d8a97d66125f3f8468
Binary files /dev/null and b/pict/but_next.jpg differ
diff --git a/pict/but_ok.jpg b/pict/but_ok.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..3bb2996fa2f3ccd958b8f3ccdbf788406799b6ef
Binary files /dev/null and b/pict/but_ok.jpg differ
diff --git a/pict/but_prev.jpg b/pict/but_prev.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..46c4f397005d169866102814cac08802f19acc4c
Binary files /dev/null and b/pict/but_prev.jpg differ
diff --git a/pict/but_replace.jpg b/pict/but_replace.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..0c17557a59ec5367fe5e1970346c8b71060b3fcd
Binary files /dev/null and b/pict/but_replace.jpg differ
diff --git a/pict/but_report.jpg b/pict/but_report.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e283c36212ec407630b1956482b898960f305bf3
Binary files /dev/null and b/pict/but_report.jpg differ
diff --git a/pict/but_search.jpg b/pict/but_search.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ed5287e349e2f92564d49534908f4bdde0799155
Binary files /dev/null and b/pict/but_search.jpg differ
diff --git a/pict/but_view.jpg b/pict/but_view.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..90a0ae9b60482d54a3956a2f8fd60039dadcfd3a
Binary files /dev/null and b/pict/but_view.jpg differ
diff --git a/pict/but_viewcont.jpg b/pict/but_viewcont.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..76f58842eee5c730cac18badbefdcf86db88006a
Binary files /dev/null and b/pict/but_viewcont.jpg differ
diff --git a/pict/favicon.ico b/pict/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..0a4ba44527995af4c14f35423c64ff52c518e87c
Binary files /dev/null and b/pict/favicon.ico differ
diff --git a/pict/file_b_alldel.jpg b/pict/file_b_alldel.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e82f225dddcf276465c90e7be790bbeddf72efea
Binary files /dev/null and b/pict/file_b_alldel.jpg differ
diff --git a/pict/file_b_allfiles.jpg b/pict/file_b_allfiles.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ac88e0c2711fa690c927cca15e5fd590018bca98
Binary files /dev/null and b/pict/file_b_allfiles.jpg differ
diff --git a/pict/file_b_check.jpg b/pict/file_b_check.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..68049e674a4b13538ad1e65aa330177c31571ef3
Binary files /dev/null and b/pict/file_b_check.jpg differ
diff --git a/pict/file_b_expand.jpg b/pict/file_b_expand.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..86b720efa5126dae8d836e156b9cfa4f92a87626
Binary files /dev/null and b/pict/file_b_expand.jpg differ
diff --git a/pict/file_b_hide.jpg b/pict/file_b_hide.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5689c05b18cb36ce96a771a697cde40c99d137b7
Binary files /dev/null and b/pict/file_b_hide.jpg differ
diff --git a/pict/file_b_md5list.jpg b/pict/file_b_md5list.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..9dac25518acf9deaa84115d9156f7e9b62f0dc34
Binary files /dev/null and b/pict/file_b_md5list.jpg differ
diff --git a/pict/file_h_acc_cur.jpg b/pict/file_h_acc_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8907e17b7b98daaf1e579501ba8d72243b0a4888
Binary files /dev/null and b/pict/file_h_acc_cur.jpg differ
diff --git a/pict/file_h_acc_link.jpg b/pict/file_h_acc_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..50d9ca2a3289308e6919988c79a3095015aa6342
Binary files /dev/null and b/pict/file_h_acc_link.jpg differ
diff --git a/pict/file_h_chg_cur.jpg b/pict/file_h_chg_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..0f987ce883e1a3c8714efb32b5eaf8452c551064
Binary files /dev/null and b/pict/file_h_chg_cur.jpg differ
diff --git a/pict/file_h_chg_link.jpg b/pict/file_h_chg_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8dab273e0c039b89bd1c208f1f0890337d4913ec
Binary files /dev/null and b/pict/file_h_chg_link.jpg differ
diff --git a/pict/file_h_cre_cur.jpg b/pict/file_h_cre_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..0df3fc9a0e82d51b3fe13e458784b6fe6a05471a
Binary files /dev/null and b/pict/file_h_cre_cur.jpg differ
diff --git a/pict/file_h_cre_link.jpg b/pict/file_h_cre_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..3861f661ef4ae1cb86f947ee51cf0107434f26d0
Binary files /dev/null and b/pict/file_h_cre_link.jpg differ
diff --git a/pict/file_h_del_cur.jpg b/pict/file_h_del_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..38a713b9ab044ac68e3479d4a1acbeef7d355cf5
Binary files /dev/null and b/pict/file_h_del_cur.jpg differ
diff --git a/pict/file_h_del_link.jpg b/pict/file_h_del_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..253db16e8c571653a3bf19303e99d324defedf21
Binary files /dev/null and b/pict/file_h_del_link.jpg differ
diff --git a/pict/file_h_gid_cur.jpg b/pict/file_h_gid_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e775b344bdb256afb445770a8a9314b1a48a64f6
Binary files /dev/null and b/pict/file_h_gid_cur.jpg differ
diff --git a/pict/file_h_gid_link.jpg b/pict/file_h_gid_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..38833628098e304ee60396383c984734bf865f40
Binary files /dev/null and b/pict/file_h_gid_link.jpg differ
diff --git a/pict/file_h_meta_cur.jpg b/pict/file_h_meta_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..62d64d95d7831aaea0fad1291bb29737c1ea4f14
Binary files /dev/null and b/pict/file_h_meta_cur.jpg differ
diff --git a/pict/file_h_meta_link.jpg b/pict/file_h_meta_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..d691cfe2731222df8d204212276ac7cae98276a9
Binary files /dev/null and b/pict/file_h_meta_link.jpg differ
diff --git a/pict/file_h_mod_cur.jpg b/pict/file_h_mod_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..f08924e959bceefca05ed73511f9af94e2dd61b0
Binary files /dev/null and b/pict/file_h_mod_cur.jpg differ
diff --git a/pict/file_h_mod_link.jpg b/pict/file_h_mod_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a6e7aabfe996bb10897e621c3354b58efa16e47d
Binary files /dev/null and b/pict/file_h_mod_link.jpg differ
diff --git a/pict/file_h_nam_cur.jpg b/pict/file_h_nam_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..19c3d43d6307aec2b3699edeec4a9e931e684b72
Binary files /dev/null and b/pict/file_h_nam_cur.jpg differ
diff --git a/pict/file_h_nam_link.jpg b/pict/file_h_nam_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..76c9de71e733b887e1b59b6a37c53e08cb10ed3b
Binary files /dev/null and b/pict/file_h_nam_link.jpg differ
diff --git a/pict/file_h_siz_cur.jpg b/pict/file_h_siz_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..17b4fadaa92f3c5446bede9d16079305d0d9c400
Binary files /dev/null and b/pict/file_h_siz_cur.jpg differ
diff --git a/pict/file_h_siz_link.jpg b/pict/file_h_siz_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..27527d69a2d58581d11f25c57d1bc702cf13730d
Binary files /dev/null and b/pict/file_h_siz_link.jpg differ
diff --git a/pict/file_h_uid_cur.jpg b/pict/file_h_uid_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..fa1d27ea3187815a95bf7cbdf5203a6098d46cb2
Binary files /dev/null and b/pict/file_h_uid_cur.jpg differ
diff --git a/pict/file_h_uid_link.jpg b/pict/file_h_uid_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..29bab9c18fab59b73c9f4d91010c91cc552aba61
Binary files /dev/null and b/pict/file_h_uid_link.jpg differ
diff --git a/pict/file_h_wr_cur.jpg b/pict/file_h_wr_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..bd9d380ed717fe727c1f550d0058f1c2ea5631b4
Binary files /dev/null and b/pict/file_h_wr_cur.jpg differ
diff --git a/pict/file_h_wr_link.jpg b/pict/file_h_wr_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..709726d663f642f0a364aaea76b3c3fe44b7e3c5
Binary files /dev/null and b/pict/file_h_wr_link.jpg differ
diff --git a/pict/hashdb_h_alert.jpg b/pict/hashdb_h_alert.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..55301aacd7eadcded069585668d40a3474c405dc
Binary files /dev/null and b/pict/hashdb_h_alert.jpg differ
diff --git a/pict/hashdb_h_ig.jpg b/pict/hashdb_h_ig.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..edf80bbadc96f8b137c461a99b05dbf7beda2f34
Binary files /dev/null and b/pict/hashdb_h_ig.jpg differ
diff --git a/pict/hashdb_h_nsrl.jpg b/pict/hashdb_h_nsrl.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..b333af90c19ac2f680246ead9725025d5702aba7
Binary files /dev/null and b/pict/hashdb_h_nsrl.jpg differ
diff --git a/pict/int_b_calc.jpg b/pict/int_b_calc.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..db33eca6ba0396288096a5e37e5b3e872402cb17
Binary files /dev/null and b/pict/int_b_calc.jpg differ
diff --git a/pict/int_b_valid.jpg b/pict/int_b_valid.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..aee869b6e65f18e68ede4ce08d69eafd8548e593
Binary files /dev/null and b/pict/int_b_valid.jpg differ
diff --git a/pict/int_h_data.jpg b/pict/int_h_data.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..cf69f3704e4de9f5ba945e4958b33a99463d0271
Binary files /dev/null and b/pict/int_h_data.jpg differ
diff --git a/pict/int_h_img.jpg b/pict/int_h_img.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a22cf45eee60064970f62bbb0512f933eedb798c
Binary files /dev/null and b/pict/int_h_img.jpg differ
diff --git a/pict/int_h_str.jpg b/pict/int_h_str.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..f8b3e8e75183f672994acad1851bcfe21059d957
Binary files /dev/null and b/pict/int_h_str.jpg differ
diff --git a/pict/int_h_tl.jpg b/pict/int_h_tl.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..d1afeed84e02ea11d23704a72ee1c23213c89cb5
Binary files /dev/null and b/pict/int_h_tl.jpg differ
diff --git a/pict/int_h_unalloc.jpg b/pict/int_h_unalloc.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ce7fa58139f09bb12d104c9715a5232e7653aa1e
Binary files /dev/null and b/pict/int_h_unalloc.jpg differ
diff --git a/pict/logo.jpg b/pict/logo.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..0d9c29c3826757ccb30110bebf418ddc79121a3c
Binary files /dev/null and b/pict/logo.jpg differ
diff --git a/pict/main_t_dat_cur.jpg b/pict/main_t_dat_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..02bf5442e84a7dec1a0f90f16c75a33c9490666a
Binary files /dev/null and b/pict/main_t_dat_cur.jpg differ
diff --git a/pict/main_t_dat_link.jpg b/pict/main_t_dat_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e40990093dfef4c2c9591bc360abf67f1a7a91d0
Binary files /dev/null and b/pict/main_t_dat_link.jpg differ
diff --git a/pict/main_t_fil_cur.jpg b/pict/main_t_fil_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..91a4a83e20501b946b05609807e09d7e5908d2be
Binary files /dev/null and b/pict/main_t_fil_cur.jpg differ
diff --git a/pict/main_t_fil_link.jpg b/pict/main_t_fil_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..82b814c7d6cca4dfbc31853f308104f9506c733c
Binary files /dev/null and b/pict/main_t_fil_link.jpg differ
diff --git a/pict/main_t_fil_org.jpg b/pict/main_t_fil_org.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..150bdb49620d650abb431975e7a90b6de2d89f4c
Binary files /dev/null and b/pict/main_t_fil_org.jpg differ
diff --git a/pict/main_t_ftype_cur.jpg b/pict/main_t_ftype_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..c72918d7f8ec4f6cdc160c79efc6720535976adc
Binary files /dev/null and b/pict/main_t_ftype_cur.jpg differ
diff --git a/pict/main_t_ftype_link.jpg b/pict/main_t_ftype_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..9161ec5fdc1ea495905da6173620490adf293c13
Binary files /dev/null and b/pict/main_t_ftype_link.jpg differ
diff --git a/pict/main_t_ftype_org.jpg b/pict/main_t_ftype_org.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..801c1b075a92baeae0b4e1c39f1cd43d09c7ddc2
Binary files /dev/null and b/pict/main_t_ftype_org.jpg differ
diff --git a/pict/main_t_img_cur.jpg b/pict/main_t_img_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5de656e4a65246e1acc8983fa96cc3ff01b100f4
Binary files /dev/null and b/pict/main_t_img_cur.jpg differ
diff --git a/pict/main_t_img_link.jpg b/pict/main_t_img_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..51c1654dfb95cffed252a2ecfdb1937713f13c62
Binary files /dev/null and b/pict/main_t_img_link.jpg differ
diff --git a/pict/main_t_img_org.jpg b/pict/main_t_img_org.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..bdc0d2935524e5896b803c1a4bc4c788dc86f2d3
Binary files /dev/null and b/pict/main_t_img_org.jpg differ
diff --git a/pict/main_t_met_cur.jpg b/pict/main_t_met_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..64016bdeca984d722a58c4321800da4a43b1907b
Binary files /dev/null and b/pict/main_t_met_cur.jpg differ
diff --git a/pict/main_t_met_link.jpg b/pict/main_t_met_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..cfe4494153ffe652e09299998e4cab5dd2aadb87
Binary files /dev/null and b/pict/main_t_met_link.jpg differ
diff --git a/pict/main_t_met_org.jpg b/pict/main_t_met_org.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e5c014064d8e9c2bc1ced606167c1fa897eaecfa
Binary files /dev/null and b/pict/main_t_met_org.jpg differ
diff --git a/pict/main_t_srch_cur.jpg b/pict/main_t_srch_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..9b99415c84b83ea6f473c103c520fa01cee888ae
Binary files /dev/null and b/pict/main_t_srch_cur.jpg differ
diff --git a/pict/main_t_srch_link.jpg b/pict/main_t_srch_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8087c4a48bb9a39e1b063f4bca601a0657ad0645
Binary files /dev/null and b/pict/main_t_srch_link.jpg differ
diff --git a/pict/menu_b_add.jpg b/pict/menu_b_add.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..9a50a3c0b18105b65b81bd13c62faf37aa0b9288
Binary files /dev/null and b/pict/menu_b_add.jpg differ
diff --git a/pict/menu_b_analyze.jpg b/pict/menu_b_analyze.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ab8cad740061be354bf0a27cae798a6e5ec391ef
Binary files /dev/null and b/pict/menu_b_analyze.jpg differ
diff --git a/pict/menu_b_back.jpg b/pict/menu_b_back.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..d42433316343b73e8ca5aa4ee1b72df7e3ab1e19
Binary files /dev/null and b/pict/menu_b_back.jpg differ
diff --git a/pict/menu_b_cancel.jpg b/pict/menu_b_cancel.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..1e0de235f772b19076b3f91d97df469dc27bf0bb
Binary files /dev/null and b/pict/menu_b_cancel.jpg differ
diff --git a/pict/menu_b_ccls.jpg b/pict/menu_b_ccls.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..879bcd53726cc6576bf795afe1c6833401373bbf
Binary files /dev/null and b/pict/menu_b_ccls.jpg differ
diff --git a/pict/menu_b_close.jpg b/pict/menu_b_close.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ebed7dd19b09858c175852c608d8dcaa91c64ffd
Binary files /dev/null and b/pict/menu_b_close.jpg differ
diff --git a/pict/menu_b_cnew.jpg b/pict/menu_b_cnew.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..f4fbf24758bef9998596578ee224b2aed0f9706c
Binary files /dev/null and b/pict/menu_b_cnew.jpg differ
diff --git a/pict/menu_b_copen.jpg b/pict/menu_b_copen.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..4df3f4771bf4fc551bae6e2934db4bd4cd8ee28d
Binary files /dev/null and b/pict/menu_b_copen.jpg differ
diff --git a/pict/menu_b_fs.jpg b/pict/menu_b_fs.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..32bcd63ceedf6b8005cc8deaafcb423e9cc9bf07
Binary files /dev/null and b/pict/menu_b_fs.jpg differ
diff --git a/pict/menu_b_hashdb.jpg b/pict/menu_b_hashdb.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ffd2a995d08009e54a563bcbe782d6505aa7ffa8
Binary files /dev/null and b/pict/menu_b_hashdb.jpg differ
diff --git a/pict/menu_b_hcls.jpg b/pict/menu_b_hcls.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..6ef9ec634ab402ed689051374a6f6121ce25de60
Binary files /dev/null and b/pict/menu_b_hcls.jpg differ
diff --git a/pict/menu_b_help.jpg b/pict/menu_b_help.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..6a0d06591a801fbc9f0377b36d66c0938125353d
Binary files /dev/null and b/pict/menu_b_help.jpg differ
diff --git a/pict/menu_b_hnew.jpg b/pict/menu_b_hnew.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8cf2e8c5ab3ed2176e60049c7f46871968647629
Binary files /dev/null and b/pict/menu_b_hnew.jpg differ
diff --git a/pict/menu_b_ifnew.jpg b/pict/menu_b_ifnew.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ec8355f99bf052a53827ac0f6e2763d5b1d16d72
Binary files /dev/null and b/pict/menu_b_ifnew.jpg differ
diff --git a/pict/menu_b_inew.jpg b/pict/menu_b_inew.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8f990e32d8fd0872762f97fe119da665ab44383e
Binary files /dev/null and b/pict/menu_b_inew.jpg differ
diff --git a/pict/menu_b_int.jpg b/pict/menu_b_int.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5fc0af25213a370f00e24004df8ca07d75d56b0b
Binary files /dev/null and b/pict/menu_b_int.jpg differ
diff --git a/pict/menu_b_menu.jpg b/pict/menu_b_menu.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..124a7e098032178d7696048a7a798b9d11a29c06
Binary files /dev/null and b/pict/menu_b_menu.jpg differ
diff --git a/pict/menu_b_next.jpg b/pict/menu_b_next.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..c1f2c254ff6ec2b1e6644fd7264e4e4ad77ca42e
Binary files /dev/null and b/pict/menu_b_next.jpg differ
diff --git a/pict/menu_b_note.jpg b/pict/menu_b_note.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..eeea7bb1012d71b132c88b9d0fd09f8622cc4068
Binary files /dev/null and b/pict/menu_b_note.jpg differ
diff --git a/pict/menu_b_ok.jpg b/pict/menu_b_ok.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e682233fb41bf3932041dbbbfcb97a2ea281ad1f
Binary files /dev/null and b/pict/menu_b_ok.jpg differ
diff --git a/pict/menu_b_ref.jpg b/pict/menu_b_ref.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a7a4329df9430703aad90c5cabcc77823a6b2326
Binary files /dev/null and b/pict/menu_b_ref.jpg differ
diff --git a/pict/menu_b_rem.jpg b/pict/menu_b_rem.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..0a6f73498d1ad3ba02768b161fdda1a745dfe29c
Binary files /dev/null and b/pict/menu_b_rem.jpg differ
diff --git a/pict/menu_b_seq.jpg b/pict/menu_b_seq.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..d903d25a19d24bd2b2718e4fea2d0ba775c31593
Binary files /dev/null and b/pict/menu_b_seq.jpg differ
diff --git a/pict/menu_b_tl.jpg b/pict/menu_b_tl.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..212be616c47567848cfbdabfbcc6990b05874173
Binary files /dev/null and b/pict/menu_b_tl.jpg differ
diff --git a/pict/menu_h_cdet.jpg b/pict/menu_h_cdet.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..b9bcfa77e405814fabfb2ade971b6ed41d024d0f
Binary files /dev/null and b/pict/menu_h_cdet.jpg differ
diff --git a/pict/menu_h_cnew.jpg b/pict/menu_h_cnew.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..9488016824ea0d4f837dbf2e670dc77a1f833bf9
Binary files /dev/null and b/pict/menu_h_cnew.jpg differ
diff --git a/pict/menu_h_hdet.jpg b/pict/menu_h_hdet.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..55d96bb1cee2a6b6bdd3eca8b9d45eb1489522e6
Binary files /dev/null and b/pict/menu_h_hdet.jpg differ
diff --git a/pict/menu_h_hnew.jpg b/pict/menu_h_hnew.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a0293ccd5c62ecc4c48d6238adcb2c631f2e25a9
Binary files /dev/null and b/pict/menu_h_hnew.jpg differ
diff --git a/pict/menu_h_idet.jpg b/pict/menu_h_idet.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..dff892fa72ddb121eaf8c230ad3fc93109c6dfa3
Binary files /dev/null and b/pict/menu_h_idet.jpg differ
diff --git a/pict/menu_h_inew.jpg b/pict/menu_h_inew.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..1671f20cc442b7d4298de592b52262ba5bd13839
Binary files /dev/null and b/pict/menu_h_inew.jpg differ
diff --git a/pict/menu_t_cg_cur.jpg b/pict/menu_t_cg_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..4ace65321d056d8e3adc9e976c57627de4d29d79
Binary files /dev/null and b/pict/menu_t_cg_cur.jpg differ
diff --git a/pict/menu_t_cg_link.jpg b/pict/menu_t_cg_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..4f758b5cdd58d519f0ef017a70f068c6b6018f39
Binary files /dev/null and b/pict/menu_t_cg_link.jpg differ
diff --git a/pict/menu_t_cg_org.jpg b/pict/menu_t_cg_org.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..152db199670b79cb3b70a533c27f0d74a1973628
Binary files /dev/null and b/pict/menu_t_cg_org.jpg differ
diff --git a/pict/menu_t_hg_cur.jpg b/pict/menu_t_hg_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..72cb1fbacd8a0a8f1f76c66ee66ae857d9f0e470
Binary files /dev/null and b/pict/menu_t_hg_cur.jpg differ
diff --git a/pict/menu_t_hg_link.jpg b/pict/menu_t_hg_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..97f79c8f3e9711cab83fd9f94c45c1f01d743016
Binary files /dev/null and b/pict/menu_t_hg_link.jpg differ
diff --git a/pict/menu_t_hg_org.jpg b/pict/menu_t_hg_org.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..37f4b110451a7a88bc2f464f6aaa79aa2714a2b2
Binary files /dev/null and b/pict/menu_t_hg_org.jpg differ
diff --git a/pict/menu_t_hm_cur.jpg b/pict/menu_t_hm_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..67a9ee4699f6a9990705b25459aafca434c20e85
Binary files /dev/null and b/pict/menu_t_hm_cur.jpg differ
diff --git a/pict/menu_t_hm_link.jpg b/pict/menu_t_hm_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..4e17433ea435378aeb2828ad57d7922fd714a995
Binary files /dev/null and b/pict/menu_t_hm_link.jpg differ
diff --git a/pict/menu_t_hm_org.jpg b/pict/menu_t_hm_org.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5fb204ae57489b7bd2e863b671f7c5cf5bb4d913
Binary files /dev/null and b/pict/menu_t_hm_org.jpg differ
diff --git a/pict/sanit_b_norm.jpg b/pict/sanit_b_norm.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..2a86e0e6ae06c8077435a206fc313c4bc98f3cec
Binary files /dev/null and b/pict/sanit_b_norm.jpg differ
diff --git a/pict/sanit_b_san.jpg b/pict/sanit_b_san.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..601b8d67c04ef93b1649be0b0bc2451cd64e9e9e
Binary files /dev/null and b/pict/sanit_b_san.jpg differ
diff --git a/pict/sanitized.jpg b/pict/sanitized.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..bec0da750b1534fe54a516f8d0e25c13481879aa
Binary files /dev/null and b/pict/sanitized.jpg differ
diff --git a/pict/srch_b_lorig.jpg b/pict/srch_b_lorig.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..01354eec4e47d6e7396dddbdce76a355eb908cf0
Binary files /dev/null and b/pict/srch_b_lorig.jpg differ
diff --git a/pict/srch_b_lun.jpg b/pict/srch_b_lun.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8a2d2b720e6ecd7a8e1ff14d8e2ad1cb15328b3d
Binary files /dev/null and b/pict/srch_b_lun.jpg differ
diff --git a/pict/srch_b_str.jpg b/pict/srch_b_str.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..9d9371452a5001e11945c3cfc67f0fa209d8eb93
Binary files /dev/null and b/pict/srch_b_str.jpg differ
diff --git a/pict/srch_b_un.jpg b/pict/srch_b_un.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e1a4b4d2da8b8d38d84f163fd8d406711676cca9
Binary files /dev/null and b/pict/srch_b_un.jpg differ
diff --git a/pict/tab_close.jpg b/pict/tab_close.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..0a63dd24ba231299168472dea3524db52727b4f1
Binary files /dev/null and b/pict/tab_close.jpg differ
diff --git a/pict/tab_help.jpg b/pict/tab_help.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..632e27006b00f6a18c51e5b20f31ed9dede5de0a
Binary files /dev/null and b/pict/tab_help.jpg differ
diff --git a/pict/tl_t_data_cur.jpg b/pict/tl_t_data_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..d9d9b10638a30653b203b5f99107d915ca007465
Binary files /dev/null and b/pict/tl_t_data_cur.jpg differ
diff --git a/pict/tl_t_data_link.jpg b/pict/tl_t_data_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..fe8333bf274b8acf0ad68cea2502698ad53dabcf
Binary files /dev/null and b/pict/tl_t_data_link.jpg differ
diff --git a/pict/tl_t_notes_link.jpg b/pict/tl_t_notes_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..fe01d8c05554a886039c72e519a95283e67279e8
Binary files /dev/null and b/pict/tl_t_notes_link.jpg differ
diff --git a/pict/tl_t_notes_org.jpg b/pict/tl_t_notes_org.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..03c643b84cc6f49571ff4f2219c4107ce28e2c45
Binary files /dev/null and b/pict/tl_t_notes_org.jpg differ
diff --git a/pict/tl_t_tl_cur.jpg b/pict/tl_t_tl_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ed69d8bb2511b86e499b460d817bbddf9844a8d4
Binary files /dev/null and b/pict/tl_t_tl_cur.jpg differ
diff --git a/pict/tl_t_tl_link.jpg b/pict/tl_t_tl_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..1da8edd58df6f0a30a0377d819670d82303ab23f
Binary files /dev/null and b/pict/tl_t_tl_link.jpg differ
diff --git a/pict/tl_t_view_cur.jpg b/pict/tl_t_view_cur.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..b621d7d857b3e437f9b7da200f40138522aef2c4
Binary files /dev/null and b/pict/tl_t_view_cur.jpg differ
diff --git a/pict/tl_t_view_link.jpg b/pict/tl_t_view_link.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..94016071364e8948b80a50593f21f3e89fbd822e
Binary files /dev/null and b/pict/tl_t_view_link.jpg differ
diff --git a/xcode/autopsy.xcodeproj/project.pbxproj b/xcode/autopsy.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000000000000000000000000000000000..f04caa4f2f1d6538933554471790f516a69dae43
--- /dev/null
+++ b/xcode/autopsy.xcodeproj/project.pbxproj
@@ -0,0 +1,138 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 42;
+	objects = {
+
+/* Begin PBXFileReference section */
+		02B041C40E9070E400E46A87 /* .perltidyrc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = .perltidyrc; sourceTree = "<group>"; };
+		02B041C50E9070E400E46A87 /* Appsort.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Appsort.pm; sourceTree = "<group>"; };
+		02B041C60E9070E400E46A87 /* Appview.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Appview.pm; sourceTree = "<group>"; };
+		02B041C70E9070E400E46A87 /* Args.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Args.pm; sourceTree = "<group>"; };
+		02B041C80E9070E400E46A87 /* Caseman.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Caseman.pm; sourceTree = "<group>"; };
+		02B041C90E9070E400E46A87 /* Data.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Data.pm; sourceTree = "<group>"; };
+		02B041CA0E9070E400E46A87 /* define.pl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = define.pl; sourceTree = "<group>"; };
+		02B041CB0E9070E400E46A87 /* Exec.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Exec.pm; sourceTree = "<group>"; };
+		02B041CC0E9070E400E46A87 /* File.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = File.pm; sourceTree = "<group>"; };
+		02B041CD0E9070E400E46A87 /* Filesystem.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Filesystem.pm; sourceTree = "<group>"; };
+		02B041CE0E9070E400E46A87 /* Frame.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Frame.pm; sourceTree = "<group>"; };
+		02B041CF0E9070E400E46A87 /* Fs.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Fs.pm; sourceTree = "<group>"; };
+		02B041D00E9070E400E46A87 /* Hash.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Hash.pm; sourceTree = "<group>"; };
+		02B041D10E9070E400E46A87 /* Kwsrch.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Kwsrch.pm; sourceTree = "<group>"; };
+		02B041D20E9070E400E46A87 /* Main.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Main.pm; sourceTree = "<group>"; };
+		02B041D30E9070E400E46A87 /* Meta.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Meta.pm; sourceTree = "<group>"; };
+		02B041D40E9070E400E46A87 /* Notes.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Notes.pm; sourceTree = "<group>"; };
+		02B041D50E9070E400E46A87 /* Print.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Print.pm; sourceTree = "<group>"; };
+		02B041D60E9070E400E46A87 /* search.pl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = search.pl; sourceTree = "<group>"; };
+		02B041D70E9070E400E46A87 /* Timeline.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Timeline.pm; sourceTree = "<group>"; };
+		02B041D80E9070E400E46A87 /* Vs.pm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = Vs.pm; sourceTree = "<group>"; };
+		02B041DA0E90710300E46A87 /* .perltidyrc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = .perltidyrc; sourceTree = "<group>"; };
+		02B041DB0E90710300E46A87 /* autopsy.base */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = autopsy.base; sourceTree = "<group>"; };
+		02B041DD0E90710400E46A87 /* make-live-cd.base */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "make-live-cd.base"; sourceTree = "<group>"; };
+		02EF3BBF0860F668001CA8B0 /* global.css */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = global.css; path = ../global.css; sourceTree = SOURCE_ROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXGroup section */
+		02670C57079A2F7E00BA95F3 = {
+			isa = PBXGroup;
+			children = (
+				02B041D90E90710300E46A87 /* base */,
+				02B041C30E9070E400E46A87 /* lib */,
+				02EF3BBF0860F668001CA8B0 /* global.css */,
+			);
+			sourceTree = "<group>";
+		};
+		02B041C30E9070E400E46A87 /* lib */ = {
+			isa = PBXGroup;
+			children = (
+				02B041C40E9070E400E46A87 /* .perltidyrc */,
+				02B041C50E9070E400E46A87 /* Appsort.pm */,
+				02B041C60E9070E400E46A87 /* Appview.pm */,
+				02B041C70E9070E400E46A87 /* Args.pm */,
+				02B041C80E9070E400E46A87 /* Caseman.pm */,
+				02B041C90E9070E400E46A87 /* Data.pm */,
+				02B041CA0E9070E400E46A87 /* define.pl */,
+				02B041CB0E9070E400E46A87 /* Exec.pm */,
+				02B041CC0E9070E400E46A87 /* File.pm */,
+				02B041CD0E9070E400E46A87 /* Filesystem.pm */,
+				02B041CE0E9070E400E46A87 /* Frame.pm */,
+				02B041CF0E9070E400E46A87 /* Fs.pm */,
+				02B041D00E9070E400E46A87 /* Hash.pm */,
+				02B041D10E9070E400E46A87 /* Kwsrch.pm */,
+				02B041D20E9070E400E46A87 /* Main.pm */,
+				02B041D30E9070E400E46A87 /* Meta.pm */,
+				02B041D40E9070E400E46A87 /* Notes.pm */,
+				02B041D50E9070E400E46A87 /* Print.pm */,
+				02B041D60E9070E400E46A87 /* search.pl */,
+				02B041D70E9070E400E46A87 /* Timeline.pm */,
+				02B041D80E9070E400E46A87 /* Vs.pm */,
+			);
+			name = lib;
+			path = ../lib;
+			sourceTree = SOURCE_ROOT;
+		};
+		02B041D90E90710300E46A87 /* base */ = {
+			isa = PBXGroup;
+			children = (
+				02B041DA0E90710300E46A87 /* .perltidyrc */,
+				02B041DB0E90710300E46A87 /* autopsy.base */,
+				02B041DD0E90710400E46A87 /* make-live-cd.base */,
+			);
+			name = base;
+			path = ../base;
+			sourceTree = SOURCE_ROOT;
+		};
+/* End PBXGroup section */
+
+/* Begin PBXProject section */
+		02670C5B079A2F7E00BA95F3 /* Project object */ = {
+			isa = PBXProject;
+			buildConfigurationList = 027355510E7C4D6D002BD6DB /* Build configuration list for PBXProject "autopsy" */;
+			compatibilityVersion = "Xcode 2.4";
+			hasScannedForEncodings = 1;
+			mainGroup = 02670C57079A2F7E00BA95F3;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+			);
+		};
+/* End PBXProject section */
+
+/* Begin XCBuildConfiguration section */
+		027355520E7C4D6D002BD6DB /* Development */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+			};
+			name = Development;
+		};
+		027355530E7C4D6D002BD6DB /* Deployment */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+			};
+			name = Deployment;
+		};
+		027355540E7C4D6D002BD6DB /* Default */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+			};
+			name = Default;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		027355510E7C4D6D002BD6DB /* Build configuration list for PBXProject "autopsy" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				027355520E7C4D6D002BD6DB /* Development */,
+				027355530E7C4D6D002BD6DB /* Deployment */,
+				027355540E7C4D6D002BD6DB /* Default */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Default;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 02670C5B079A2F7E00BA95F3 /* Project object */;
+}