Merge branch 'develop' of github.com:sleuthkit/autopsy into develop

This commit is contained in:
Brian Carrier 2015-10-18 21:51:02 -04:00
commit 0179e86e78
391 changed files with 25021 additions and 6233 deletions

1
.gitignore vendored
View File

@ -65,7 +65,6 @@ genfiles.properties
!/Testing/nbproject/project.properties
*~
/netbeans-plat
/docs/doxygen/doxygen_docs
/docs/doxygen-user/user-docs
/jdiff-javadocs/*
/jdiff-logs/*

View File

@ -1,8 +1,8 @@
Last Updated: Sept 17, 2014
Last Updated: 27 April 2015
This file outlines what it takes to build Autopsy from source.
Note that it currently only works out of the box on Windows. We
Note that it currently only works out-of-the-box on Windows. We
are working on getting the process working under non-Windows systems.
It generally works, but needs some custom mangling to find the
correct C libraries.
@ -11,7 +11,10 @@ correct C libraries.
STEPS:
1) Get Java Setup
1a) Download and install JDK version 1.8. For the current version of JavaFX that we use, you'll need 1.8.0_40 or greater. You can now use 32-bit or 64-bit, but special work is needed to get The Sleuth Kit to compile as 64-bit. So, 32-bit is easier.
1a) Download and install JDK version 1.8. For the current version of JavaFX
that we use, you'll need 1.8.0_40 or greater. You can now use 32-bit or 64-bit,
but special work is needed to get The Sleuth Kit to compile as 64-bit. So,
32-bit is easier, but if you intend to use PostgreSQL, choose 64-bit.
Autopsy has been used and tested with Oracle JavaSE and the included JavaFX support
(http://www.oracle.com/technetwork/java/javase/downloads/index.html).
@ -28,33 +31,25 @@ but it is a recommended IDE to use for development of Autopsy modules.
need to set JRE_HOME_32 to the root 32-bit JRE directory and/or JRE_HOME_64
to the root 64-bit JRE directory.
1e) (optional) For some Autopsy features to be functional, you need to add java executable to the system PATH.
1e) (optional) For some Autopsy features to be functional, you need to add the
java executable to the system PATH.
2) Get Sleuth Kit Setup
2a) Download and build the release version of Libewf2 (20130119 or
later). All you need is the dll file. Note that you will get a
launching error if you use libewf 1.
- http://sourceforge.net/projects/libewf/
If you want to build the 64-bit version of The Sleuth Kit, download
our 64-bit version of libewf:
- https://github.com/sleuthkit/libewf_64bit
2b) Set LIBEWF_HOME environment variable to root directory of LIBEWF
2c) Download and build a Release version of Sleuth Kit (TSK) 4.0. You
need to build the tsk_jni project. You can use a released version or
download the latest from github:
2a) Download and build a Release version of Sleuth Kit (TSK) 4.0. See
win32\BUILDING.txt in the TSK package for more information. You need to
build the tsk_jni project. Select the Release_PostgreSQL x64 target. You can
use a released version or download the latest from github:
- git://github.com/sleuthkit/sleuthkit.git
2d) Build the TSK JAR file by typing 'ant' in bindings/java in the
TSK source code folder from a command line. You can also add the
code to a NetBeans project and build it from there.
2b) Build the TSK JAR file by typing 'ant PostgreSQL' in bindings/java in the
TSK source code folder from a command line. Note it is case sensitive. You
can also add the code to a NetBeans project and build it from there,
selecting the PostgreSQL target.
2e) Set TSK_HOME environment variable to the root directory of TSK
2c) Set TSK_HOME environment variable to the root directory of TSK
2f) On Non-Windows systems, you will need to do a 'make install'
2d) On Non-Windows systems, you will need to do a 'make install'
from the TSK root directory to install the libraries and such in
the needed places (i.e. '/usr/local').
@ -85,12 +80,12 @@ and by submitting pull requests to the main Autopsy repository.
5) Compile Autopsy
5a) using Netbeans IDE:
- Start NetBeans IDE and open the Autopsy project.
- Choose to build the Autopsy project / module. It is the highest
level project that will then cause the other modules to be compiled.
- Choose to build the Autopsy project / module. It is the highest level project
that will cause the other modules to be compiled.
5b) without Netbeans IDE (requires JDK and ant >= 1.7.1):
- from root directory of Autopsy source execute:
ant build
ant
(to build Autopsy)
ant run
(to run Autopsy)
@ -101,14 +96,13 @@ Here are some notes to shed some light on what is going on during
the build process.
- The Sleuth Kit Java datamodel JAR file has native JNI libraries
that are copied into it. These JNI libraries have dependencies on
libewf and zlib. On non-Windows platforms, the JNI library also has
a dependency on libtsk (on Windows, it is compiled into libtsk_jni).
that are copied into it. These JNI libraries have dependencies on
libewf, zlib, libpq, libintl-8, libeay32, and ssleay32 DLL files. On non-Windows
platforms, the JNI library also has a dependency on libtsk (on Windows,
it is compiled into libtsk_jni).
- NetBeans uses ant to build Autopsy. The build target copies the
TSK datamodel JAR file into the project. If you want to use the
debug version of the TSK dll, then there is a different ant target
in the TSK datamodel to copy the debug versions of the dlls.
- NetBeans uses ant to build Autopsy. The build target copies the
TSK datamodel JAR file into the project.
- On a Windows system, the compile-time ant target copies the
dependency libraries into the Autopsy code structure so that they can

View File

@ -24,6 +24,10 @@
<property environment="env"/>
<copy file="${env.TSK_HOME}/bindings/java/dist/Tsk_DataModel.jar" tofile="${basedir}/release/modules/ext/Tsk_DataModel.jar"/>
<copy file="${env.TSK_HOME}/bindings/java/lib/sqlite-jdbc-3.8.11.jar" tofile="${basedir}/release/modules/ext/sqlite-jdbc-3.8.11.jar"/>
<copy file="${env.TSK_HOME}/bindings/java/lib/postgresql-9.4-1201-jdbc41.jar" tofile="${basedir}/release/modules/ext/postgresql-9.4-1201-jdbc41.jar"/>
<copy file="${env.TSK_HOME}/bindings/java/lib/mchange-commons-java-0.2.9.jar" tofile="${basedir}/release/modules/ext/mchange-commons-java-0.2.9.jar"/>
<copy file="${env.TSK_HOME}/bindings/java/lib/c3p0-0.9.5.jar" tofile="${basedir}/release/modules/ext/c3p0-0.9.5.jar"/>
<copy file="${env.TSK_HOME}/bindings/java/lib/sqlite-jdbc-3.8.11.jar" tofile="${basedir}/release/modules/ext/sqlite-jdbc-3.8.11.jar"/>
</target>

View File

@ -1,19 +1,21 @@
file.reference.activemq-all-5.11.1.jar=release/modules/ext/activemq-all-5.11.1.jar
file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar
file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar
file.reference.jython.jar-1=release/modules/ext/jython.jar
file.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1.jar
file.reference.postgresql-9.4-1201-jdbc41.jar=release/modules/ext/postgresql-9.4-1201-jdbc41.jar
file.reference.opencv-248.jar=release/modules/ext/opencv-248.jar
file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar
file.reference.sevenzipjbinding-AllPlatforms.jar=release/modules/ext/sevenzipjbinding-AllPlatforms.jar
file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar
file.reference.sqlite-jdbc-3.8.11.jar=release/modules/ext/sqlite-jdbc-3.8.11.jar
file.reference.StixLib.jar=release/modules/ext/StixLib.jar
file.reference.tika-core-1.2.jar=release/modules/ext/tika-core-1.2.jar
file.reference.tika-core-1.5.jar=release/modules/ext/tika-core-1.5.jar
file.reference.Tsk_DataModel.jar=release/modules/ext/Tsk_DataModel.jar
file.reference.xmpcore-5.1.2.jar=release/modules/ext/xmpcore-5.1.2.jar
javac.source=1.8
javac.compilerargs=-Xlint -Xlint:-serial
javadoc.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1-src.zip
license.file=../LICENSE-2.0.txt
nbm.homepage=http://www.sleuthkit.org/
nbm.module.author=Brian Carrier

View File

@ -184,9 +184,11 @@
<public-packages>
<package>org.sleuthkit.autopsy.actions</package>
<package>org.sleuthkit.autopsy.casemodule</package>
<package>org.sleuthkit.autopsy.casemodule.events</package>
<package>org.sleuthkit.autopsy.casemodule.services</package>
<package>org.sleuthkit.autopsy.contentviewers</package>
<package>org.sleuthkit.autopsy.core</package>
<package>org.sleuthkit.autopsy.core.events</package>
<package>org.sleuthkit.autopsy.corecomponentinterfaces</package>
<package>org.sleuthkit.autopsy.corecomponents</package>
<package>org.sleuthkit.autopsy.coreutils</package>
@ -203,14 +205,26 @@
<package>org.sleuthkit.autopsy.report</package>
<package>org.sleuthkit.datamodel</package>
</public-packages>
<class-path-extension>
<runtime-relative-path>ext/xmpcore-5.1.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/xmpcore-5.1.2.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jdom-2.0.5.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jdom-2.0.5.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/postgresql-9.4-1201-jdbc41.jar</runtime-relative-path>
<binary-origin>release/modules/ext/postgresql-9.4-1201-jdbc41.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/mchange-commons-java-0.2.9.jar</runtime-relative-path>
<binary-origin>release/modules/ext/mchange-commons-java-0.2.9.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/c3p0-0.9.5.jar</runtime-relative-path>
<binary-origin>release/modules/ext/c3p0-0.9.5.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/xmpcore-5.1.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/xmpcore-5.1.2.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/StixLib.jar</runtime-relative-path>
<binary-origin>release/modules/ext/StixLib.jar</binary-origin>
@ -228,20 +242,32 @@
<binary-origin>release/modules/ext/Rejistry-1.0-SNAPSHOT.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sevenzipjbinding.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sevenzipjbinding.jar</binary-origin>
<runtime-relative-path>ext/activemq-all-5.11.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/activemq-all-5.11.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/Rejistry-1.0-SNAPSHOT.jar</runtime-relative-path>
<binary-origin>release/modules/ext/Rejistry-1.0-SNAPSHOT.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jython-standalone-2.7.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jython-standalone-2.7.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sevenzipjbinding.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sevenzipjbinding.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sevenzipjbinding-AllPlatforms.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sevenzipjbinding-AllPlatforms.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/tika-core-1.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/tika-core-1.2.jar</binary-origin>
<runtime-relative-path>ext/tika-core-1.5.jar</runtime-relative-path>
<binary-origin>release/modules/ext/tika-core-1.5.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/metadata-extractor-2.8.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/metadata-extractor-2.8.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/metadata-extractor-2.8.1.jar</runtime-relative-path>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2013-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -21,7 +21,7 @@ package org.sleuthkit.autopsy.actions;
import java.util.Collection;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.casemodule.Case;
@ -63,20 +63,25 @@ public class AddBlackboardArtifactTagAction extends AddTagAction {
@Override
protected void addTag(TagName tagName, String comment) {
Collection<? extends BlackboardArtifact> selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
for (BlackboardArtifact artifact : selectedArtifacts) {
try {
Case.getCurrentCase().getServices().getTagsManager().addBlackboardArtifactTag(artifact, tagName, comment);
} catch (TskCoreException ex) {
Logger.getLogger(AddBlackboardArtifactTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); //NON-NLS
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"AddBlackboardArtifactTagAction.unableToTag.msg",
artifact.getDisplayName()),
NbBundle.getMessage(this.getClass(),
"AddBlackboardArtifactTagAction.taggingErr"),
JOptionPane.ERROR_MESSAGE);
final Collection<? extends BlackboardArtifact> selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
new Thread(() -> {
for (BlackboardArtifact artifact : selectedArtifacts) {
try {
Case.getCurrentCase().getServices().getTagsManager().addBlackboardArtifactTag(artifact, tagName, comment);
} catch (TskCoreException ex) {
Logger.getLogger(AddBlackboardArtifactTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); //NON-NLS
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"AddBlackboardArtifactTagAction.unableToTag.msg",
artifact.getDisplayName()),
NbBundle.getMessage(this.getClass(),
"AddBlackboardArtifactTagAction.taggingErr"),
JOptionPane.ERROR_MESSAGE);
});
}
}
}
}).start();
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-15 Basis Technology Corp.
* Copyright 2013-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -22,6 +22,7 @@ import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.casemodule.Case;
@ -41,6 +42,7 @@ public class AddContentTagAction extends AddTagAction {
// This class is a singleton to support multi-selection of nodes, since
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
// node in the array returns a reference to the same action object from Node.getActions(boolean).
private static AddContentTagAction instance;
public static synchronized AddContentTagAction getInstance() {
@ -63,71 +65,93 @@ public class AddContentTagAction extends AddTagAction {
@Override
protected void addTag(TagName tagName, String comment) {
Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
for (AbstractFile file : selectedFiles) {
try {
// Handle the special cases of current (".") and parent ("..") directory entries.
if (".".equals(file.getName())) {
Content parentFile = file.getParent();
if (parentFile instanceof AbstractFile) {
file = (AbstractFile) parentFile;
} else {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.unableToTag.msg",
parentFile.getName()),
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.cannotApplyTagErr"),
JOptionPane.WARNING_MESSAGE);
continue;
}
} else if ("..".equals(file.getName())) {
Content parentFile = file.getParent();
if (parentFile instanceof AbstractFile) {
parentFile = parentFile.getParent();
final Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
new Thread(() -> {
for (AbstractFile file : selectedFiles) {
try {
// Handle the special cases of current (".") and parent ("..") directory entries.
if (file.getName().equals(".")) {
Content parentFile = file.getParent();
if (parentFile instanceof AbstractFile) {
file = (AbstractFile) parentFile;
} else {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.unableToTag.msg",
parentFile.getName()),
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.cannotApplyTagErr"),
JOptionPane.WARNING_MESSAGE);
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.unableToTag.msg",
parentFile.getName()),
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.cannotApplyTagErr"),
JOptionPane.WARNING_MESSAGE);
});
continue;
}
} else {
} else if (file.getName().equals("..")) {
Content parentFile = file.getParent();
if (parentFile instanceof AbstractFile) {
parentFile = (AbstractFile) ((AbstractFile) parentFile).getParent();
if (parentFile instanceof AbstractFile) {
file = (AbstractFile) parentFile;
} else {
final Content parentFileCopy = parentFile;
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.unableToTag.msg",
parentFileCopy.getName()),
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.cannotApplyTagErr"),
JOptionPane.WARNING_MESSAGE);
});
continue;
}
} else {
final Content parentFileCopy = parentFile;
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.unableToTag.msg",
parentFileCopy.getName()),
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.cannotApplyTagErr"),
JOptionPane.WARNING_MESSAGE);
});
continue;
}
}
// check if the same tag is being added for the same abstract file.
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
List<ContentTag> contentTagList = tagsManager.getContentTagsByContent(file);
for (ContentTag contentTag : contentTagList) {
if (contentTag.getName().getDisplayName().equals(tagName.getDisplayName())) {
AbstractFile fileCopy = file;
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.tagExists",
fileCopy.getName(), tagName.getDisplayName()),
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.cannotApplyTagErr"),
JOptionPane.WARNING_MESSAGE);
});
return;
}
}
tagsManager.addContentTag(file, tagName, comment);
} catch (TskCoreException ex) {
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); //NON-NLS
AbstractFile fileCopy = file;
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.unableToTag.msg",
parentFile.getName()),
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.cannotApplyTagErr"),
JOptionPane.WARNING_MESSAGE);
continue;
}
"AddContentTagAction.unableToTag.msg2",
fileCopy.getName()),
NbBundle.getMessage(this.getClass(), "AddContentTagAction.taggingErr"),
JOptionPane.ERROR_MESSAGE);
});
}
// check if the same tag is being added for the same abstract file.
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
List<ContentTag> contentTagList = tagsManager.getContentTagsByContent(file);
boolean alreadyTaggedWithTagName = contentTagList.stream()
.map(ContentTag::getName)
.filter(tagName::equals)
.findAny().isPresent();
if (alreadyTaggedWithTagName) {
continue; //skip this file, it already has a tag with this TagName.
}
tagsManager.addContentTag(file, tagName, comment);
} catch (TskCoreException ex) {
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); //NON-NLS
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"AddContentTagAction.unableToTag.msg2",
file.getName()),
NbBundle.getMessage(this.getClass(), "AddContentTagAction.taggingErr"),
JOptionPane.ERROR_MESSAGE);
}
}
}).start();
}
}

View File

@ -49,7 +49,12 @@ GetTagNameDialog.taggingErr=Tagging Error
GetTagNameDialog.tagNameAlreadyDef.msg=A {0} tag name has already been defined.
GetTagNameDialog.dupTagErr=Duplicate Tag Error
OpenLogFolder.error1=Log File Not Found: {0}
OpenLogFolder.CouldNotOpenLogFolder=Could not open log folder
CTL_OpenLogFolder=Open Log Folder
CTL_OpenOutputFolder=Open Output Folder
OpenOutputFolder.error1=Output Folder Not Found: {0}
OpenOutputFolder.noCaseOpen=No open case, therefore no current output folder available.
OpenOutputFolder.CouldNotOpenOutputFolder=Could not open output folder
ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot
OpenPythonModulesFolderAction.actionName.text=Python Plugins
OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python plugins folder not found: {0}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2013-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -23,6 +23,7 @@ import java.util.Collection;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.casemodule.Case;
@ -36,6 +37,7 @@ import org.sleuthkit.datamodel.TskCoreException;
*/
public class DeleteBlackboardArtifactTagAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private static final String MENU_TEXT = NbBundle.getMessage(DeleteBlackboardArtifactTagAction.class,
"DeleteBlackboardArtifactTagAction.deleteTags");
@ -57,20 +59,49 @@ public class DeleteBlackboardArtifactTagAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent event) {
Collection<? extends BlackboardArtifactTag> selectedTags = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactTag.class);
for (BlackboardArtifactTag tag : selectedTags) {
try {
Case.getCurrentCase().getServices().getTagsManager().deleteBlackboardArtifactTag(tag);
} catch (TskCoreException ex) {
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"DeleteBlackboardArtifactTagAction.unableToDelTag.msg",
tag.getName()),
NbBundle.getMessage(this.getClass(),
"DeleteBlackboardArtifactTagAction.tagDelErr"),
JOptionPane.ERROR_MESSAGE);
final Collection<? extends BlackboardArtifactTag> selectedTags = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactTag.class);
new Thread(() -> {
for (BlackboardArtifactTag tag : selectedTags) {
try {
Case.getCurrentCase().getServices().getTagsManager().deleteBlackboardArtifactTag(tag);
} catch (TskCoreException ex) {
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"DeleteBlackboardArtifactTagAction.unableToDelTag.msg",
tag.getName()),
NbBundle.getMessage(this.getClass(),
"DeleteBlackboardArtifactTagAction.tagDelErr"),
JOptionPane.ERROR_MESSAGE);
});
}
}
}
}).start();
}
/**
* Deprecated, use actionPerformed() instead.
*
* @param event The event associated with the action.
*
* @deprecated
*/
@Deprecated
protected void doAction(ActionEvent event) {
actionPerformed(event);
}
/**
* Deprecated, does nothing. The TagManager methods to create, update or
* delete tags now notify the case that there is a tag change. The case then
* publishes an event that triggers a refresh of the tags sub-tree in the
* tree view.
*
* @deprecated
*/
@Deprecated
protected void refreshDirectoryTree() {
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2013-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -23,6 +23,7 @@ import java.util.Collection;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.casemodule.Case;
@ -35,6 +36,7 @@ import org.sleuthkit.datamodel.TskCoreException;
*/
public class DeleteContentTagAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private static final String MENU_TEXT = NbBundle.getMessage(DeleteContentTagAction.class,
"DeleteContentTagAction.deleteTags");
@ -56,19 +58,48 @@ public class DeleteContentTagAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
Collection<? extends ContentTag> selectedTags = Utilities.actionsGlobalContext().lookupAll(ContentTag.class);
for (ContentTag tag : selectedTags) {
try {
Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(tag);
} catch (TskCoreException ex) {
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"DeleteContentTagAction.unableToDelTag.msg",
tag.getName()),
NbBundle.getMessage(this.getClass(), "DeleteContentTagAction.tagDelErr"),
JOptionPane.ERROR_MESSAGE);
final Collection<? extends ContentTag> selectedTags = Utilities.actionsGlobalContext().lookupAll(ContentTag.class);
new Thread(() -> {
for (ContentTag tag : selectedTags) {
try {
Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(tag);
} catch (TskCoreException ex) {
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"DeleteContentTagAction.unableToDelTag.msg",
tag.getName()),
NbBundle.getMessage(this.getClass(), "DeleteContentTagAction.tagDelErr"),
JOptionPane.ERROR_MESSAGE);
});
}
}
}
}).start();
}
/**
* Deprecated, use actionPerformed() instead.
*
* @param event The event associated with the action.
*
* @deprecated
*/
@Deprecated
protected void doAction(ActionEvent event) {
actionPerformed(event);
}
/**
* Deprecated, does nothing. The TagManager methods to create, update or
* delete tags now notify the case that there is a tag change. The case then
* publishes an event that triggers a refresh of the tags sub-tree in the
* tree view.
*
* @deprecated
*/
@Deprecated
protected void refreshDirectoryTree() {
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Copyright 2014-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -23,15 +23,16 @@ import java.awt.event.ActionListener;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionRegistration;
import org.openide.modules.Places;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Action in menu to open the folder containing the log files
@ -42,6 +43,8 @@ import org.sleuthkit.autopsy.casemodule.Case;
@ActionID(id = "org.sleuthkit.autopsy.actions.OpenLogFolderAction", category = "Help")
public final class OpenLogFolderAction implements ActionListener {
private static final Logger logger = Logger.getLogger(OpenLogFolderAction.class.getName());
@Override
public void actionPerformed(ActionEvent e) {
try {
@ -61,7 +64,8 @@ public final class OpenLogFolderAction implements ActionListener {
Desktop.getDesktop().open(logDir);
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "OpenLogFolder.CouldNotOpenLogFolder"), ex); //NON-NLS
}
}
}

View File

@ -0,0 +1,71 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionRegistration;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Action in menu to open the folder containing the output files
*/
@ActionRegistration(
displayName = "#CTL_OpenOutputFolder", iconInMenu = true)
@ActionReference(path = "Menu/Help", position = 1850)
@ActionID(id = "org.sleuthkit.autopsy.actions.OpenOutputFolderAction", category = "Help")
public final class OpenOutputFolderAction implements ActionListener {
private static final Logger logger = Logger.getLogger(OpenOutputFolderAction.class.getName());
@Override
public void actionPerformed(ActionEvent e) {
try {
File outputDir;
if (Case.isCaseOpen()) {
outputDir = new File(Case.getCurrentCase().getOutputDirectory());
if (outputDir.exists() == false) {
NotifyDescriptor d
= new NotifyDescriptor.Message(NbBundle.getMessage(this.getClass(),
"OpenOutputFolder.error1", outputDir.getAbsolutePath()),
NotifyDescriptor.ERROR_MESSAGE);
DialogDisplayer.getDefault().notify(d);
} else {
Desktop.getDesktop().open(outputDir);
}
} else {
JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(), "OpenOutputFolder.noCaseOpen"));
}
} catch (IOException ex) {
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "OpenOutputFolder.CouldNotOpenOutputFolder"), ex); //NON-NLS
}
}
}

View File

@ -20,12 +20,10 @@ package org.sleuthkit.autopsy.casemodule;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.event.ChangeEvent;
@ -33,7 +31,8 @@ import javax.swing.event.ChangeListener;
import org.openide.WizardDescriptor;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.openide.windows.WindowManager;
import java.awt.Cursor;
/**
* The "Add Image" wizard panel1 handling the logic of selecting image file(s)
@ -70,6 +69,7 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<Wiza
@Override
public AddImageWizardChooseDataSourceVisual getComponent() {
if (component == null) {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
component = new AddImageWizardChooseDataSourceVisual(this);
}
component.addPropertyChangeListener(this);

View File

@ -84,7 +84,13 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
// make a list of core DSPs
// ensure that the core DSPs are at the top and in a fixed order
coreDSPTypes.add(ImageDSProcessor.getType());
coreDSPTypes.add(LocalDiskDSProcessor.getType());
// Local disk processing is not allowed for multi-user cases
if (Case.getCurrentCase().getCaseType() != Case.CaseType.MULTI_USER_CASE) {
coreDSPTypes.add(LocalDiskDSProcessor.getType());
} else {
// remove LocalDiskDSProcessor from list of DSPs
datasourceProcessorsMap.remove(LocalDiskDSProcessor.getType());
}
coreDSPTypes.add(LocalFilesDSProcessor.getType());
for (String dspType : coreDSPTypes) {

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2014 Basis Technology Corp.
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -25,13 +25,13 @@ import java.awt.Window;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeListener;
import org.openide.WizardDescriptor;
import org.openide.util.HelpCtx;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
@ -47,7 +47,7 @@ import org.sleuthkit.autopsy.ingest.IngestManager;
*/
class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDescriptor> {
private IngestJobSettingsPanel ingestJobSettingsPanel;
private final IngestJobSettingsPanel ingestJobSettingsPanel;
/**
* The visual component that displays this panel. If you need to access the
@ -220,13 +220,14 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
* DataSourceProcessor
*/
private void startDataSourceProcessing(WizardDescriptor settings) {
final UUID dataSourceId = UUID.randomUUID();
// Add a cleanup task to interrupt the background process if the
// wizard exits while the background process is running.
cleanupTask = addImageAction.new CleanupTask() {
@Override
void cleanup() throws Exception {
cancelDataSourceProcessing();
cancelDataSourceProcessing(dataSourceId);
}
};
@ -235,10 +236,13 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
// get the selected DSProcessor
dsProcessor = dataSourcePanel.getComponent().getCurrentDSProcessor();
new Thread(() -> {
Case.getCurrentCase().notifyAddingDataSource(dataSourceId);
}).start();
DataSourceProcessorCallback cbObj = new DataSourceProcessorCallback() {
@Override
public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
dataSourceProcessorDone(result, errList, contents);
dataSourceProcessorDone(dataSourceId, result, errList, contents);
}
};
@ -253,7 +257,10 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
/*
* Cancels the data source processing - in case the users presses 'Cancel'
*/
private void cancelDataSourceProcessing() {
private void cancelDataSourceProcessing(UUID dataSourceId) {
new Thread(() -> {
Case.getCurrentCase().notifyFailedAddingDataSource(dataSourceId);
}).start();
dsProcessor.cancel();
}
@ -261,8 +268,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
* Callback for the data source processor. Invoked by the DSP on the EDT
* thread, when it finishes processing the data source.
*/
private void dataSourceProcessorDone(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
private void dataSourceProcessorDone(UUID dataSourceId, DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
// disable the cleanup task
cleanupTask.disable();
@ -301,10 +307,13 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
newContents.addAll(contents);
//notify the UI of the new content added to the case
if (!newContents.isEmpty()) {
Case.getCurrentCase().notifyNewDataSource(newContents.get(0));
}
new Thread(() -> {
if (!newContents.isEmpty()) {
Case.getCurrentCase().notifyDataSourceAdded(newContents.get(0), dataSourceId);
} else {
Case.getCurrentCase().notifyFailedAddingDataSource(dataSourceId);
}
}).start();
// Start ingest if we can
progressPanel.setStateStarted();

View File

@ -107,13 +107,13 @@ AddImageWizardIngestConfigVisual.getName.text=Configure Ingest Modules
AddImageWizardIterator.stepXofN=Step {0} of {1}
AddLocalFilesTask.localFileAdd.progress.text=Adding\: {0}/{1}
Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open\!
Case.moduleErr=Module Error
Case.changeCase.errListenToCaseUpdates.msg=A module caused an error listening to Case updates. See log to determine which module. Some data could be incomplete.
Case.create.exception.msg=Error creating a case\: {0} in dir {1}
Case.databaseConnectionInfo.error.msg=Error accessing case database connection info
Case.open.exception.blankCase.msg=Case name is blank.
Case.open.msgDlg.updated.msg=Updated case database schema.\nA backup copy of the database with the following path has been made\:\n {0}
Case.open.msgDlg.updated.title=Case Database Schema Update
Case.open.exception.checkFile.msg=Check that you selected the correct case file (usually with {0} extension)
Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. See Tools, Options, Multi-user.
Case.open.exception.gen.msg=Error opening the case
Case.checkImgExist.confDlg.doesntExist.msg={0} has detected that one of the images associated with \n\
this case are missing. Would you like to search for them now?\n\
@ -135,7 +135,11 @@ Case.createCaseDir.exception.existCantRW=Cannot create case dir, already exists
Case.createCaseDir.exception.cantCreate=Cannot create case dir\: {0}
Case.createCaseDir.exception.cantCreateCaseDir=Could not create case directory\: {0}
Case.createCaseDir.exception.cantCreateModDir=Could not create modules output directory\: {0}
Case.createCaseDir.exception.cantCreateReportsDir=Could not create reports output directory\: {0}
Case.createCaseDir.exception.gen=Could not create case directory\: {0}
Case.CollaborationSetup.FailNotify.ErrMsg=Failed to connect to any other nodes that may be collaborating on this case.
Case.CollaborationSetup.FailNotify.Title=Connection Failure
Case.GetCaseTypeGivenPath.Failure=Unable to get case type
CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \n\
Case Name\: {0}\n\
Case Directory\: {1}
@ -145,10 +149,11 @@ Close the folder and file and try again or you can delete the case manually.
CaseDeleteAction.msgDlg.fileInUse.title=Error\: Folder In Use
CaseDeleteAction.msgDlg.caseDelete.msg=Case {0} has been deleted.
CaseOpenAction.autFilter.title={0} Case File ( {1})
CaseOpenAction.msgDlg.fileNotExist.msg=Error\: File does not exist.
CaseOpenAction.msgDlg.fileNotExist.title=Error
CaseOpenAction.msgDlg.cantOpenCase.msg=Error\: could not open the case in folder {0}\: {1}
CaseOpenAction.msgDlg.cantOpenCase.title=Error
CaseOpenAction.msgDlg.cantOpenCase.title=Error Opening Case
CaseCreateAction.msgDlg.cantCreateCase.msg=Cannot create case
IntervalErrorReport.NewIssues=new issue(s)
IntervalErrorReport.TotalIssues=total issue(s)
IntervalErrorReport.ErrorText=Database Connection Error
CasePropertiesAction.window.title=Case Properties
CasePropertiesForm.updateCaseName.msgDlg.empty.msg=The caseName cannot be empty.
CasePropertiesForm.updateCaseName.msgDlg.empty.title=Error
@ -183,13 +188,18 @@ MissingImageDialog.allDesc.text=All Supported Types
MissingImageDialog.display.title=Search for Missing Image
MissingImageDialog.confDlg.noFileSel.msg=No image file has been selected, are you sure you\nwould like to exit without finding the image.
MissingImageDialog.confDlg.noFileSel.title=Missing Image
MissingImageDialog.ErrorSettingImage=Error setting image path. Please try again.
NewCaseVisualPanel1.getName.text=Case Info
NewCaseVisualPanel1.caseDirBrowse.selectButton.text=Select
NewCaseVisualPanel1.badCredentials.text=Bad multi-user settings (see Tools, Options, Multi-user) or services are down.
NewCaseVisualPanel1.MultiUserDisabled.text=Multi-user cases not enabled. See Tools, Options, Multi-user.
NewCaseVisualPanel2.getName.text=Additional Information
NewCaseWizardAction.closeCurCase.confMsg.msg=Do you want to save and close this case and proceed with the new case creation?
NewCaseWizardAction.closeCurCase.confMsg.title=Warning\: Closing the Current Case
NewCaseWizardAction.newCase.windowTitle.text=New Case Information
NewCaseWizardAction.getName.text=New Case Wizard
NewCaseWizardAction.databaseProblem1.text=Cannot open database. Cancelling case creation.
NewCaseWizardAction.databaseProblem2.text=Error
NewCaseWizardPanel1.validate.errMsg.invalidSymbols=The Case Name cannot contain any of the following symbols\: \\ / \: * ? " < > |
NewCaseWizardPanel1.validate.errMsg.dirExists=Case directory ''{0}'' already exists.
NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory "{0}" does not exist. \n\n\
@ -221,5 +231,33 @@ Detail\: \n\
Cannot open a non-Autopsy config file (at {1}).
XMLCaseManagement.open.msgDlg.notAutCase.title=Error
AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel
ImageFilePanel.errorLabel.text=Error Label
DataSourceOnCDriveError.text=Warning: Path to multi-user data source is on \"C:\" drive
NewCaseVisualPanel1.CaseFolderOnCDriveError.text=Warning: Path to multi-user case folder is on \"C:\" drive
LocalFilesPanel.errorLabel.text=Error Label
CollaborationMonitor.addingDataSourceStatus.msg={0} adding data source
CollaborationMonitor.analyzingDataSourceStatus.msg={0} analyzing {1}
MissingImageDialog.lbWarning.text=
MissingImageDialog.lbWarning.toolTipText=
SingleUserCaseImporter.AlreadyMultiUser=Case is already multi-user!
SingleUserCaseImporter.BadCaseSourceFolder=Case source folder does not exist!
SingleUserCaseImporter.BadImageSourceFolder=Image source folder does not exist!
SingleUserCaseImporter.BadDatabaseFileName=Database file does not exist!
SingleUserCaseImporter.NonUniqueOutputFolder=Output folder not unique. Skipping
SingleUserCaseImporter.NonUniqueDatabaseName=Database name not unique. Skipping.
SingleUserCaseImporter.PotentiallyNonUniqueDatabaseName=Unclear if database name unique. Moving ahead.
SingleUserCaseImporter.ImportedAsMultiUser=\nThis case was imported as a multi-user collaborative case on
SingleUserCaseImporter.UnableToCopySourceImages=Unable to copy source images
SingleUserCaseImporter.DeletingCase=Deleting original case folder
SingleUserCaseImporter.CanNotOpenDatabase=Unable to open database
SingleUserCaseImporter.WillImport=Will import:
SingleUserCaseImporter.WillNotImport=Will not import:
SingleUserCaseImporter.None=None
SingleUserCaseImporter.ContinueWithImport=Continue with import?
SingleUserCaseImporter.Cancelled=Cancelled
NewCaseVisualPanel1.caseParentDirWarningLabel.text=Case directory warning label
NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-user
NewCaseVisualPanel1.singleUserCaseRadioButton.text=Single-user
NewCaseVisualPanel1.multiUserSettingsWarningLabel.text=Multi-user settings warning label
Case.deleteReports.deleteFromDiskException.log.msg=Unable to delete the report from the disk.
Case.deleteReports.deleteFromDiskException.msg=Unable to delete the report {0} from the disk.\nYou may manually delete it from {1}

View File

@ -102,8 +102,6 @@ AddImageWizardIngestConfigVisual.getName.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30
AddImageWizardIterator.stepXofN=\u30b9\u30c6\u30c3\u30d7{0}\uff0f{1}
AddLocalFilesTask.localFileAdd.progress.text=\u8ffd\u52a0\u4e2d\uff1a{0}/{1}
Case.getCurCase.exception.noneOpen=\u73fe\u5728\u306e\u30b1\u30fc\u30b9\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\uff1b\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\uff01
Case.moduleErr=\u30e2\u30b8\u30e5\u30fc\u30eb\u30a8\u30e9\u30fc
Case.changeCase.errListenToCaseUpdates.msg=\u30b1\u30fc\u30b9\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3092\u78ba\u8a8d\u4e2d\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u30a8\u30e9\u30fc\u3092\u8d77\u3053\u3057\u307e\u3057\u305f\u3002\u3069\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u304b\u30ed\u30b0\u3067\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\u3002\u4e00\u90e8\u306e\u30c7\u30fc\u30bf\u304c\u4e0d\u5b8c\u5168\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002
Case.create.exception.msg=\u30b1\u30fc\u30b9\u4f5c\u6210\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a\u30c7\u30a3\u30ec\u30af\u30c8\u30ea{1}\u306e{0}
Case.open.exception.blankCase.msg=\u30b1\u30fc\u30b9\u540d\u304c\u7a7a\u767d\u3067\u3059\u3002
Case.open.msgDlg.updated.msg=\u30b1\u30fc\u30b9\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30b9\u30ad\u30fc\u30de\u3092\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3057\u307e\u3057\u305f\u3002\n\
@ -217,3 +215,6 @@ XMLCaseManagement.open.msgDlg.notAutCase.title=\u30a8\u30e9\u30fc
ImageFilePanel.noFatOrphansCheckbox.text=FAT\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u306e\u30aa\u30fc\u30d5\u30a1\u30f3\u30d5\u30a1\u30a4\u30eb\u306f\u7121\u8996
LocalDiskPanel.noFatOrphansCheckbox.text=FAT\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u306e\u30aa\u30fc\u30d5\u30a1\u30f3\u30d5\u30a1\u30a4\u30eb\u306f\u7121\u8996
AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=\u30ad\u30e3\u30f3\u30bb\u30eb
ImageFilePanel.errorLabel.text=\u30a8\u30e9\u30fc\u30e9\u30d9\u30eb
LocalFilesPanel.errorLabel.text=\u30a8\u30e9\u30fc\u30e9\u30d9\u30eb
NewCaseVisualPanel1.caseParentDirWarningLabel.text=\u30a8\u30e9\u30fc\u30e9\u30d9\u30eb

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2014 Basis Technology Corp.
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -19,15 +19,11 @@
package org.sleuthkit.autopsy.casemodule;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.SwingWorker;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction;
@ -37,7 +33,7 @@ import org.openide.util.actions.Presenter;
* The action to close the current Case. This class should be disabled on
* creation and it will be enabled on new case creation or case opened.
*/
final class CaseCloseAction extends CallableSystemAction implements Presenter.Toolbar {
public final class CaseCloseAction extends CallableSystemAction implements Presenter.Toolbar {
JButton toolbarButton = new JButton();
@ -49,13 +45,7 @@ final class CaseCloseAction extends CallableSystemAction implements Presenter.To
putValue(Action.NAME, NbBundle.getMessage(CaseCloseAction.class, "CTL_CaseCloseAct")); // put the action Name
// set action of the toolbar button
toolbarButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
CaseCloseAction.this.actionPerformed(e);
}
});
toolbarButton.addActionListener(CaseCloseAction.this::actionPerformed);
this.setEnabled(false);
}
@ -71,23 +61,24 @@ final class CaseCloseAction extends CallableSystemAction implements Presenter.To
return;
}
Case result = Case.getCurrentCase();
new SwingWorker<Void, Void>() {
if (!MessageNotifyUtil.Message.confirm("Are you sure you want to close current case?")) {
return;
}
try {
result.closeCase();
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
StartupWindowProvider.getInstance().open();
@Override
protected Void doInBackground() throws Exception {
try {
Case result = Case.getCurrentCase();
result.closeCase();
} catch (CaseActionException | IllegalStateException unused) {
// Already logged.
}
});
} catch (Exception ex) {
Logger.getLogger(CaseCloseAction.class.getName()).log(Level.WARNING, "Error closing case.", ex); //NON-NLS
}
return null;
}
@Override
protected void done() {
StartupWindowProvider.getInstance().open();
}
}.execute();
}
/**

View File

@ -0,0 +1,136 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule;
import java.nio.file.Path;
/**
* Provides access to case metadata.
*/
public final class CaseMetadata {
/**
* Exception thrown by the CaseMetadata class when there is a problem
* accessing the metadata for a case.
*/
public final static class CaseMetadataException extends Exception {
private CaseMetadataException(String message) {
super(message);
}
private CaseMetadataException(String message, Throwable cause) {
super(message, cause);
}
}
private final Case.CaseType caseType;
private final String caseName;
private final String caseNumber;
private final String examiner;
private final String caseDirectory;
private final String caseDatabaseName;
/**
* Constructs an object that provides access to case metadata.
*
* @param metadataFilePath
*/
public CaseMetadata(Path metadataFilePath) throws CaseMetadataException {
try {
// NOTE: This class will eventually replace XMLCaseManagement.
// This constructor should parse all of the metadata. In the future,
// case metadata may be moved into the case database.
XMLCaseManagement metadata = new XMLCaseManagement();
metadata.open(metadataFilePath.toString());
caseType = metadata.getCaseType();
caseName = metadata.getCaseName();
if (caseName.isEmpty()) {
throw new CaseMetadataException("Case name missing");
}
caseNumber = metadata.getCaseNumber();
examiner = metadata.getCaseExaminer();
caseDirectory = metadata.getCaseDirectory();
if (caseDirectory.isEmpty()) {
throw new CaseMetadataException("Case directory missing");
}
caseDatabaseName = metadata.getDatabaseName();
if (Case.CaseType.MULTI_USER_CASE == caseType && caseDatabaseName.isEmpty()) {
throw new CaseMetadataException("Case database name missing");
}
} catch (CaseActionException ex) {
throw new CaseMetadataException(ex.getLocalizedMessage(), ex);
}
}
/**
* Gets the case type.
*
* @return The case type.
*/
public Case.CaseType getCaseType() {
return this.caseType;
}
/**
* Gets the case name.
*
* @return The case name.
*/
public String getCaseName() {
return caseName;
}
/**
* Gets the case number.
*
* @return The case number, may be empty.
*/
public String getCaseNumber() {
return caseNumber;
}
/**
* Gets the examiner.
*
* @return The examiner, may be empty.
*/
public String getExaminer() {
return examiner;
}
/**
* Gets the case directory.
*
* @return The case directory.
*/
public String getCaseDirectory() {
return caseDirectory;
}
/**
* Gets the case database name.
*
* @return The case database name, will be empty for a single-user case.
*/
public String getCaseDatabaseName() {
return caseDatabaseName;
}
}

View File

@ -19,6 +19,9 @@
package org.sleuthkit.autopsy.casemodule;
import java.awt.event.ActionEvent;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction;
import org.openide.util.actions.SystemAction;
import org.openide.util.lookup.ServiceProvider;
@ -28,7 +31,7 @@ import org.openide.util.lookup.ServiceProvider;
* @author jantonius
*/
@ServiceProvider(service = CaseNewActionInterface.class)
public final class CaseNewAction implements CaseNewActionInterface {
public final class CaseNewAction extends CallableSystemAction implements CaseNewActionInterface {
private NewCaseWizardAction wizard = SystemAction.get(NewCaseWizardAction.class);
@ -41,4 +44,18 @@ public final class CaseNewAction implements CaseNewActionInterface {
public void actionPerformed(ActionEvent e) {
wizard.performAction();
}
@Override
public void performAction() {
}
@Override
public String getName() {
return NbBundle.getMessage(CaseNewAction.class, "CTL_CaseNewAction");
}
@Override
public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2014 Basis Technology Corp.
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,97 +18,87 @@
*/
package org.sleuthkit.autopsy.casemodule;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.logging.Level;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.Version;
/**
* The action to open a existing case. This class is always enabled.
* An action that opens an existing case.
*/
@ServiceProvider(service = CaseOpenAction.class)
public final class CaseOpenAction implements ActionListener {
private static final Logger logger = Logger.getLogger(CaseOpenAction.class.getName());
private static final String PROP_BASECASE = "LBL_BaseCase_PATH"; //NON-NLS
private final JFileChooser fc = new JFileChooser();
private FileFilter autFilter;
private final JFileChooser fileChooser = new JFileChooser();
private final FileFilter caseMetadataFileFilter;
/**
* The constructor
* Constructs an action that opens an existing case.
*/
public CaseOpenAction() {
autFilter = new FileNameExtensionFilter(
NbBundle.getMessage(CaseOpenAction.class, "CaseOpenAction.autFilter.title", Version.getName(),
Case.CASE_DOT_EXTENSION),
Case.CASE_EXTENSION);
fc.setDragEnabled(false);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setMultiSelectionEnabled(false);
fc.setFileFilter(autFilter);
try {
if (ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_BASECASE) != null) {
fc.setCurrentDirectory(new File(ModuleSettings.getConfigSetting("Case", PROP_BASECASE))); //NON-NLS
}
} catch (Exception e) {
caseMetadataFileFilter = new FileNameExtensionFilter(NbBundle.getMessage(CaseOpenAction.class, "CaseOpenAction.autFilter.title", Version.getName(), Case.CASE_DOT_EXTENSION), Case.CASE_EXTENSION);
fileChooser.setDragEnabled(false);
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.setMultiSelectionEnabled(false);
fileChooser.setFileFilter(caseMetadataFileFilter);
if (null != ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_BASECASE)) {
fileChooser.setCurrentDirectory(new File(ModuleSettings.getConfigSetting("Case", PROP_BASECASE))); //NON-NLS
}
}
/**
* Pop-up the File Chooser to open the existing case (.aut file)
* Pops up a file chooser to allow the user to select a case meta data file
* (.aut file) and attempts to open the case described by the file.
*
* @param e the action event
* @param e The action event.
*/
@Override
public void actionPerformed(ActionEvent e) {
int retval = fc.showOpenDialog((Component) e.getSource());
/**
* Pop up a file chooser to allow the user to select a case meta data
* file (.aut file)
*/
int retval = fileChooser.showOpenDialog(WindowManager.getDefault().getMainWindow());
if (retval == JFileChooser.APPROVE_OPTION) {
String path = fc.getSelectedFile().getPath();
String dirPath = fc.getSelectedFile().getParent();
ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_BASECASE, dirPath.substring(0, dirPath.lastIndexOf(File.separator)));
// check if the file exists
if (!new File(path).exists()) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"CaseOpenAction.msgDlg.fileNotExist.msg"),
NbBundle.getMessage(this.getClass(),
"CaseOpenAction.msgDlg.fileNotExist.title"),
JOptionPane.ERROR_MESSAGE);
this.actionPerformed(e); // show the dialog box again
} else {
// try to close Startup window if there's one
try {
StartupWindowProvider.getInstance().close();
} catch (Exception ex) {
// no need to show the error message to the user.
logger.log(Level.WARNING, "Error closing startup window.", ex); //NON-NLS
}
try {
Case.open(path); // open the case
} catch (CaseActionException ex) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"CaseOpenAction.msgDlg.cantOpenCase.msg", path,
ex.getMessage()),
NbBundle.getMessage(this.getClass(),
"CaseOpenAction.msgDlg.cantOpenCase.title"),
JOptionPane.ERROR_MESSAGE);
logger.log(Level.WARNING, "Error opening case in folder " + path, ex); //NON-NLS
StartupWindowProvider.getInstance().open();
}
/**
* This is a bit of a hack, but close the startup window, if it was
* the source of the action invocation.
*/
try {
StartupWindowProvider.getInstance().close();
} catch (Exception unused) {
}
/**
* Try to open the caswe associated with the case meta data file the
* user selected.
*/
final String path = fileChooser.getSelectedFile().getPath();
String dirPath = fileChooser.getSelectedFile().getParent();
ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_BASECASE, dirPath.substring(0, dirPath.lastIndexOf(File.separator)));
new Thread(() -> {
try {
Case.open(path);
} catch (CaseActionException ex) {
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null, ex.getMessage(), NbBundle.getMessage(this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"), JOptionPane.ERROR_MESSAGE);
if (!Case.isCaseOpen()) {
StartupWindowProvider.getInstance().open();
}
});
}
}).start();
}
}
}

View File

@ -12,6 +12,12 @@
<xs:element name="Examiner" type="String" nillable="true"/>
<xs:element name="CaseType" type="String" nillable="false"/>
<xs:element name="DatabaseName" type="String" nillable="false"/>
<xs:element name="TextIndexName" type="String" nillable="true"/>
<xs:attribute name="Relative" type="xs:boolean"/>
<xs:element name="CreatedDate" >
@ -92,6 +98,11 @@
<xs:element ref="LogFolder"/>
<xs:element ref="TempFolder"/>
<xs:element ref="CacheFolder"/>
<xs:sequence minOccurs="0" maxOccurs="1">
<xs:element ref="CaseType"/>
<xs:element ref="DatabaseName"/>
<xs:element ref="TextIndexName"/>
</xs:sequence>
</xs:sequence>
</xs:complexType>
</xs:element>

View File

@ -0,0 +1,601 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent;
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceFailedEvent;
import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.autopsy.events.AutopsyEventException;
import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisCompletedEvent;
import org.sleuthkit.autopsy.ingest.events.DataSourceAnalysisStartedEvent;
/**
* A collaboration monitor listens to local events and translates them into
* collaboration tasks that are broadcast to collaborating nodes and informs the
* user of collaboration tasks on other nodes using progress bars.
*/
final class CollaborationMonitor {
private static final String EVENT_CHANNEL_NAME = "%s-Collaboration-Monitor-Events";
private static final String COLLABORATION_MONITOR_EVENT = "COLLABORATION_MONITOR_EVENT";
private static final Set<String> CASE_EVENTS_OF_INTEREST = new HashSet<>(Arrays.asList(new String[]{Case.Events.ADDING_DATA_SOURCE.toString(), Case.Events.DATA_SOURCE_ADDED.toString(), Case.Events.ADDING_DATA_SOURCE_FAILED.toString()}));
private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 2;
private static final String PERIODIC_TASK_THREAD_NAME = "collab-monitor-periodic-tasks-%d";
private static final long HEARTBEAT_INTERVAL_MINUTES = 1;
private static final long MAX_MISSED_HEARTBEATS = 5;
private static final long STALE_TASKS_DETECTION_INTERVAL_MINUTES = 2;
private static final long EXECUTOR_TERMINATION_WAIT_SECS = 30;
private static final Logger logger = Logger.getLogger(CollaborationMonitor.class.getName());
private final String hostName;
private final LocalTasksManager localTasksManager;
private final RemoteTasksManager remoteTasksManager;
private final AutopsyEventPublisher eventPublisher;
private final ScheduledThreadPoolExecutor periodicTasksExecutor;
/**
* Constructs a collaboration monitor that listens to local events and
* translates them into collaboration tasks that are broadcast to
* collaborating nodes, informs the user of collaboration tasks on other
* nodes using progress bars, and monitors the health of key collaboration
* services.
*/
CollaborationMonitor() throws CollaborationMonitorException {
/**
* Get the local host name so it can be used to identify the source of
* collaboration tasks broadcast by this node.
*/
hostName = NetworkUtils.getLocalHostName();
/**
* Create an event publisher that will be used to communicate with
* collaboration monitors on other nodes working on the case.
*/
eventPublisher = new AutopsyEventPublisher();
try {
Case openedCase = Case.getCurrentCase();
String channelPrefix = openedCase.getTextIndexName();
eventPublisher.openRemoteEventChannel(String.format(EVENT_CHANNEL_NAME, channelPrefix));
} catch (AutopsyEventException ex) {
throw new CollaborationMonitorException("Failed to initialize", ex);
}
/**
* Create a remote tasks manager to track and display the progress of
* remote tasks.
*/
remoteTasksManager = new RemoteTasksManager();
eventPublisher.addSubscriber(COLLABORATION_MONITOR_EVENT, remoteTasksManager);
/**
* Create a local tasks manager to track and broadcast local tasks.
*/
localTasksManager = new LocalTasksManager();
IngestManager.getInstance().addIngestJobEventListener(localTasksManager);
Case.addEventSubscriber(CASE_EVENTS_OF_INTEREST, localTasksManager);
/**
* Start periodic tasks that:
*
* 1. Send heartbeats to collaboration monitors on other nodes.<br>
* 2. Check for stale remote tasks.<br>
*/
periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build());
periodicTasksExecutor.scheduleAtFixedRate(new HeartbeatTask(), HEARTBEAT_INTERVAL_MINUTES, HEARTBEAT_INTERVAL_MINUTES, TimeUnit.MINUTES);
periodicTasksExecutor.scheduleAtFixedRate(new StaleTaskDetectionTask(), STALE_TASKS_DETECTION_INTERVAL_MINUTES, STALE_TASKS_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES);
}
/**
* Shuts down this collaboration monitor.
*/
void shutdown() {
if (null != periodicTasksExecutor) {
periodicTasksExecutor.shutdownNow();
try {
while (!periodicTasksExecutor.awaitTermination(EXECUTOR_TERMINATION_WAIT_SECS, TimeUnit.SECONDS)) {
logger.log(Level.WARNING, "Waited at least {0} seconds for periodic tasks executor to shut down, continuing to wait", EXECUTOR_TERMINATION_WAIT_SECS); //NON-NLS
}
} catch (InterruptedException ex) {
logger.log(Level.SEVERE, "Unexpected interrupt while stopping periodic tasks executor", ex); //NON-NLS
}
}
Case.removeEventSubscriber(CASE_EVENTS_OF_INTEREST, localTasksManager);
IngestManager.getInstance().removeIngestJobEventListener(localTasksManager);
if (null != eventPublisher) {
eventPublisher.removeSubscriber(COLLABORATION_MONITOR_EVENT, remoteTasksManager);
eventPublisher.closeRemoteEventChannel();
}
remoteTasksManager.shutdown();
}
/**
* The local tasks manager listens to local events and translates them into
* tasks it broadcasts to collaborating nodes. Note that all access to the
* task collections is synchronized since they may be accessed by both the
* threads publishing property change events and by the heartbeat task
* thread.
*/
private final class LocalTasksManager implements PropertyChangeListener {
private long nextTaskId;
private final Map<Integer, Task> uuidsToAddDataSourceTasks;
private final Map<Long, Task> jobIdsTodataSourceAnalysisTasks;
/**
* Constructs a local tasks manager that listens to local events and
* translates them into tasks that can be broadcast to collaborating
* nodes.
*/
LocalTasksManager() {
nextTaskId = 0;
uuidsToAddDataSourceTasks = new HashMap<>();
jobIdsTodataSourceAnalysisTasks = new HashMap<>();
}
/**
* Translates events into updates of the collection of local tasks this
* node is broadcasting to other nodes.
*
* @param event A PropertyChangeEvent.
*/
@Override
public void propertyChange(PropertyChangeEvent event) {
if (AutopsyEvent.SourceType.LOCAL == ((AutopsyEvent) event).getSourceType()) {
String eventName = event.getPropertyName();
if (eventName.equals(Case.Events.ADDING_DATA_SOURCE.toString())) {
addDataSourceAddTask((AddingDataSourceEvent) event);
} else if (eventName.equals(Case.Events.ADDING_DATA_SOURCE_FAILED.toString())) {
removeDataSourceAddTask(((AddingDataSourceFailedEvent) event).getDataSourceId());
} else if (eventName.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
removeDataSourceAddTask(((DataSourceAddedEvent) event).getDataSourceId());
} else if (eventName.equals(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_STARTED.toString())) {
addDataSourceAnalysisTask((DataSourceAnalysisStartedEvent) event);
} else if (eventName.equals(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED.toString())) {
removeDataSourceAnalysisTask((DataSourceAnalysisCompletedEvent) event);
}
}
}
/**
* Adds an adding data source task to the collection of local tasks and
* publishes the updated collection to any collaborating nodes.
*
* @param event An adding data source event.
*/
synchronized void addDataSourceAddTask(AddingDataSourceEvent event) {
String status = NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.addingDataSourceStatus.msg", hostName);
uuidsToAddDataSourceTasks.put(event.getDataSourceId().hashCode(), new Task(++nextTaskId, status));
eventPublisher.publishRemotely(new CollaborationEvent(hostName, getCurrentTasks()));
}
/**
* Removes an adding data source task from the collection of local tasks
* and publishes the updated collection to any collaborating nodes.
*
* @param dataSourceId A data source id to pair a data source added or
* adding data source failed event with an adding
* data source event.
*/
synchronized void removeDataSourceAddTask(UUID dataSourceId) {
uuidsToAddDataSourceTasks.remove(dataSourceId.hashCode());
eventPublisher.publishRemotely(new CollaborationEvent(hostName, getCurrentTasks()));
}
/**
* Adds a data source analysis task to the collection of local tasks and
* publishes the updated collection to any collaborating nodes.
*
* @param event A data source analysis started event.
*/
synchronized void addDataSourceAnalysisTask(DataSourceAnalysisStartedEvent event) {
String status = NbBundle.getMessage(CollaborationMonitor.class, "CollaborationMonitor.analyzingDataSourceStatus.msg", hostName, event.getDataSource().getName());
jobIdsTodataSourceAnalysisTasks.put(event.getDataSourceIngestJobId(), new Task(++nextTaskId, status));
eventPublisher.publishRemotely(new CollaborationEvent(hostName, getCurrentTasks()));
}
/**
* Removes a data source analysis task from the collection of local
* tasks and publishes the updated collection to any collaborating
* nodes.
*
* @param event A data source analysis completed event.
*/
synchronized void removeDataSourceAnalysisTask(DataSourceAnalysisCompletedEvent event) {
jobIdsTodataSourceAnalysisTasks.remove(event.getDataSourceIngestJobId());
eventPublisher.publishRemotely(new CollaborationEvent(hostName, getCurrentTasks()));
}
/**
* Gets the current local tasks.
*
* @return A mapping of task IDs to tasks, may be empty.
*/
synchronized Map<Long, Task> getCurrentTasks() {
Map<Long, Task> currentTasks = new HashMap<>();
uuidsToAddDataSourceTasks.values().stream().forEach((task) -> {
currentTasks.put(task.getId(), task);
});
jobIdsTodataSourceAnalysisTasks.values().stream().forEach((task) -> {
currentTasks.put(task.getId(), task);
});
return currentTasks;
}
}
/**
* Listens for collaboration event messages broadcast by collaboration
* monitors on other nodes and translates them into remote tasks represented
* locally using progress bars. Note that all access to the remote tasks is
* synchronized since it may be accessed by both the threads publishing
* property change events and by the thread running periodic checks for
* "stale" tasks.
*/
private final class RemoteTasksManager implements PropertyChangeListener {
private final Map<String, RemoteTasks> hostsToTasks;
/**
* Constructs an object that listens for collaboration event messages
* broadcast by collaboration monitors on other nodes and translates
* them into remote tasks represented locally using progress bars.
*/
RemoteTasksManager() {
hostsToTasks = new HashMap<>();
}
/**
* Updates the remote tasks in response to a collaboration event
* received from another node.
*
* @param event The collaboration event.
*/
@Override
public void propertyChange(PropertyChangeEvent event) {
if (event.getPropertyName().equals(COLLABORATION_MONITOR_EVENT)) {
updateTasks((CollaborationEvent) event);
}
}
/**
* Finishes the progress bars for all remote tasks.
*/
synchronized void shutdown() {
finishAllTasks();
}
/**
* Updates the remote tasks to reflect a collaboration event received
* from another node.
*
* @param event The collaboration event.
*/
synchronized void updateTasks(CollaborationEvent event) {
RemoteTasks tasksForHost = hostsToTasks.get(event.getHostName());
if (null != tasksForHost) {
tasksForHost.update(event);
} else {
hostsToTasks.put(event.getHostName(), new RemoteTasks(event));
}
}
/**
* Finishes the progress bars any remote tasks that have gone stale,
* i.e., tasks for which updates have ceased, presumably because the
* collaborating node has gone down or there is a network issue.
*/
synchronized void finishStaleTasks() {
for (Iterator<Map.Entry<String, RemoteTasks>> it = hostsToTasks.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, RemoteTasks> entry = it.next();
RemoteTasks tasksForHost = entry.getValue();
if (tasksForHost.isStale()) {
tasksForHost.finishAllTasks();
it.remove();
}
}
}
/**
* Finishes the progress bars for all remote tasks.
*/
synchronized void finishAllTasks() {
for (Iterator<Map.Entry<String, RemoteTasks>> it = hostsToTasks.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, RemoteTasks> entry = it.next();
RemoteTasks tasksForHost = entry.getValue();
tasksForHost.finishAllTasks();
it.remove();
}
}
/**
* A collection of progress bars for tasks on a collaborating node.
*/
private final class RemoteTasks {
private final long MAX_MINUTES_WITHOUT_UPDATE = HEARTBEAT_INTERVAL_MINUTES * MAX_MISSED_HEARTBEATS;
private Instant lastUpdateTime;
private Map<Long, ProgressHandle> taskIdsToProgressBars;
/**
* Construct a set of progress bars to represent remote tasks for a
* particular host.
*
* @param event A collaboration event.
*/
RemoteTasks(CollaborationEvent event) {
/**
* Set the initial value of the last update time stamp.
*/
lastUpdateTime = Instant.now();
taskIdsToProgressBars = new HashMap<>();
event.getCurrentTasks().values().stream().forEach((task) -> {
ProgressHandle progress = ProgressHandleFactory.createHandle(event.getHostName());
progress.start();
progress.progress(task.getStatus());
taskIdsToProgressBars.put(task.getId(), progress);
});
}
/**
* Updates this remote tasks collection.
*
* @param event A collaboration event from the collaborating node
* associated with these tasks.
*/
void update(CollaborationEvent event) {
/**
* Update the last update timestamp.
*/
lastUpdateTime = Instant.now();
/**
* Create or update the progress bars for the current tasks of
* the node that published the event.
*/
Map<Long, Task> remoteTasks = event.getCurrentTasks();
remoteTasks.values().stream().forEach((task) -> {
ProgressHandle progress = taskIdsToProgressBars.get(task.getId());
if (null != progress) {
/**
* Update the existing progress bar.
*/
progress.progress(task.getStatus());
} else {
/**
* A new task, create a progress bar.
*/
progress = ProgressHandleFactory.createHandle(event.getHostName());
progress.start();
progress.progress(task.getStatus());
taskIdsToProgressBars.put(task.getId(), progress);
}
});
/**
* If a task is no longer in the task list from the remote node,
* it is finished. Remove the progress bars for finished tasks.
*/
for (Iterator<Map.Entry<Long, ProgressHandle>> iterator = taskIdsToProgressBars.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<Long, ProgressHandle> entry = iterator.next();
if (!remoteTasks.containsKey(entry.getKey())) {
ProgressHandle progress = entry.getValue();
progress.finish();
iterator.remove();
}
}
}
/**
* Unconditionally finishes the entire set or remote tasks. To be
* used when a host drops off unexpectedly.
*/
void finishAllTasks() {
taskIdsToProgressBars.values().stream().forEach((progress) -> {
progress.finish();
});
taskIdsToProgressBars.clear();
}
/**
* Determines whether or not the time since the last update of this
* remote tasks collection is greater than the maximum acceptable
* interval between updates.
*
* @return True or false.
*/
boolean isStale() {
return Duration.between(lastUpdateTime, Instant.now()).toMinutes() >= MAX_MINUTES_WITHOUT_UPDATE;
}
}
}
/**
* A Runnable task that periodically publishes the local tasks in progress
* on this node, providing a heartbeat message for collaboration monitors on
* other nodes. The current local tasks are included in the heartbeat
* message so that nodes that have just joined the event channel know what
* this node is doing, even if they join after the current tasks are begun.
*/
private final class HeartbeatTask implements Runnable {
/**
* Publish a heartbeat message.
*/
@Override
public void run() {
eventPublisher.publishRemotely(new CollaborationEvent(hostName, localTasksManager.getCurrentTasks()));
}
}
/**
* A Runnable task that periodically deals with any remote tasks that have
* gone stale, i.e., tasks for which updates have ceased, presumably because
* the collaborating node has gone down or there is a network issue.
*/
private final class StaleTaskDetectionTask implements Runnable {
/**
* Check for stale remote tasks and clean them up, if found.
*/
@Override
public void run() {
remoteTasksManager.finishStaleTasks();
}
}
/**
* An Autopsy event to be sent in event messages to the collaboration
* monitors on other Autopsy nodes.
*/
private final static class CollaborationEvent extends AutopsyEvent implements Serializable {
private static final long serialVersionUID = 1L;
private final String hostName;
private final Map<Long, Task> currentTasks;
/**
* Constructs an Autopsy event to be sent in event messages to the
* collaboration monitors on other Autopsy nodes.
*
* @param hostName The name of the host sending the event.
* @param currentTasks The tasks in progress for this Autopsy node.
*/
CollaborationEvent(String hostName, Map<Long, Task> currentTasks) {
super(COLLABORATION_MONITOR_EVENT, null, null);
this.hostName = hostName;
this.currentTasks = currentTasks;
}
/**
* Gets the host name of the Autopsy node that published this event.
*
* @return The host name.
*/
String getHostName() {
return hostName;
}
/**
* Gets the current tasks for the Autopsy node that published this
* event.
*
* @return A mapping of task IDs to current tasks
*/
Map<Long, Task> getCurrentTasks() {
return currentTasks;
}
}
/**
* A representation of a task in progress on this Autopsy node.
*/
private final static class Task implements Serializable {
private static final long serialVersionUID = 1L;
private final long id;
private final String status;
/**
* Constructs a representation of a task in progress on this Autopsy
* node.
*
* @param id
* @param status
*/
Task(long id, String status) {
this.id = id;
this.status = status;
}
/**
* Gets ID of this task.
*
* @return A task id, unique to this task for this case and this Autopsy
* node.
*/
long getId() {
return id;
}
/**
* Gets the status of the task at the time this object was constructed.
*
* @return A task status string.
*/
String getStatus() {
return status;
}
}
/**
* Custom exception class for the collaboration monitor.
*/
final static class CollaborationMonitorException extends Exception {
/**
* Constructs and instance of the custom exception class for the
* collaboration monitor.
*
* @param message Exception message.
*/
CollaborationMonitorException(String message) {
super(message);
}
/**
* Constructs and instance of the custom exception class for the
* collaboration monitor.
*
* @param message Exception message.
* @param throwable Exception cause.
*/
CollaborationMonitorException(String message, Throwable throwable) {
super(message, throwable);
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,16 +18,18 @@
*/
package org.sleuthkit.autopsy.casemodule;
import java.awt.*;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
@ -42,7 +44,6 @@ public class CueBannerPanel extends javax.swing.JPanel {
// for error handling
private static JPanel caller = new JPanel();
private String className = this.getClass().toString();
public CueBannerPanel() {
initComponents();
@ -209,6 +210,10 @@ public class CueBannerPanel extends javax.swing.JPanel {
// set the location of the popUp Window on the center of the screen
recentCasesWindow.setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2);
recentCasesWindow.setLocationRelativeTo(this);
recentCasesWindow.getRootPane().registerKeyboardAction(e -> {
recentCasesWindow.dispose();
}, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
OpenRecentCasePanel welcomeWindow = OpenRecentCasePanel.getInstance();

View File

@ -43,6 +43,7 @@
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="errorLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="20" max="32767" attributes="0"/>
</Group>
@ -57,7 +58,9 @@
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="pathTextField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="1" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="timeZoneLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="timeZoneComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
@ -66,7 +69,7 @@
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="13" max="32767" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -131,5 +134,15 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="errorLabel">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.errorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -37,6 +37,7 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PathValidator;
/**
* ImageTypePanel for adding an image file such as .img, .E0x, .00x, etc.
@ -65,6 +66,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setMultiSelectionEnabled(false);
errorLabel.setVisible(false);
boolean firstFilter = true;
for (FileFilter filter : fileChooserFilters) {
if (firstFilter) { // set the first on the list as the default selection
@ -115,6 +118,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
timeZoneComboBox = new javax.swing.JComboBox<String>();
noFatOrphansCheckbox = new javax.swing.JCheckBox();
descLabel = new javax.swing.JLabel();
errorLabel = new javax.swing.JLabel();
setMinimumSize(new java.awt.Dimension(0, 65));
setPreferredSize(new java.awt.Dimension(403, 65));
@ -139,6 +143,9 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.descLabel.text")); // NOI18N
errorLabel.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.errorLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@ -158,7 +165,8 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
.addComponent(noFatOrphansCheckbox)
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addComponent(descLabel)))
.addComponent(descLabel))
.addComponent(errorLabel))
.addGap(0, 20, Short.MAX_VALUE))
);
layout.setVerticalGroup(
@ -169,7 +177,9 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(browseButton)
.addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
.addGap(3, 3, 3)
.addComponent(errorLabel)
.addGap(1, 1, 1)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(timeZoneLabel)
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
@ -177,7 +187,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
.addComponent(noFatOrphansCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(descLabel)
.addContainerGap(13, Short.MAX_VALUE))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
@ -208,6 +218,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton browseButton;
private javax.swing.JLabel descLabel;
private javax.swing.JLabel errorLabel;
private javax.swing.JCheckBox noFatOrphansCheckbox;
private javax.swing.JLabel pathLabel;
private javax.swing.JTextField pathTextField;
@ -252,11 +263,15 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
* @return true if a proper image has been selected, false otherwise
*/
public boolean validatePanel() {
errorLabel.setVisible(false);
String path = getContentPaths();
if (path == null || path.isEmpty()) {
return false;
}
// display warning if there is one (but don't disable "next" button)
warnIfPathIsInvalid(path);
boolean isExist = Case.pathExists(path);
boolean isPhysicalDrive = Case.isPhysicalDrive(path);
boolean isPartition = Case.isPartition(path);
@ -264,6 +279,19 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
return (isExist || isPhysicalDrive || isPartition);
}
/**
* Validates path to selected data source and displays warning if it is
* invalid.
*
* @param path Absolute path to the selected data source
*/
private void warnIfPathIsInvalid(String path) {
if (!PathValidator.isValid(path, Case.getCurrentCase().getCaseType())) {
errorLabel.setVisible(true);
errorLabel.setText(NbBundle.getMessage(this.getClass(), "DataSourceOnCDriveError.text"));
}
}
public void storeSettings() {
String imagePathName = getContentPaths();
if (null != imagePathName) {

View File

@ -0,0 +1,6 @@
package org.sleuthkit.autopsy.casemodule;
public interface ImportDoneCallback {
void importDoneCallback(boolean result, String resultString);
}

View File

@ -0,0 +1,92 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
/**
* This class enables capturing errors and batching them for reporting on a
* no-more-than-x number of seconds basis. When created, you specify the minimum
* time between user notifications. When the time between notifications has
* expired, the next error encountered will cause a report to be shown to the
* user.
*/
class IntervalErrorReportData {
private final Case currentCase;
private long newProblems;
private long totalProblems;
private long lastReportedDate;
private final int milliSecondsBetweenReports;
private final String message;
/**
* Create a new IntervalErrorReprotData instance and subscribe for TSK error
* notifications for the current case.
*
* @param currentCase Case for which TSK errors should be tracked
* and displayed.
* @param secondsBetweenReports Minimum number of seconds between reports.
* It will not warn more frequently than this.
* @param message The message that will be shown when warning
* the user
*/
IntervalErrorReportData(Case currentCase, int secondsBetweenReports, String message) {
this.newProblems = 0;
this.totalProblems = 0;
this.lastReportedDate = 0; // arm the first warning by choosing zero
this.milliSecondsBetweenReports = secondsBetweenReports * 1000; // convert to milliseconds
this.message = message;
this.currentCase = currentCase;
this.currentCase.getSleuthkitCase().addErrorObserver(this.currentCase);
}
/**
* Un-subscribe from TSK error notifications for current case.
*/
void shutdown() {
this.currentCase.getSleuthkitCase().removeErrorObserver(this.currentCase);
}
/**
* Call this to add problems to the class. When the time threshold is met
* (or if this is the first problem encountered), a warning will be shown to
* the user.
*
* @param context The context in which the error occurred.
* @param errorMessage A description of the error that occurred.
*/
void addProblems(String context, String errorMessage) {
this.newProblems += 1;
this.totalProblems += newProblems;
long currentTimeStamp = System.currentTimeMillis();
if ((currentTimeStamp - lastReportedDate) > milliSecondsBetweenReports) {
this.lastReportedDate = currentTimeStamp;
MessageNotifyUtil.Notify.error(message, context + ", " + errorMessage + " "
+ this.newProblems + " "
+ NbBundle.getMessage(IntervalErrorReportData.class, "IntervalErrorReport.NewIssues")
+ " " + this.totalProblems + " "
+ NbBundle.getMessage(IntervalErrorReportData.class, "IntervalErrorReport.TotalIssues")
+ ".");
this.newProblems = 0;
}
}
}

View File

@ -61,7 +61,7 @@
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="21" max="32767" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>

View File

@ -93,9 +93,9 @@ final class LocalDiskPanel extends JPanel {
diskComboBox.setModel(model);
diskComboBox.setRenderer(model);
errorLabel.setVisible(false);
errorLabel.setText("");
diskComboBox.setEnabled(false);
}
/**
@ -167,7 +167,7 @@ final class LocalDiskPanel extends JPanel {
.addComponent(noFatOrphansCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(descLabel)
.addContainerGap(21, Short.MAX_VALUE))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables

View File

@ -60,6 +60,10 @@
</Group>
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
@ -67,15 +71,16 @@
<Group type="102" alignment="0" attributes="0">
<Component id="infoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="jScrollPane2" min="-2" pref="82" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Component id="selectButton" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="17" max="32767" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="clearButton" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="jScrollPane2" pref="0" max="32767" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -136,5 +141,15 @@
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="errorLabel">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalFilesPanel.errorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.casemodule;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.JFileChooser;
@ -30,7 +32,9 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PathValidator;
/**
* Add input wizard subpanel for adding local files / dirs to the case
@ -61,8 +65,8 @@ class LocalFilesPanel extends JPanel {
private void customInit() {
localFileChooser.setMultiSelectionEnabled(true);
errorLabel.setVisible(false);
selectedPaths.setText("");
}
//@Override
@ -93,9 +97,35 @@ class LocalFilesPanel extends JPanel {
//@Override
public boolean validatePanel() {
// display warning if there is one (but don't disable "next" button)
warnIfPathIsInvalid(getContentPaths());
return enableNext;
}
/**
* Validates path to selected data source and displays warning if it is
* invalid.
*
* @param path Absolute path to the selected data source
*/
private void warnIfPathIsInvalid(String path) {
errorLabel.setVisible(false);
// Path variable for "Local files" module is a coma separated string containg multiple paths
List<String> pathsList = Arrays.asList(path.split(","));
CaseType currentCaseType = Case.getCurrentCase().getCaseType();
for (String currentPath : pathsList) {
if (!PathValidator.isValid(currentPath, currentCaseType)) {
errorLabel.setVisible(true);
errorLabel.setText(NbBundle.getMessage(this.getClass(), "DataSourceOnCDriveError.text"));
return;
}
}
}
//@Override
public void select() {
reset();
@ -106,8 +136,7 @@ class LocalFilesPanel extends JPanel {
currentFiles.clear();
selectedPaths.setText("");
enableNext = false;
//pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
errorLabel.setVisible(false);
}
@Override
@ -150,6 +179,7 @@ class LocalFilesPanel extends JPanel {
clearButton = new javax.swing.JButton();
jScrollPane2 = new javax.swing.JScrollPane();
selectedPaths = new javax.swing.JTextArea();
errorLabel = new javax.swing.JLabel();
localFileChooser.setApproveButtonText(org.openide.util.NbBundle.getMessage(LocalFilesPanel.class, "LocalFilesPanel.localFileChooser.approveButtonText")); // NOI18N
localFileChooser.setApproveButtonToolTipText(org.openide.util.NbBundle.getMessage(LocalFilesPanel.class, "LocalFilesPanel.localFileChooser.approveButtonToolTipText")); // NOI18N
@ -185,6 +215,9 @@ class LocalFilesPanel extends JPanel {
selectedPaths.setToolTipText(org.openide.util.NbBundle.getMessage(LocalFilesPanel.class, "LocalFilesPanel.selectedPaths.toolTipText")); // NOI18N
jScrollPane2.setViewportView(selectedPaths);
errorLabel.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(LocalFilesPanel.class, "LocalFilesPanel.errorLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@ -199,19 +232,23 @@ class LocalFilesPanel extends JPanel {
.addComponent(selectButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(clearButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGap(2, 2, 2))
.addGroup(layout.createSequentialGroup()
.addComponent(errorLabel)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(infoLabel)
.addGap(5, 5, 5)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createSequentialGroup()
.addComponent(selectButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 17, Short.MAX_VALUE)
.addComponent(clearButton))
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
.addGap(0, 0, 0))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(clearButton)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(errorLabel))
);
}// </editor-fold>//GEN-END:initComponents
@ -256,6 +293,7 @@ class LocalFilesPanel extends JPanel {
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton clearButton;
private javax.swing.JLabel errorLabel;
private javax.swing.JLabel infoLabel;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;

View File

@ -112,10 +112,15 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="pathNameTextField" min="-2" pref="285" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="browseButton" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="83" max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lbWarning" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="pathNameTextField" min="-2" pref="285" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="browseButton" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="83" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
</DimensionLayout>
@ -127,7 +132,9 @@
<Component id="pathNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="62" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="lbWarning" pref="19" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -153,6 +160,22 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lbWarning">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="1"/>
</Property>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="f4" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MissingImageDialog.lbWarning.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MissingImageDialog.lbWarning.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="titleLabel">

View File

@ -137,6 +137,7 @@ class MissingImageDialog extends javax.swing.JDialog {
containerPanel = new javax.swing.JPanel();
pathNameTextField = new javax.swing.JTextField();
browseButton = new javax.swing.JButton();
lbWarning = new javax.swing.JLabel();
titleLabel = new javax.swing.JLabel();
titleSeparator = new javax.swing.JSeparator();
@ -191,16 +192,24 @@ class MissingImageDialog extends javax.swing.JDialog {
}
});
lbWarning.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
lbWarning.setForeground(new java.awt.Color(244, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(lbWarning, org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.lbWarning.text")); // NOI18N
lbWarning.setToolTipText(org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.lbWarning.toolTipText")); // NOI18N
javax.swing.GroupLayout containerPanelLayout = new javax.swing.GroupLayout(containerPanel);
containerPanel.setLayout(containerPanelLayout);
containerPanelLayout.setHorizontalGroup(
containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(containerPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(pathNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 285, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(browseButton)
.addContainerGap(83, Short.MAX_VALUE))
.addGroup(containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lbWarning, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(containerPanelLayout.createSequentialGroup()
.addComponent(pathNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 285, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(browseButton)
.addContainerGap(83, Short.MAX_VALUE))))
);
containerPanelLayout.setVerticalGroup(
containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -209,12 +218,13 @@ class MissingImageDialog extends javax.swing.JDialog {
.addGroup(containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(pathNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(browseButton))
.addContainerGap(62, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(lbWarning, javax.swing.GroupLayout.DEFAULT_SIZE, 19, Short.MAX_VALUE)
.addGap(18, 18, 18))
);
titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, 12));
org.openide.awt.Mnemonics.setLocalizedText(titleLabel, org.openide.util.NbBundle
.getMessage(MissingImageDialog.class, "MissingImageDialog.titleLabel.text")); // NOI18N
titleLabel.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(titleLabel, org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.titleLabel.text")); // NOI18N
titleSeparator.setForeground(new java.awt.Color(102, 102, 102));
@ -254,10 +264,11 @@ class MissingImageDialog extends javax.swing.JDialog {
String newPath = pathNameTextField.getText();
//TODO handle local files
db.setImagePaths(obj_id, Arrays.asList(new String[]{newPath}));
this.dispose();
} catch (TskCoreException ex) {
lbWarning.setText(NbBundle.getMessage(this.getClass(), "MissingImageDialog.ErrorSettingImage"));
logger.log(Level.WARNING, "Error setting image paths", ex); //NON-NLS
}
this.dispose();
}//GEN-LAST:event_selectButtonActionPerformed
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
@ -273,7 +284,7 @@ class MissingImageDialog extends javax.swing.JDialog {
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
String oldText = pathNameTextField.getText();
lbWarning.setText("");
// set the current directory of the FileChooser if the ImagePath Field is valid
File currentDir = new File(oldText);
if (currentDir.exists()) {
@ -294,6 +305,7 @@ class MissingImageDialog extends javax.swing.JDialog {
private javax.swing.JPanel buttonPanel;
private javax.swing.JButton cancelButton;
private javax.swing.JPanel containerPanel;
private javax.swing.JLabel lbWarning;
private javax.swing.JTextField pathNameTextField;
private javax.swing.JButton selectButton;
private javax.swing.JLabel titleLabel;

View File

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="javax.swing.ButtonGroup" name="caseTypeButtonGroup">
</Component>
</NonVisualComponents>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
@ -16,30 +20,49 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="caseDirLabel" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="caseDirTextField" alignment="0" max="32767" attributes="1"/>
<Group type="102" alignment="0" attributes="0">
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="227" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="caseDirLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="caseParentDirTextField" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="caseNameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
<Component id="caseNameTextField" max="32767" attributes="0"/>
</Group>
<Component id="multiUserSettingsWarningLabel" alignment="1" max="32767" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="caseParentDirTextField" min="-2" pref="296" max="-2" attributes="0"/>
<Component id="caseDirBrowseButton" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="caseNameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="caseNameTextField" min="-2" pref="296" max="-2" attributes="0"/>
</Group>
<Component id="caseDirTextField" alignment="0" min="-2" pref="380" max="-2" attributes="1"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="caseDirBrowseButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="singleUserCaseRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="multiUserCaseRadioButton" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="caseParentDirWarningLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -63,7 +86,16 @@
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="caseDirTextField" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="32" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="singleUserCaseRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="multiUserCaseRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="caseParentDirWarningLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="1" max="-2" attributes="0"/>
<Component id="multiUserSettingsWarningLabel" min="-2" pref="23" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -132,5 +164,51 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="singleUserCaseRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="caseTypeButtonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="NewCaseVisualPanel1.singleUserCaseRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="singleUserCaseRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="multiUserCaseRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="caseTypeButtonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="NewCaseVisualPanel1.multiUserCaseRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="multiUserCaseRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="multiUserSettingsWarningLabel">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="NewCaseVisualPanel1.multiUserSettingsWarningLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="caseParentDirWarningLabel">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="NewCaseVisualPanel1.caseParentDirWarningLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -24,25 +24,51 @@ import java.awt.*;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.PathValidator;
/**
* The wizard panel for the new case creation.
*
* @author jantonius
* The JPanel for the first page of the new case wizard.
*/
final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
private JFileChooser fc = new JFileChooser();
private NewCaseWizardPanel1 wizPanel;
private final JFileChooser fileChooser = new JFileChooser();
private final NewCaseWizardPanel1 wizPanel;
/**
* Constructs the JPanel for the first page of the new case wizard.
*
* @param wizPanel The wizard panmel that owns this panel.
*/
NewCaseVisualPanel1(NewCaseWizardPanel1 wizPanel) {
initComponents();
this.wizPanel = wizPanel;
caseNameTextField.getDocument().addDocumentListener(this);
caseParentDirTextField.getDocument().addDocumentListener(this);
initComponents();
TextFieldListener listener = new TextFieldListener();
caseNameTextField.getDocument().addDocumentListener(listener);
caseParentDirTextField.getDocument().addDocumentListener(listener);
caseParentDirWarningLabel.setVisible(false);
}
/**
* Should be called by the readSettings() of the wizard panel that owns this
* UI panel so that this panel can read settings for each invocation of the
* wizard as well.
*/
void readSettings() {
caseNameTextField.setText("");
if (UserPreferences.getIsMultiUserModeEnabled()) {
multiUserCaseRadioButton.setEnabled(true);
multiUserCaseRadioButton.setSelected(true);
multiUserSettingsWarningLabel.setVisible(false);
} else {
multiUserCaseRadioButton.setEnabled(false);
singleUserCaseRadioButton.setSelected(true);
multiUserSettingsWarningLabel.setText(NbBundle.getMessage(this.getClass(), "NewCaseVisualPanel1.MultiUserDisabled.text"));
}
validateSettings();
}
/**
@ -61,27 +87,112 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
*
* @return caseName the case name from the case name text field
*/
public String getCaseName() {
String getCaseName() {
return this.caseNameTextField.getText();
}
/**
* Allows the the wizard panel that owns this UI panel to set the base case
* directory to a persisted vlaue.
*
* @param caseParentDir The persisted path to the base case directory.
*/
void setCaseParentDir(String caseParentDir) {
caseParentDirTextField.setText(caseParentDir);
validateSettings();
}
/**
* Gets the base directory that the user typed on the base directory text
* field. Will add file separator if it was not added.
*
* @return baseDirectory the base directory from the case dir text field
*/
public String getCaseParentDir() {
String getCaseParentDir() {
String parentDir = this.caseParentDirTextField.getText();
if (parentDir.endsWith(File.separator) == false) {
parentDir = parentDir + File.separator;
}
return parentDir;
}
public JTextField getCaseParentDirTextField() {
return this.caseParentDirTextField;
/**
* Gets the case type.
*
* @return CaseType as set via radio buttons
*/
CaseType getCaseType() {
CaseType value = CaseType.SINGLE_USER_CASE;
if (singleUserCaseRadioButton.isSelected()) {
value = CaseType.SINGLE_USER_CASE;
} else if (multiUserCaseRadioButton.isSelected()) {
value = CaseType.MULTI_USER_CASE;
}
return value;
}
/**
* Called when the user interacts with a child UI component of this panel,
* this method notifies the wizard panel that owns this panel and then
* validates the user's settings.
*/
private void handleUpdate() {
wizPanel.fireChangeEvent();
validateSettings();
}
/**
* Does validation of the current settings and enables or disables the
* "Next" button of the wizard panel that owns this panel.
*/
private void validateSettings() {
/**
* Check the base case directory for the selected case type and show a
* warning if it is a dubious choice.
*/
caseParentDirWarningLabel.setVisible(false);
String parentDir = getCaseParentDir();
if (!PathValidator.isValid(parentDir, getCaseType())) {
caseParentDirWarningLabel.setVisible(true);
caseParentDirWarningLabel.setText(NbBundle.getMessage(this.getClass(), "NewCaseVisualPanel1.CaseFolderOnCDriveError.text"));
}
/**
* Enable the "Next" button for the wizard if there is text entered for
* the case name and base case directory. Also make sure that multi-user
* cases are enabled if the multi-user case radio button is selected.
*/
String caseName = getCaseName();
if (!caseName.equals("") && !parentDir.equals("")) {
caseDirTextField.setText(parentDir + caseName);
wizPanel.setIsFinish(true);
} else {
caseDirTextField.setText("");
wizPanel.setIsFinish(false);
}
}
/**
* Handles validation when the user provides input to text field components
* of this panel.
*/
private class TextFieldListener implements DocumentListener {
@Override
public void insertUpdate(DocumentEvent e) {
handleUpdate();
}
@Override
public void removeUpdate(DocumentEvent e) {
handleUpdate();
}
@Override
public void changedUpdate(DocumentEvent e) {
handleUpdate();
}
}
/**
@ -92,6 +203,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
caseTypeButtonGroup = new javax.swing.ButtonGroup();
jLabel1 = new javax.swing.JLabel();
caseNameLabel = new javax.swing.JLabel();
caseDirLabel = new javax.swing.JLabel();
@ -100,10 +212,13 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
caseDirBrowseButton = new javax.swing.JButton();
jLabel2 = new javax.swing.JLabel();
caseDirTextField = new javax.swing.JTextField();
singleUserCaseRadioButton = new javax.swing.JRadioButton();
multiUserCaseRadioButton = new javax.swing.JRadioButton();
multiUserSettingsWarningLabel = new javax.swing.JLabel();
caseParentDirWarningLabel = new javax.swing.JLabel();
jLabel1.setFont(jLabel1.getFont().deriveFont(Font.BOLD, 14));
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle
.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.jLabel1.text_1")); // NOI18N
jLabel1.setFont(new java.awt.Font("Tahoma", 1, 14)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.jLabel1.text_1")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(caseNameLabel, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.caseNameLabel.text_1")); // NOI18N
@ -125,6 +240,28 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
caseDirTextField.setEditable(false);
caseDirTextField.setText(org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.caseDirTextField.text_1")); // NOI18N
caseTypeButtonGroup.add(singleUserCaseRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(singleUserCaseRadioButton, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.singleUserCaseRadioButton.text")); // NOI18N
singleUserCaseRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
singleUserCaseRadioButtonActionPerformed(evt);
}
});
caseTypeButtonGroup.add(multiUserCaseRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(multiUserCaseRadioButton, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.multiUserCaseRadioButton.text")); // NOI18N
multiUserCaseRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
multiUserCaseRadioButtonActionPerformed(evt);
}
});
multiUserSettingsWarningLabel.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(multiUserSettingsWarningLabel, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.multiUserSettingsWarningLabel.text")); // NOI18N
caseParentDirWarningLabel.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(caseParentDirWarningLabel, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.caseParentDirWarningLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@ -132,22 +269,35 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel2)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(jLabel1, javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(caseDirLabel)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel2)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(caseDirTextField, javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(jLabel1)
.addGap(0, 227, Short.MAX_VALUE))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(caseDirLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(caseParentDirTextField))
.addGroup(layout.createSequentialGroup()
.addComponent(caseNameLabel)
.addGap(26, 26, 26)
.addComponent(caseNameTextField))
.addComponent(multiUserSettingsWarningLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(caseParentDirTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(caseNameLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(caseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(caseDirTextField, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 380, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(caseDirBrowseButton)))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(caseDirBrowseButton)))
.addContainerGap())
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(singleUserCaseRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(multiUserCaseRadioButton))
.addComponent(caseParentDirWarningLabel))
.addGap(0, 0, Short.MAX_VALUE))))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -167,7 +317,15 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(caseDirTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(32, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(singleUserCaseRadioButton)
.addComponent(multiUserCaseRadioButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(caseParentDirWarningLabel)
.addGap(1, 1, 1)
.addComponent(multiUserSettingsWarningLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
@ -179,23 +337,27 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
* @param evt the action event
*/
private void caseDirBrowseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_caseDirBrowseButtonActionPerformed
// show the directory chooser where the case directory will be created
fc.setDragEnabled(false);
fileChooser.setDragEnabled(false);
if (!caseParentDirTextField.getText().trim().equals("")) {
fc.setCurrentDirectory(new File(caseParentDirTextField.getText()));
fileChooser.setCurrentDirectory(new File(caseParentDirTextField.getText()));
}
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
//fc.setSelectedFile(new File("C:\\Program Files\\"));
//disableTextField(fc); // disable all the text field on the file chooser
int returnValue = fc.showDialog((Component) evt.getSource(), NbBundle.getMessage(this.getClass(),
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int choice = fileChooser.showDialog((Component) evt.getSource(), NbBundle.getMessage(this.getClass(),
"NewCaseVisualPanel1.caseDirBrowse.selectButton.text"));
if (returnValue == JFileChooser.APPROVE_OPTION) {
String path = fc.getSelectedFile().getPath();
caseParentDirTextField.setText(path); // put the path to the textfield
if (JFileChooser.APPROVE_OPTION == choice) {
String path = fileChooser.getSelectedFile().getPath();
caseParentDirTextField.setText(path);
}
}//GEN-LAST:event_caseDirBrowseButtonActionPerformed
private void singleUserCaseRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_singleUserCaseRadioButtonActionPerformed
handleUpdate();
}//GEN-LAST:event_singleUserCaseRadioButtonActionPerformed
private void multiUserCaseRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_multiUserCaseRadioButtonActionPerformed
handleUpdate();
}//GEN-LAST:event_multiUserCaseRadioButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton caseDirBrowseButton;
private javax.swing.JLabel caseDirLabel;
@ -203,8 +365,13 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
private javax.swing.JLabel caseNameLabel;
private javax.swing.JTextField caseNameTextField;
private javax.swing.JTextField caseParentDirTextField;
private javax.swing.JLabel caseParentDirWarningLabel;
private javax.swing.ButtonGroup caseTypeButtonGroup;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JRadioButton multiUserCaseRadioButton;
private javax.swing.JLabel multiUserSettingsWarningLabel;
private javax.swing.JRadioButton singleUserCaseRadioButton;
// End of variables declaration//GEN-END:variables
/**

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2014 Basis Technology Corp.
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -24,6 +24,8 @@ import java.io.File;
import java.text.MessageFormat;
import java.util.logging.Level;
import javax.swing.JComponent;
import javax.swing.SwingWorker;
import javax.swing.SwingUtilities;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
@ -33,6 +35,12 @@ import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction;
import org.openide.util.actions.SystemAction;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JOptionPane;
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskData.DbType;
/**
* Action to open the New Case wizard.
@ -74,7 +82,7 @@ final class NewCaseWizardAction extends CallableSystemAction {
* The method to perform new case creation
*/
private void newCaseAction() {
WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
final WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
// {0} will be replaced by WizardDesriptor.Panel.getComponent().getName()
wizardDescriptor.setTitleFormat(new MessageFormat("{0}"));
wizardDescriptor.setTitle(NbBundle.getMessage(this.getClass(), "NewCaseWizardAction.newCase.windowTitle.text"));
@ -82,32 +90,67 @@ final class NewCaseWizardAction extends CallableSystemAction {
dialog.setVisible(true);
dialog.toFront();
boolean finished = wizardDescriptor.getValue() == WizardDescriptor.FINISH_OPTION; // check if it finishes (it's not cancelled)
boolean isCancelled = wizardDescriptor.getValue() == WizardDescriptor.CANCEL_OPTION; // check if the "Cancel" button is pressed
if (wizardDescriptor.getValue() == WizardDescriptor.FINISH_OPTION) {
new SwingWorker<Void, Void>() {
// if the finish button is pressed (not cancelled)
if (finished) {
// now start the 'Add Image' wizard
//TODO fix for local
AddImageAction addImageAction = SystemAction.get(AddImageAction.class);
addImageAction.actionPerformed(null);
}
@Override
protected Void doInBackground() throws Exception {
// Create case.
// if Cancel button is pressed
if (isCancelled) {
String createdDirectory = (String) wizardDescriptor.getProperty("createdDirectory"); //NON-NLS
if (createdDirectory != null) {
logger.log(Level.INFO, "Deleting a created case directory due to isCancelled set, dir: " + createdDirectory); //NON-NLS
Case.deleteCaseDirectory(new File(createdDirectory));
}
// if there's case opened, close the case
if (Case.existsCurrentCase()) {
// close the previous case if there's any
CaseCloseAction closeCase = SystemAction.get(CaseCloseAction.class);
closeCase.actionPerformed(null);
}
String caseNumber = (String) wizardDescriptor.getProperty("caseNumber"); //NON-NLS
String examiner = (String) wizardDescriptor.getProperty("caseExaminer"); //NON-NLS
final String caseName = (String) wizardDescriptor.getProperty("caseName"); //NON-NLS
String createdDirectory = (String) wizardDescriptor.getProperty("createdDirectory"); //NON-NLS
CaseType caseType = CaseType.values()[(int) wizardDescriptor.getProperty("caseType")]; //NON-NLS
Case.create(createdDirectory, caseName, caseNumber, examiner, caseType);
return null;
}
@Override
protected void done() {
try {
get();
CaseType currentCaseType = CaseType.values()[(int) wizardDescriptor.getProperty("caseType")]; //NON-NLS
CaseDbConnectionInfo info = UserPreferences.getDatabaseConnectionInfo();
if ((currentCaseType == CaseType.SINGLE_USER_CASE) || ((info.getDbType() != DbType.SQLITE) && SleuthkitCase.tryConnectOld(info.getHost(), info.getPort(), info.getUserName(), info.getPassword(), info.getDbType()))) {
AddImageAction addImageAction = SystemAction.get(AddImageAction.class);
addImageAction.actionPerformed(null);
} else {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(), "NewCaseWizardAction.databaseProblem1.text"),
NbBundle.getMessage(this.getClass(), "NewCaseWizardAction.databaseProblem2.text"),
JOptionPane.ERROR_MESSAGE);
doFailedCaseCleanup(wizardDescriptor);
}
} catch (Exception ex) {
final String caseName = (String) wizardDescriptor.getProperty("caseName"); //NON-NLS
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(),
"CaseCreateAction.msgDlg.cantCreateCase.msg") + " " + caseName,
NbBundle.getMessage(this.getClass(),
"CaseOpenAction.msgDlg.cantOpenCase.title"),
JOptionPane.ERROR_MESSAGE);
});
doFailedCaseCleanup(wizardDescriptor);
}
}
}.execute();
} else {
new Thread(() -> {
doFailedCaseCleanup(wizardDescriptor);
}).start();
}
}
private void doFailedCaseCleanup(WizardDescriptor wizardDescriptor) {
String createdDirectory = (String) wizardDescriptor.getProperty("createdDirectory"); //NON-NLS
if (createdDirectory != null) {
logger.log(Level.INFO, "Deleting a created case directory due to an error, dir: {0}", createdDirectory); //NON-NLS
Case.deleteCaseDirectory(new File(createdDirectory));
}
panels = null; // reset the panel
}
/**
@ -131,7 +174,7 @@ final class NewCaseWizardAction extends CallableSystemAction {
if (c instanceof JComponent) { // assume Swing components
JComponent jc = (JComponent) c;
// Sets step number of a component
jc.putClientProperty("WizardPanel_contentSelectedIndex", new Integer(i));
jc.putClientProperty("WizardPanel_contentSelectedIndex", i);
// Sets steps names for a panel
jc.putClientProperty("WizardPanel_contentData", steps);
// Turn on subtitle creation on each step

View File

@ -33,8 +33,8 @@ import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.WizardDescriptor;
import org.openide.WizardValidationException;
import org.openide.util.Exceptions;
import org.openide.util.HelpCtx;
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
/**
@ -170,7 +170,8 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDesc
NewCaseVisualPanel1 component = getComponent();
try {
String lastBaseDirectory = ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_BASECASE);
component.getCaseParentDirTextField().setText(lastBaseDirectory);
component.setCaseParentDir(lastBaseDirectory);
component.readSettings();
createdDirectory = (String) settings.getProperty("createdDirectory"); //NON-NLS
if (createdDirectory != null && !createdDirectory.equals("")) {
logger.log(Level.INFO, "Deleting a case dir in readSettings(): " + createdDirectory); //NON-NLS
@ -192,9 +193,12 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDesc
*/
@Override
public void storeSettings(WizardDescriptor settings) {
CaseType caseType = getComponent().getCaseType();
settings.putProperty("caseName", getComponent().getCaseName()); //NON-NLS
settings.putProperty("caseParentDir", getComponent().getCaseParentDir()); //NON-NLS
settings.putProperty("createdDirectory", createdDirectory); //NON-NLS
settings.putProperty("caseType", caseType.ordinal()); //NON-NLS
ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, ModuleSettings.CURRENT_CASE_TYPE, caseType.toString());
ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_BASECASE, getComponent().getCaseParentDir());
}
@ -237,7 +241,7 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDesc
if (res2 != null && res2 == DialogDescriptor.YES_OPTION) {
// if user say yes
try {
createDirectory(caseDirPath);
createDirectory(caseDirPath, getComponent().getCaseType());
} catch (Exception ex) {
String errorMsg = NbBundle.getMessage(this.getClass(),
"NewCaseWizardPanel1.validate.errMsg.cantCreateParDir.msg",
@ -254,7 +258,7 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDesc
}
} else {
try {
createDirectory(caseDirPath);
createDirectory(caseDirPath, getComponent().getCaseType());
} catch (Exception ex) {
String errorMsg = NbBundle
.getMessage(this.getClass(), "NewCaseWizardPanel1.validate.errMsg.cantCreateDir");
@ -279,11 +283,11 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDesc
/*
* create the directory and create a new case
*/
private void createDirectory(final String caseDirPath) throws WizardValidationException {
// try to create the directory with the case name in the choosen parent directory
private void createDirectory(final String caseDirPath, CaseType caseType) throws WizardValidationException {
// try to create the directory with the case name in the chosen parent directory
boolean success = false;
try {
Case.createCaseDirectory(caseDirPath);
Case.createCaseDirectory(caseDirPath, caseType);
success = true;
} catch (CaseActionException ex) {
logger.log(Level.SEVERE, "Could not createDirectory for the case, ", ex); //NON-NLS

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -21,14 +21,14 @@ package org.sleuthkit.autopsy.casemodule;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.openide.WizardDescriptor;
import org.openide.WizardValidationException;
import org.openide.util.Exceptions;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.windows.WindowManager;
import java.awt.Cursor;
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
/**
* The "New Case" wizard panel with a component on it. This class represents
@ -48,6 +48,7 @@ class NewCaseWizardPanel2 implements WizardDescriptor.ValidatingPanel<WizardDesc
private String caseName;
private String caseDir;
private String createdDirectory;
private CaseType caseType;
/**
* Get the visual component for the panel. In this template, the component
@ -129,7 +130,7 @@ class NewCaseWizardPanel2 implements WizardDescriptor.ValidatingPanel<WizardDesc
protected final void fireChangeEvent() {
Iterator<ChangeListener> it;
synchronized (listeners) {
it = new HashSet<ChangeListener>(listeners).iterator();
it = new HashSet<>(listeners).iterator();
}
ChangeEvent ev = new ChangeEvent(this);
while (it.hasNext()) {
@ -154,6 +155,7 @@ class NewCaseWizardPanel2 implements WizardDescriptor.ValidatingPanel<WizardDesc
caseName = (String) settings.getProperty("caseName"); //NON-NLS
caseDir = (String) settings.getProperty("caseParentDir"); //NON-NLS
createdDirectory = (String) settings.getProperty("createdDirectory"); //NON-NLS
caseType = CaseType.values()[(int) settings.getProperty("caseType")]; //NON-NLS
}
/**
@ -167,34 +169,13 @@ class NewCaseWizardPanel2 implements WizardDescriptor.ValidatingPanel<WizardDesc
*/
@Override
public void storeSettings(WizardDescriptor settings) {
NewCaseVisualPanel2 currentComponent = getComponent();
settings.putProperty("caseNumber", currentComponent.getCaseNumber());
settings.putProperty("caseExaminer", currentComponent.getExaminer());
}
@Override
public void validate() throws WizardValidationException {
NewCaseVisualPanel2 currentComponent = getComponent();
final String caseNumber = currentComponent.getCaseNumber();
final String examiner = currentComponent.getExaminer();
try {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
Case.create(createdDirectory, caseName, caseNumber, examiner);
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
}
}
});
//Case.create(createdDirectory, caseName, caseNumber, examiner);
} catch (Exception ex) {
throw new WizardValidationException(this.getComponent(),
NbBundle.getMessage(this.getClass(),
"NewCaseWizardPanel2.validate.errCreateCase.msg"),
null);
}
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -24,8 +24,8 @@ import java.io.File;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -37,7 +37,7 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
static String[] caseNames;
static String[] casePaths;
private static Logger logger = Logger.getLogger(OpenRecentCasePanel.class.getName());
private static final Logger logger = Logger.getLogger(OpenRecentCasePanel.class.getName());
private static OpenRecentCasePanel instance;
private RecentCasesTableModel model;
@ -184,8 +184,8 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
logger.log(Level.INFO, "No Case paths exist, cannot open the case"); //NON-NLS
return;
}
String casePath = casePaths[imagesTable.getSelectedRow()];
String caseName = caseNames[imagesTable.getSelectedRow()];
final String casePath = casePaths[imagesTable.getSelectedRow()];
final String caseName = caseNames[imagesTable.getSelectedRow()];
if (!casePath.equals("")) {
// Close the startup menu
try {
@ -195,27 +195,34 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
logger.log(Level.WARNING, "Error: couldn't open case: " + caseName, ex); //NON-NLS
}
// Open the recent cases
try {
if (caseName.equals("") || casePath.equals("") || (!new File(casePath).exists())) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(OpenRecentCasePanel.class,
"OpenRecentCasePanel.openCase.msgDlg.caseDoesntExist.msg",
caseName),
NbBundle.getMessage(OpenRecentCasePanel.class,
"OpenRecentCasePanel.openCase.msgDlg.err"),
JOptionPane.ERROR_MESSAGE);
RecentCases.getInstance().removeRecentCase(caseName, casePath); // remove the recent case if it doesn't exist anymore
if (caseName.equals("") || casePath.equals("") || (!new File(casePath).exists())) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"OpenRecentCasePanel.openCase.msgDlg.caseDoesntExist.msg",
caseName),
NbBundle.getMessage(this.getClass(),
"OpenRecentCasePanel.openCase.msgDlg.err"),
JOptionPane.ERROR_MESSAGE);
RecentCases.getInstance().removeRecentCase(caseName, casePath); // remove the recent case if it doesn't exist anymore
//if case is not opened, open the start window
if (Case.isCaseOpen() == false) {
StartupWindowProvider.getInstance().open();
}
} else {
Case.open(casePath); // open the case
//if case is not opened, open the start window
if (Case.isCaseOpen() == false) {
StartupWindowProvider.getInstance().open();
}
} catch (CaseActionException ex) {
logger.log(Level.WARNING, "Error: couldn't open case: " + caseName, ex); //NON-NLS
} else {
new Thread(() -> {
try {
Case.open(casePath);
} catch (CaseActionException ex) {
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null, ex.getMessage(), NbBundle.getMessage(this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"), JOptionPane.ERROR_MESSAGE);
if (!Case.isCaseOpen()) {
StartupWindowProvider.getInstance().open();
}
});
}
}).start();
}
}
}
@ -286,7 +293,7 @@ class OpenRecentCasePanel extends javax.swing.JPanel {
ret = shortenPath(casePaths[rowIndex]);
break;
default:
logger.log(Level.SEVERE, "Invalid table column index: " + columnIndex); //NON-NLS
logger.log(Level.SEVERE, "Invalid table column index: {0}", columnIndex); //NON-NLS
break;
}
return ret;

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2014 Basis Technology Corp.
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -22,11 +22,10 @@ import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* This class is used to add the action to the recent case menu item. When the
@ -34,8 +33,8 @@ import org.sleuthkit.autopsy.coreutils.Logger;
*/
class RecentItems implements ActionListener {
String caseName;
String casePath;
final String caseName;
final String casePath;
private JPanel caller; // for error handling
/**
@ -65,22 +64,25 @@ class RecentItems implements ActionListener {
//if case is not opened, open the start window
if (Case.isCaseOpen() == false) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
StartupWindowProvider.getInstance().open();
}
EventQueue.invokeLater(() -> {
StartupWindowProvider.getInstance().open();
});
}
} else {
try {
Case.open(casePath); // open the case
} catch (CaseActionException ex) {
Logger.getLogger(RecentItems.class.getName()).log(Level.WARNING, "Error: Couldn't open recent case at " + casePath, ex); //NON-NLS
}
new Thread(() -> {
// Create case.
try {
Case.open(casePath);
} catch (CaseActionException ex) {
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null, ex.getMessage(), NbBundle.getMessage(RecentItems.this.getClass(), "CaseOpenAction.msgDlg.cantOpenCase.title"), JOptionPane.ERROR_MESSAGE);
if (!Case.isCaseOpen()) {
StartupWindowProvider.getInstance().open();
}
});
}
}).start();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -59,6 +59,7 @@ public final class StartupWindow extends JDialog implements StartupWindowInterfa
// set the location of the popUp Window on the center of the screen
setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2);
setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
welcomeWindow = new CueBannerPanel();
@ -80,6 +81,7 @@ public final class StartupWindow extends JDialog implements StartupWindowInterfa
@Override
public void open() {
welcomeWindow.refresh();
setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
setVisible(true);
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -33,8 +33,10 @@ class UpdateRecentCases extends JMenuItem implements DynamicMenuContent {
int length;
static boolean hasRecentCase = false;
/** the constructor */
UpdateRecentCases(){
/**
* the constructor
*/
UpdateRecentCases() {
// display last 5 cases.
length = RecentCases.LENGTH - 1;
}
@ -60,7 +62,7 @@ class UpdateRecentCases extends JMenuItem implements DynamicMenuContent {
menuItem.setActionCommand(caseName[i].toUpperCase());
menuItem.addActionListener(new RecentItems(caseName[i], casePath[i]));
comps[i] = menuItem;
hasRecentCase = hasRecentCase || true;
hasRecentCase = true;
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012 Basis Technology Corp.
* Copyright 2012-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -29,10 +29,10 @@ import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
import org.sleuthkit.autopsy.core.RuntimeProperties;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.XMLUtil;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
@ -60,6 +60,7 @@ class XMLCaseManagement implements CaseConfigFileInterface {
final static String SCHEMA_VERSION_NAME = "SchemaVersion"; //NON-NLS
final static String AUTOPSY_CRVERSION_NAME = "AutopsyCreatedVersion"; //NON-NLS
final static String AUTOPSY_MVERSION_NAME = "AutopsySavedVersion"; //NON-NLS
final static String CASE_TEXT_INDEX_NAME = "TextIndexName"; //NON-NLS
// folders inside case directory
final static String LOG_FOLDER_NAME = "LogFolder"; //NON-NLS
final static String LOG_FOLDER_RELPATH = "Log"; //NON-NLS
@ -69,6 +70,8 @@ class XMLCaseManagement implements CaseConfigFileInterface {
final static String EXPORT_FOLDER_RELPATH = "Export"; //NON-NLS
final static String CACHE_FOLDER_NAME = "CacheFolder"; //NON-NLS
final static String CACHE_FOLDER_RELPATH = "Cache"; //NON-NLS
final static String CASE_TYPE = "CaseType"; //NON-NLS
final static String DATABASE_NAME = "DatabaseName"; //NON-NLS
// folders attribute
final static String RELATIVE_NAME = "Relative"; // relevant path info NON-NLS
// folder attr values
@ -77,23 +80,26 @@ class XMLCaseManagement implements CaseConfigFileInterface {
// the document
private Document doc;
// general info
private DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)");
private final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)");
private String caseDirPath; // case directory path
private String caseName; // case name
private String caseNumber; // case number
private String caseNumber; // case number
private String examiner; // examiner name
private String schemaVersion = "1.0";
private String autopsySavedVersion;
private final String schemaVersion = "1.0";
private final String autopsySavedVersion;
private CaseType caseType; // The type of case: local or shared
private String dbName; // The name of the database
private String textIndexName; // The name of the index where extracted text is stored.
// for error handling
private JPanel caller;
private String className = this.getClass().toString();
private final String className = this.getClass().toString();
private static final Logger logger = Logger.getLogger(XMLCaseManagement.class.getName());
/**
* The constructor
*/
XMLCaseManagement() {
// System.setProperty("netbeans.buildnumber", autopsyVer); // set the current autopsy version // moved to CoreComponents installer
public XMLCaseManagement() {
autopsySavedVersion = System.getProperty("netbeans.buildnumber");
}
@ -148,6 +154,23 @@ class XMLCaseManagement implements CaseConfigFileInterface {
}
/**
* Sets the created date on the XML configuration file. This method is for
* preserving the created date when converting a case from single-user to
* multi-user.
*
* @param createdDate the date the case was originally created
*
* @throws org.sleuthkit.autopsy.casemodule.CaseActionException
*/
public void setCreatedDate(String createdDate) throws CaseActionException {
String newDate = dateFormat.format(new Date());
Element rootEl = getRootElement();
rootEl.getElementsByTagName(CREATED_DATE_NAME).item(0).setTextContent(createdDate);
rootEl.getElementsByTagName(MODIFIED_DATE_NAME).item(0).setTextContent(newDate);
writeFile();
}
/**
* Sets the examiner on the XML configuration file
*
@ -187,6 +210,89 @@ class XMLCaseManagement implements CaseConfigFileInterface {
caseNumber = givenCaseNumber; // change this to change the xml file if needed
}
/**
* Sets the case type internally (on local variable in this class)
*
* @param givenCaseType the new case type
*/
private void setCaseType(CaseType givenCaseType) {
caseType = givenCaseType; // change this to change the xml file if needed
}
/**
* Gets the case Type from the document handler. Defaults to local if it
* can't figure it out.
*
* @return caseType from the document handler
*/
public CaseType getCaseType() {
if (doc == null) {
return CaseType.SINGLE_USER_CASE;
} else {
if (getCaseElement().getElementsByTagName(CASE_TYPE).getLength() > 0) {
Element nameElement = (Element) getCaseElement().getElementsByTagName(CASE_TYPE).item(0);
return CaseType.fromString(nameElement.getTextContent());
} else {
return CaseType.SINGLE_USER_CASE;
}
}
}
/**
* Sets the database name internally (on local variable in this class)
*
* @param givenDbName the new db name
*/
private void setDatabaseName(String givenDbName) {
dbName = givenDbName; // change this to change the xml file if needed
}
/**
* Gets the database name from the document handler
*
* @return the database name
*/
public String getDatabaseName() {
if (doc == null) {
return "";
} else {
if (getCaseElement().getElementsByTagName(DATABASE_NAME).getLength() > 0) {
Element nameElement = (Element) getCaseElement().getElementsByTagName(DATABASE_NAME).item(0);
return nameElement.getTextContent();
} else {
return ""; /// couldn't find one, so return a blank name
}
}
}
/**
* Sets the text index name internally (on local variable in this class)
*
* @param textIndexName the new name for the index where extracted text is
* stored for the case.
*/
private void setTextIndexName(String textIndexName) {
this.textIndexName = textIndexName; // change this to change the xml file if needed
}
/**
* Gets the name of the index where extracted text is stored.
*
* @return the index name
*/
public String getTextIndexName() {
if (doc == null) {
return "";
} else {
if (getCaseElement().getElementsByTagName(CASE_TEXT_INDEX_NAME).getLength() > 0) {
Element nameElement = (Element) getCaseElement().getElementsByTagName(CASE_TEXT_INDEX_NAME).item(0);
return nameElement.getTextContent();
} else {
return ""; /// couldn't find one, so return a blank index name
}
}
}
/**
* Sets the examiner name internally (on local variable in this class)
*
@ -282,7 +388,7 @@ class XMLCaseManagement implements CaseConfigFileInterface {
*
* @return createdDate the creation date of this case
*/
protected String getCreatedDate() {
public String getCreatedDate() {
if (doc != null) {
Element crDateElement = (Element) getRootElement().getElementsByTagName(CREATED_DATE_NAME).item(0);
return crDateElement.getTextContent();
@ -437,13 +543,17 @@ class XMLCaseManagement implements CaseConfigFileInterface {
* Initialize the basic values for a new case management file. Note: this is
* the schema version 1.0
*
* @param dirPath case directory path
* @param caseName the name of the config file to be located in the case
* directory
* @param examiner examiner for the case (optional, can be empty string
* @param caseNumber case number (optional), can be empty
* @param dirPath case directory path
* @param caseName the name of the config file to be located in the
* case directory
* @param examiner examiner for the case (optional, can be empty string
* @param caseNumber case number (optional), can be empty
* @param dbName the name of the database. Could be a local path,
* could be a Postgre db name.
* @param textIndexName The name of the index where extracted text is
* stored.
*/
protected void create(String dirPath, String caseName, String examiner, String caseNumber) throws CaseActionException {
public void create(String dirPath, String caseName, String examiner, String caseNumber, CaseType caseType, String dbName, String textIndexName) throws CaseActionException {
clear(); // clear the previous data
// set the case Name and Directory and the parent directory
@ -451,6 +561,9 @@ class XMLCaseManagement implements CaseConfigFileInterface {
setName(caseName);
setExaminer(examiner);
setNumber(caseNumber);
setCaseType(caseType);
setDatabaseName(dbName);
setTextIndexName(textIndexName);
DocumentBuilder docBuilder;
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
@ -522,6 +635,18 @@ class XMLCaseManagement implements CaseConfigFileInterface {
cacheElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS
caseElement.appendChild(cacheElement);
Element typeElement = doc.createElement(CASE_TYPE); // <CaseType> ... </CaseType>
typeElement.appendChild(doc.createTextNode(caseType.toString()));
caseElement.appendChild(typeElement);
Element dbNameElement = doc.createElement(DATABASE_NAME); // <DatabaseName> ... </DatabaseName>
dbNameElement.appendChild(doc.createTextNode(dbName));
caseElement.appendChild(dbNameElement);
Element indexNameElement = doc.createElement(CASE_TEXT_INDEX_NAME); // <TextIndexName> ... </TextIndexName>
indexNameElement.appendChild(doc.createTextNode(textIndexName));
caseElement.appendChild(indexNameElement);
// write more code if needed ...
}
@ -597,19 +722,11 @@ class XMLCaseManagement implements CaseConfigFileInterface {
File file = new File(conFilePath);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = null;
DocumentBuilder db;
try {
db = dbf.newDocumentBuilder();
doc = db.parse(file);
} catch (ParserConfigurationException ex) {
throw new CaseActionException(
NbBundle.getMessage(this.getClass(), "XMLCaseManagement.open.exception.errReadXMLFile.msg",
conFilePath), ex);
} catch (SAXException ex) {
throw new CaseActionException(
NbBundle.getMessage(this.getClass(), "XMLCaseManagement.open.exception.errReadXMLFile.msg",
conFilePath), ex);
} catch (IOException ex) {
} catch (ParserConfigurationException | SAXException | IOException ex) {
throw new CaseActionException(
NbBundle.getMessage(this.getClass(), "XMLCaseManagement.open.exception.errReadXMLFile.msg",
conFilePath), ex);
@ -618,10 +735,10 @@ class XMLCaseManagement implements CaseConfigFileInterface {
doc.getDocumentElement().normalize();
doc.getDocumentElement().normalize();
if (!XMLUtil.xmlIsValid(doc, XMLCaseManagement.class, XSDFILE)) {
logger.log(Level.WARNING, "Could not validate against [" + XSDFILE + "], results may not accurate"); //NON-NLS
}
// TODO: Restore later
// if (!XMLUtil.xmlIsValid(doc, XMLCaseManagement.class, XSDFILE)) {
// logger.log(Level.WARNING, "Could not validate against [" + XSDFILE + "], results may not accurate"); //NON-NLS
// }
Element rootEl = doc.getDocumentElement();
String rootName = rootEl.getNodeName();
@ -629,13 +746,16 @@ class XMLCaseManagement implements CaseConfigFileInterface {
if (!rootName.equals(TOP_ROOT_NAME)) {
// throw an error ...
clear();
JOptionPane.showMessageDialog(caller,
NbBundle.getMessage(this.getClass(),
"XMLCaseManagement.open.msgDlg.notAutCase.msg",
file.getName(), className),
NbBundle.getMessage(this.getClass(),
"XMLCaseManagement.open.msgDlg.notAutCase.title"),
JOptionPane.ERROR_MESSAGE);
if (RuntimeProperties.coreComponentsAreActive()) {
JOptionPane.showMessageDialog(caller,
NbBundle.getMessage(this.getClass(),
"XMLCaseManagement.open.msgDlg.notAutCase.msg",
file.getName(), className),
NbBundle.getMessage(this.getClass(),
"XMLCaseManagement.open.msgDlg.notAutCase.title"),
JOptionPane.ERROR_MESSAGE);
}
} else {
/*
* Autopsy Created Version
@ -687,5 +807,8 @@ class XMLCaseManagement implements CaseConfigFileInterface {
caseName = "";
caseNumber = "";
examiner = "";
caseType = CaseType.SINGLE_USER_CASE;
dbName = "";
textIndexName = "";
}
}

View File

@ -0,0 +1,61 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable;
import java.util.UUID;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.events.AutopsyEvent;
/**
* Event published when a data source is being added to a case.
*/
@Immutable
public final class AddingDataSourceEvent extends AutopsyEvent implements Serializable {
private static final long serialVersionUID = 1L;
private final UUID dataSourceId;
/**
* Constructs an event published when a data source is being added to a
* case.
*
* @param dataSourceId A unique identifier associated with the data source.
* Used to pair this AddingDataSourceEvent with a
* DataSourceAddedEvent or a
* AddingDataSourceFailedEvent.
*/
public AddingDataSourceEvent(UUID dataSourceId) {
super(Case.Events.ADDING_DATA_SOURCE.toString(), null, null);
this.dataSourceId = dataSourceId;
}
/**
* Gets the unique id for the data source used to pair this
* AddindDataSourceEvent with a a DataSourceAddedEvent or a
* AddingDataSourceFailedEvent.
*
* @return The unique id.
*/
public UUID getDataSourceId() {
return dataSourceId;
}
}

View File

@ -0,0 +1,59 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable;
import java.util.UUID;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.events.AutopsyEvent;
/**
* Event published when an attempt to add a data source to a case fails.
*/
@Immutable
public final class AddingDataSourceFailedEvent extends AutopsyEvent implements Serializable {
private static final long serialVersionUID = 1L;
private final UUID dataSourceId;
/**
* Constructs an event published when an attempt to add a data source to a
* case fails.
*
* @param dataSourceId A unique identifier associated with the data source.
* Used to pair this AddingDataSourceFailedEvent with a
* AddingDataSourceEvent.
*/
public AddingDataSourceFailedEvent(UUID dataSourceId) {
super(Case.Events.ADDING_DATA_SOURCE_FAILED.toString(), null, null);
this.dataSourceId = dataSourceId;
}
/**
* Gets the unique id for the data source used to pair this
* AddingDataSourceFailedEvent with a AddingDataSourceEvent.
*
* @return The unique id.
*/
public UUID getDataSourceId() {
return dataSourceId;
}
}

View File

@ -16,18 +16,36 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.events;
package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.TskCoreException;
/**
*
* Event sent when a black board artifact tag is added.
*/
public class BlackBoardArtifactTagAddedEvent extends TagAddedEvent<BlackboardArtifactTag> {
@Immutable
public class BlackBoardArtifactTagAddedEvent extends TagAddedEvent<BlackboardArtifactTag> implements Serializable {
private static final long serialVersionUID = 1L;
public BlackBoardArtifactTagAddedEvent(BlackboardArtifactTag newTag) {
super(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString(), newTag
);
super(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString(), newTag);
}
/**
* get the BlackboardArtifactTag that was added by its id
*
* @return BlackboardArtifactTag that was added
*
* @throws IllegalStateException
* @throws TskCoreException
*/
@Override
BlackboardArtifactTag getTagByID() throws IllegalStateException, TskCoreException {
return Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagByTagID(getTagID());
}
}

View File

@ -0,0 +1,76 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
/**
* Event that is fired when a black board artifact tag is deleted.
*/
@Immutable
public class BlackBoardArtifactTagDeletedEvent extends TagDeletedEvent<BlackboardArtifactTag> implements Serializable {
private static final long serialVersionUID = 1L;
public BlackBoardArtifactTagDeletedEvent(BlackboardArtifactTag deletedTag) {
super(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString(), new DeletedBlackboardArtifactTagInfo(deletedTag));
}
/**
* {@inheritDoc }
*
* @return the DeletedBlackboardArtifactTagInfo for the deleted tag
*/
@Override
public DeletedBlackboardArtifactTagInfo getDeletedTagInfo() {
return (DeletedBlackboardArtifactTagInfo) getOldValue();
}
/**
* Extension of {@link DeletedTagInfo} for BlackBoardArtifactTags that
* includes artifact related info.
*/
@Immutable
public static class DeletedBlackboardArtifactTagInfo extends DeletedTagInfo<BlackboardArtifactTag> implements Serializable {
private static final long serialVersionUID = 1L;
private final long contentID;
private final long artifactID;
private DeletedBlackboardArtifactTagInfo(BlackboardArtifactTag deletedTag) {
super(deletedTag);
artifactID = deletedTag.getArtifact().getArtifactID();
contentID = deletedTag.getContent().getId();
}
@Override
public long getContentID() {
return contentID;
}
public long getArtifactID() {
return artifactID;
}
}
}

View File

@ -16,20 +16,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.events;
package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TskCoreException;
/**
* An event that is fired when a ContentTag is added.
*/
@Immutable
public class ContentTagAddedEvent extends TagAddedEvent<ContentTag> {
public class ContentTagAddedEvent extends TagAddedEvent<ContentTag> implements Serializable {
private static final long serialVersionUID = 1L;
public ContentTagAddedEvent(ContentTag newTag) {
super(Case.Events.CONTENT_TAG_ADDED.toString(), newTag);
}
/**
* get the ContentTag that was added by its id
*
* @return ContentTag that was added
*
* @throws IllegalStateException
* @throws TskCoreException
*/
ContentTag getTagByID() throws IllegalStateException, TskCoreException {
return Case.getCurrentCase().getServices().getTagsManager().getContentTagByTagID(getTagID());
}
}

View File

@ -0,0 +1,82 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.ContentTag;
/**
* An event that is fired when a ContentTag is deleted.
*/
@Immutable
public class ContentTagDeletedEvent extends TagDeletedEvent<ContentTag> implements Serializable {
private static final long serialVersionUID = 1L;
public ContentTagDeletedEvent(ContentTag deletedTag) {
super(Case.Events.CONTENT_TAG_DELETED.toString(), new DeletedContentTagInfo(deletedTag));
}
/**
* {@inheritDoc }
*
* @return the DeletedContentTagInfo for the deleted tag
*/
@Override
public DeletedContentTagInfo getDeletedTagInfo() {
return (DeletedContentTagInfo) getOldValue();
}
/**
* Extension of {@link DeletedTagInfo} for BlackBoardArtifactTags that
* includes byte offset related info.
*/
@Immutable
public static class DeletedContentTagInfo extends DeletedTagInfo<ContentTag> implements Serializable {
private static final long serialVersionUID = 1L;
private final long contentID;
private final long beginByteOffset;
private final long endByteOffset;
private DeletedContentTagInfo(ContentTag deletedTag) {
super(deletedTag);
beginByteOffset = deletedTag.getBeginByteOffset();
endByteOffset = deletedTag.getEndByteOffset();
contentID = deletedTag.getContent().getId();
}
@Override
public long getContentID() {
return contentID;
}
public long getBeginByteOffset() {
return beginByteOffset;
}
public long getEndByteOffset() {
return endByteOffset;
}
}
}

View File

@ -0,0 +1,108 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable;
import java.util.UUID;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Event published when a data source is added to a case.
*/
public final class DataSourceAddedEvent extends AutopsyEvent implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(DataSourceAddedEvent.class.getName());
private transient Content dataSource;
private final UUID dataSourceId;
/**
* Constructs an event published when a data source is added to a case.
*
* @param dataSource The data source that was added.
* @param dataSourceId A unique identifier associated with the data source.
* Used to pair this DataSourceAddedEvent with a
* AddindDataSourceEvent.
*/
public DataSourceAddedEvent(Content dataSource, UUID dataSourceId) {
/**
* Putting the object id of the data source into newValue to allow for
* lazy loading of the Content object. This bypasses the issues related
* to the serialization and de-serialization of Content objects when the
* event is published over a network.
*/
super(Case.Events.DATA_SOURCE_ADDED.toString(), null, dataSource.getId());
this.dataSource = dataSource;
this.dataSourceId = dataSourceId;
}
/**
* Gets the data source that was added.
*
* @return The data source or null if there is an error retrieving the data
* source.
*/
@Override
public Object getNewValue() {
/**
* The dataSource field is set in the constructor, but it is transient
* so it will become null when the event is serialized for publication
* over a network. Doing a lazy load of the Content object bypasses the
* issues related to the serialization and de-serialization of Content
* objects and may also save database round trips from other nodes since
* subscribers to this event are often not interested in the event data.
*/
if (null != dataSource) {
return dataSource;
}
try {
long id = (Long) super.getNewValue();
dataSource = Case.getCurrentCase().getSleuthkitCase().getContentById(id);
return dataSource;
} catch (IllegalStateException | TskCoreException ex) {
logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex);
return null;
}
}
/**
* Gets the data source that was added.
*
* @return The data source.
*/
public Content getDataSource() {
return (Content) getNewValue();
}
/**
* Gets the unique id for the data source used to pair this
* DataSourceAddedEvent with a AddingDataSourceEvent.
*
* @return The unique id.
*/
public UUID getDataSourceId() {
return dataSourceId;
}
}

View File

@ -0,0 +1,86 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable;
import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.datamodel.Report;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Event published when a report is added to a case.
*/
public final class ReportAddedEvent extends AutopsyEvent implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(DataSourceAddedEvent.class.getName());
private transient Report report;
/**
* Constructs an event published when a report is added to a case.
*
* @param report The data source that was added.
*/
public ReportAddedEvent(Report report) {
/**
* Putting the object id of the report into newValue to allow for lazy
* loading of the Report object.
*/
super(Case.Events.REPORT_ADDED.toString(), null, report.getId());
this.report = report;
}
/**
* Gets the data source that was added.
*
* @return The data source.
*/
@Override
public Object getNewValue() {
/**
* The report field is set in the constructor, but it is transient so it
* will become null when the event is serialized for publication over a
* network. Doing a lazy load of the Report object may save database
* round trips from other nodes since subscribers to this event are
* often not interested in the event data.
*/
if (null != report) {
return report;
}
try {
long id = (Long) super.getNewValue();
List<Report> reports = Case.getCurrentCase().getSleuthkitCase().getAllReports();
for (Report thisReport : reports) {
if (thisReport.getId() == id) {
report = thisReport;
break;
}
}
return report;
} catch (IllegalStateException | TskCoreException ex) {
logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex);
return null;
}
}
}

View File

@ -0,0 +1,105 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Base Class for events that are fired when a Tag is added
*/
abstract class TagAddedEvent<T extends Tag> extends AutopsyEvent implements Serializable {
private static final long serialVersionUID = 1L;
/**
* The tag that was added. This will be lost during serialization and
* re-loaded from the database in getNewValue()
*/
private transient T tag;
/**
* The id of the tag that was added. This will bu used to re-load the
* transient tag from the database.
*/
private final Long tagID;
TagAddedEvent(String propertyName, T addedTag) {
super(propertyName, null, null);
tag = addedTag;
tagID = addedTag.getId();
}
/**
* get the id of the Tag that was added
*
* @return the id of the Tag that was added
*/
Long getTagID() {
return tagID;
}
/**
* get the Tag that was added
*
* @return the tTag
*/
public T getAddedTag() {
return getNewValue();
}
@Override
public T getNewValue() {
/**
* The tag field is set in the constructor, but it is transient so it
* will become null when the event is serialized for publication over a
* network. Doing a lazy load of the Tag object bypasses the issues
* related to the serialization and de-serialization of Tag objects and
* may also save database round trips from other nodes since subscribers
* to this event are often not interested in the event data.
*/
if (null != tag) {
return tag;
}
try {
tag = getTagByID();
return tag;
} catch (IllegalStateException | TskCoreException ex) {
Logger.getLogger(TagAddedEvent.class.getName()).log(Level.SEVERE, "Error doing lazy load for remote event", ex);
return null;
}
}
/**
* implementors should override this to lookup the appropriate kind of tag
* (Content/BlackBoardArtifact) during the lazy load of the transient tag
* field
*
*
* @return the Tag based on the saved tag id
*
* @throws IllegalStateException
* @throws TskCoreException
*/
abstract T getTagByID() throws IllegalStateException, TskCoreException;
}

View File

@ -0,0 +1,87 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule.events;
import java.io.Serializable;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.events.AutopsyEvent;
import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.datamodel.TagName;
/**
* Base Class for events that are fired when a Tag is deleted
*/
@Immutable
abstract class TagDeletedEvent<T extends Tag> extends AutopsyEvent implements Serializable {
private static final long serialVersionUID = 1L;
TagDeletedEvent(String propertyName, DeletedTagInfo<T> deletedTagInfo) {
super(propertyName, deletedTagInfo, null);
}
/**
* get info about the Tag that was deleted.
*
* Since we don't serialize the deleted tag, and we can't look it up by id
* after it is deleted, we send this info to represent it.
*
* @return info about the Tag that was deleted.
*/
@SuppressWarnings("unchecked")
abstract public DeletedTagInfo<T> getDeletedTagInfo();
/**
* Base Class for info about a deleted tag. This is sent as the old value in
* the event, since we are not serializing the Tag it self, and we can't
* look it up by id, like we do for added tags, because it doesn't exist in
* the db any more.
*
* @param <T> the subtype of Tag, BlackBoardArtifactTag or ContentTag
*/
@Immutable
abstract static class DeletedTagInfo<T extends Tag> implements Serializable {
private static final long serialVersionUID = 1L;
private final String comment;
private final long tagID;
private final TagName name;
DeletedTagInfo(T deletedTag) {
comment = deletedTag.getComment();
tagID = deletedTag.getId();
name = deletedTag.getName();
}
abstract public long getContentID();
public String getComment() {
return comment;
}
public long getTagID() {
return tagID;
}
public TagName getName() {
return name;
}
}
}

View File

@ -15,7 +15,7 @@ TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0
TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} out of content size range (0 - {1})
TagsManager.addContentTag.exception.endLTbegin.msg=endByteOffset < beginByteOffset
TagsManager.predefTagNames.bookmark.text=Bookmark
TagsManager.addContentTag.noCaseWarning=Failed to add publish new content tag event. There is no case open.
TagsManager.deleteContentTag.noCaseWarning=Failed to add publish content tag deleted event. There is no case open.
TagsManager.addBlackboardArtifactTag.noCaseWarning=Failed to add publish new blackboard artifact tag event. There is no case open.
TagsManager.deleteBlackboardArtifactTag.noCaseWarning=Failed to add publish blackboard artifact tag deleted event. There is no case open.
TagsManager.addContentTag.noCaseWarning=Failed to publish new content tag event. There is no case open.
TagsManager.deleteContentTag.noCaseWarning=Failed to publish content tag deleted event. There is no case open.
TagsManager.addBlackboardArtifactTag.noCaseWarning=Failed to publish new blackboard artifact tag event. There is no case open.
TagsManager.deleteBlackboardArtifactTag.noCaseWarning=Failed to publish blackboard artifact tag deleted event. There is no case open.

View File

@ -272,7 +272,7 @@ public class TagsManager implements Closeable {
tskCase.deleteContentTag(tag);
try {
Case.getCurrentCase().notifyContentTagDeleted(tag);
} catch (IllegalArgumentException e) {
} catch (IllegalStateException e) {
Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.deleteContentTag.noCaseWarning"));
}
}
@ -311,6 +311,24 @@ public class TagsManager implements Closeable {
return tskCase.getContentTagsCountByTagName(tagName);
}
/**
* Gets a content tag by tag id.
*
* @param tagID The tag id of interest.
*
* @return the content tag with the specified tag id.
*
* @throws TskCoreException
*/
public synchronized ContentTag getContentTagByTagID(long tagID) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getContentTagByID(tagID);
}
/**
* Gets content tags by tag name.
*
@ -385,7 +403,7 @@ public class TagsManager implements Closeable {
BlackboardArtifactTag addBlackboardArtifactTag = tskCase.addBlackboardArtifactTag(artifact, tagName, comment);
try {
Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(addBlackboardArtifactTag);
} catch (IllegalArgumentException e) {
} catch (IllegalStateException e) {
Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.addBlackboardArtifactTag.noCaseWarning"));
}
return addBlackboardArtifactTag;
@ -407,7 +425,7 @@ public class TagsManager implements Closeable {
tskCase.deleteBlackboardArtifactTag(tag);
try {
Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag);
} catch (IllegalArgumentException e) {
} catch (IllegalStateException e) {
Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.deleteBlackboardArtifactTag.noCaseWarning"));
}
}
@ -447,6 +465,24 @@ public class TagsManager implements Closeable {
return tskCase.getBlackboardArtifactTagsCountByTagName(tagName);
}
/**
* Gets a blackboard artifact tag by tag id.
*
* @param tagID The tag id of interest.
*
* @return the blackboard artifact tag with the specified tag id.
*
* @throws TskCoreException
*/
public synchronized BlackboardArtifactTag getBlackboardArtifactTagByTagID(long tagID) throws TskCoreException {
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
if (!tagNamesInitialized) {
getExistingTagNames();
}
return tskCase.getBlackboardArtifactTagByID(tagID);
}
/**
* Gets blackboard artifact tags by tag name.
*

View File

@ -12,7 +12,7 @@ Metadata.tableRowTitle.hashLookupResults=Hash Lookup Results
Metadata.tableRowTitle.internalid=Internal ID
Metadata.tableRowTitle.localPath=Local Path
Metadata.tableRowTitle.type=Type
Metadata.title=Metadata
Metadata.title=File Metadata
Metadata.toolTip=Displays metadata about the file.
Metadata.nodeText.nonFilePassedIn=Non-file passed in
Metadata.nodeText.text=From The Sleuth Kit istat Tool\:

View File

@ -12,3 +12,15 @@ org_sleuthkit_autopsy_core_update_center=http://sleuthkit.org/autopsy/updates.xm
Services/AutoupdateType/org_sleuthkit_autopsy_core_update_center.settings=Autopsy Update Center
Installer.errorInitJavafx.msg=Error initializing JavaFX.
Installer.errorInitJavafx.details=\ Some features will not be available. Check that you have the right JRE installed (Oracle JRE > 1.7.10).
ServicesMonitor.failedService.notify.title=Service Is Down
ServicesMonitor.failedService.notify.msg=Connection to {0} is down
ServicesMonitor.restoredService.notify.title=Service Is Up
ServicesMonitor.restoredService.notify.msg=Connection to {0} is up
ServicesMonitor.statusChange.notify.title=Service Status Update
ServicesMonitor.statusChange.notify.msg=Status for {0} is {1}
ServicesMonitor.nullServiceName.excepton.txt=Requested service name is null
ServicesMonitor.unknownServiceName.excepton.txt=Requested service name {0} is unknown
TextConverter.convert.exception.txt=Unable to convert text {0} to hex text
TextConverter.convertFromHex.exception.txt=Unable to convert hex text to text
ServicesMonitor.KeywordSearchNull=Cannot find Keyword Search service
ServicesMonitor.InvalidPortNumber=Invalid port number.

View File

@ -66,9 +66,10 @@ public class Installer extends ModuleInstall {
//We should update this if we officially switch to a new version of CRT/compiler
System.loadLibrary("msvcr100"); //NON-NLS
System.loadLibrary("msvcp100"); //NON-NLS
logger.log(Level.INFO, "MS CRT libraries loaded"); //NON-NLS
System.loadLibrary("msvcr120"); //NON-NLS
logger.log(Level.INFO, "MSVCR100 and MSVCP100 libraries loaded"); //NON-NLS
} catch (UnsatisfiedLinkError e) {
logger.log(Level.SEVERE, "Error loading ms crt libraries, ", e); //NON-NLS
logger.log(Level.SEVERE, "Error loading MSVCR100 and MSVCP100 libraries, ", e); //NON-NLS
}
try {
@ -84,6 +85,34 @@ public class Installer extends ModuleInstall {
} catch (UnsatisfiedLinkError e) {
logger.log(Level.SEVERE, "Error loading EWF library, ", e); //NON-NLS
}
try {
System.loadLibrary("libeay32"); //NON-NLS
logger.log(Level.INFO, "LIBEAY32 library loaded"); //NON-NLS
} catch (UnsatisfiedLinkError e) {
logger.log(Level.SEVERE, "Error loading LIBEAY32 library, ", e); //NON-NLS
}
try {
System.loadLibrary("ssleay32"); //NON-NLS
logger.log(Level.INFO, "SSLEAY32 library loaded"); //NON-NLS
} catch (UnsatisfiedLinkError e) {
logger.log(Level.SEVERE, "Error loading SSLEAY32 library, ", e); //NON-NLS
}
try {
System.loadLibrary("libintl-8"); //NON-NLS
logger.log(Level.INFO, "libintl-8 library loaded"); //NON-NLS
} catch (UnsatisfiedLinkError e) {
logger.log(Level.SEVERE, "Error loading libintl-8 library, ", e); //NON-NLS
}
try {
System.loadLibrary("libpq"); //NON-NLS
logger.log(Level.INFO, "LIBPQ library loaded"); //NON-NLS
} catch (UnsatisfiedLinkError e) {
logger.log(Level.SEVERE, "Error loading LIBPQ library, ", e); //NON-NLS
}
}
}

View File

@ -0,0 +1,62 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.core;
/**
* Application properties that are set once at runtime and are not saved between
* invocations of Autopsy.
*/
public class RuntimeProperties {
private static boolean coreComponentsActive = true;
private static boolean coreComponentsActiveSet = false;
/**
* Sets or unsets a flag indicating whether or not the core Autopsy UI
* components and user interactions with those components via menus, message
* boxes, NetBeans progress handles, etc., are enabled.
* <p>
* This flag exists as a mechanism to allow use of Autopsy as a platform
* with the core Autopsy user interface disabled, until such time as the
* user interface is made separable and optional.
*
* @param coreComponentsActive True or false.
*/
public static void setCoreComponentsActive(boolean coreComponentsActive) {
if (!coreComponentsActiveSet) {
RuntimeProperties.coreComponentsActive = coreComponentsActive;
coreComponentsActiveSet = true;
}
}
/**
* Gets a flag indicating whether or not the core Autopsy UI components and
* user interactions with those components via menus, message boxes,
* NetBeans progress handles, etc., are enabled.
* <p>
* This flag exists as a mechanism to allow use of Autopsy as a platform
* with the core Autopsy user interface disabled, until such time as the
* user interface is made separable and optional.
*
* @return True or false.
*/
public static boolean coreComponentsAreActive() {
return coreComponentsActive;
}
}

View File

@ -0,0 +1,411 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.core;
import org.sleuthkit.autopsy.core.events.ServiceEvent;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.beans.PropertyChangeListener;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo;
import org.sleuthkit.autopsy.events.MessageServiceException;
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException;
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* This class periodically checks availability of collaboration resources -
* remote database, remote keyword search server, messaging service - and
* reports status updates to the user in case of a gap in service.
*/
public class ServicesMonitor {
private AutopsyEventPublisher eventPublisher;
private static final Logger logger = Logger.getLogger(ServicesMonitor.class.getName());
private final ScheduledThreadPoolExecutor periodicTasksExecutor;
private static final String PERIODIC_TASK_THREAD_NAME = "services-monitor-periodic-task-%d";
private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 1;
private static final long CRASH_DETECTION_INTERVAL_MINUTES = 2;
private static final Set<String> servicesList = Stream.of(ServicesMonitor.Service.values())
.map(Service::toString)
.collect(Collectors.toSet());
/**
* The service monitor maintains a mapping of each service to it's last
* status update.
*/
private final ConcurrentHashMap<String, String> statusByService;
/**
* Call constructor on start-up so that the first check of services is done
* as soon as possible.
*/
private static ServicesMonitor instance = new ServicesMonitor();
/**
* List of services that are being monitored. The service names should be
* representative of the service functionality and readable as they get
* logged when service outage occurs.
*/
public enum Service {
/**
* Property change event fired when remote case database service status
* changes. New value is set to updated ServiceStatus, old value is
* null.
*/
REMOTE_CASE_DATABASE("Multi-user case database service"),
/**
* Property change event fired when remote keyword search service status
* changes. New value is set to updated ServiceStatus, old value is
* null.
*/
REMOTE_KEYWORD_SEARCH("Multi-user keyword search service"),
/**
* Property change event fired when messaging service status changes.
* New value is set to updated ServiceStatus, old value is null.
*/
MESSAGING("Messaging service");
private final String displayName;
private Service(String name) {
this.displayName = name;
}
public String getDisplayName() {
return displayName;
}
};
/**
* List of possible service statuses.
*/
public enum ServiceStatus {
/**
* Service is currently up.
*/
UP,
/**
* Service is currently down.
*/
DOWN
};
public synchronized static ServicesMonitor getInstance() {
if (instance == null) {
instance = new ServicesMonitor();
}
return instance;
}
private ServicesMonitor() {
this.eventPublisher = new AutopsyEventPublisher();
this.statusByService = new ConcurrentHashMap<>();
// First check is triggered immediately on current thread.
checkAllServices();
/**
* Start periodic task that check the availability of key collaboration
* services.
*/
periodicTasksExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_PERIODIC_TASK_THREADS, new ThreadFactoryBuilder().setNameFormat(PERIODIC_TASK_THREAD_NAME).build());
periodicTasksExecutor.scheduleAtFixedRate(new CrashDetectionTask(), CRASH_DETECTION_INTERVAL_MINUTES, CRASH_DETECTION_INTERVAL_MINUTES, TimeUnit.MINUTES);
}
/**
* Updates service status and publishes the service status update if it is
* different from previous status. Event is published locally. Logs status
* changes.
*
* @param service Name of the service.
* @param status Updated status for the service.
* @param details Details of the event.
*
*/
public void setServiceStatus(String service, String status, String details) {
// if the status update is for an existing service who's status hasn't changed - do nothing.
if (statusByService.containsKey(service) && status.equals(statusByService.get(service))) {
return;
}
// new service or status has changed - identify service's display name
String serviceDisplayName;
try {
serviceDisplayName = ServicesMonitor.Service.valueOf(service).getDisplayName();
} catch (IllegalArgumentException ignore) {
// custom service that is not listed in ServicesMonitor.Service enum. Use service name as display name.
serviceDisplayName = service;
}
if (status.equals(ServiceStatus.UP.toString())) {
logger.log(Level.INFO, "Connection to {0} is up", serviceDisplayName); //NON-NLS
MessageNotifyUtil.Notify.info(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.restoredService.notify.title"),
NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.restoredService.notify.msg", serviceDisplayName));
} else if (status.equals(ServiceStatus.DOWN.toString())) {
logger.log(Level.SEVERE, "Failed to connect to {0}", serviceDisplayName); //NON-NLS
MessageNotifyUtil.Notify.error(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.failedService.notify.title"),
NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.failedService.notify.msg", serviceDisplayName));
} else {
logger.log(Level.INFO, "Status for {0} is {1}", new Object[]{serviceDisplayName, status}); //NON-NLS
MessageNotifyUtil.Notify.info(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.statusChange.notify.title"),
NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.statusChange.notify.msg", new Object[]{serviceDisplayName, status}));
}
// update and publish new status
statusByService.put(service, status);
eventPublisher.publishLocally(new ServiceEvent(service, status, details));
}
/**
* Get last status update for a service.
*
* @param service Name of the service.
*
* @return ServiceStatus Status for the service.
*
* @throws ServicesMonitorException If service name is null or service
* doesn't exist.
*/
public String getServiceStatus(String service) throws ServicesMonitorException {
if (service == null) {
throw new ServicesMonitorException(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.nullServiceName.excepton.txt"));
}
// if request is for one of our "core" services - perform an on demand check
// to make sure we have the latest status.
if (servicesList.contains(service)) {
checkServiceStatus(service);
}
String status = statusByService.get(service);
if (status == null) {
// no such service
throw new ServicesMonitorException(NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.unknownServiceName.excepton.txt", service));
}
return status;
}
/**
* Performs service availability status check.
*
* @param service Name of the service.
*/
private void checkServiceStatus(String service) {
if (service.equals(Service.REMOTE_CASE_DATABASE.toString())) {
checkDatabaseConnectionStatus();
} else if (service.equals(Service.REMOTE_KEYWORD_SEARCH.toString())) {
checkKeywordSearchServerConnectionStatus();
} else if (service.equals(Service.MESSAGING.toString())) {
checkMessagingServerConnectionStatus();
}
}
/**
* Performs case database service availability status check.
*/
private void checkDatabaseConnectionStatus() {
CaseDbConnectionInfo info;
try {
info = UserPreferences.getDatabaseConnectionInfo();
} catch (UserPreferencesException ex) {
logger.log(Level.SEVERE, "Error accessing case database connection info", ex); //NON-NLS
setServiceStatus(Service.REMOTE_CASE_DATABASE.toString(), ServiceStatus.DOWN.toString(), "Error accessing case database connection info");
return;
}
try {
SleuthkitCase.tryConnect(info);
setServiceStatus(Service.REMOTE_CASE_DATABASE.toString(), ServiceStatus.UP.toString(), "");
} catch (TskCoreException ex) {
setServiceStatus(Service.REMOTE_CASE_DATABASE.toString(), ServiceStatus.DOWN.toString(), ex.getMessage());
}
}
/**
* Performs keyword search service availability status check.
*/
private void checkKeywordSearchServerConnectionStatus() {
KeywordSearchService kwsService = Lookup.getDefault().lookup(KeywordSearchService.class);
try {
if (kwsService != null) {
int port = Integer.parseUnsignedInt(UserPreferences.getIndexingServerPort());
kwsService.tryConnect(UserPreferences.getIndexingServerHost(), port);
setServiceStatus(Service.REMOTE_KEYWORD_SEARCH.toString(), ServiceStatus.UP.toString(), "");
} else {
setServiceStatus(Service.REMOTE_KEYWORD_SEARCH.toString(), ServiceStatus.DOWN.toString(),
NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.KeywordSearchNull"));
}
} catch (NumberFormatException ex) {
String rootCause = NbBundle.getMessage(ServicesMonitor.class, "ServicesMonitor.InvalidPortNumber");
logger.log(Level.SEVERE, "Unable to connect to messaging server: " + rootCause, ex); //NON-NLS
setServiceStatus(Service.REMOTE_KEYWORD_SEARCH.toString(), ServiceStatus.DOWN.toString(), rootCause);
} catch (KeywordSearchServiceException ex) {
String rootCause = ex.getMessage();
logger.log(Level.SEVERE, "Unable to connect to messaging server: " + rootCause, ex); //NON-NLS
setServiceStatus(Service.REMOTE_KEYWORD_SEARCH.toString(), ServiceStatus.DOWN.toString(), rootCause);
}
}
/**
* Performs messaging service availability status check.
*/
private void checkMessagingServerConnectionStatus() {
MessageServiceConnectionInfo info;
try {
info = UserPreferences.getMessageServiceConnectionInfo();
} catch (UserPreferencesException ex) {
logger.log(Level.SEVERE, "Error accessing messaging service connection info", ex); //NON-NLS
setServiceStatus(Service.MESSAGING.toString(), ServiceStatus.DOWN.toString(), "Error accessing messaging service connection info");
return;
}
try {
info.tryConnect();
setServiceStatus(Service.MESSAGING.toString(), ServiceStatus.UP.toString(), "");
} catch (MessageServiceException ex) {
String rootCause = ex.getMessage();
logger.log(Level.SEVERE, "Unable to connect to messaging server: " + rootCause, ex); //NON-NLS
setServiceStatus(Service.MESSAGING.toString(), ServiceStatus.DOWN.toString(), rootCause);
}
}
/**
* Adds an event subscriber to this publisher. Subscriber will be subscribed
* to all events from this publisher.
*
* @param subscriber The subscriber to add.
*/
public void addSubscriber(PropertyChangeListener subscriber) {
eventPublisher.addSubscriber(servicesList, subscriber);
}
/**
* Adds an event subscriber to this publisher.
*
* @param eventNames The events the subscriber is interested in.
* @param subscriber The subscriber to add.
*/
public void addSubscriber(Set<String> eventNames, PropertyChangeListener subscriber) {
eventPublisher.addSubscriber(eventNames, subscriber);
}
/**
* Adds an event subscriber to this publisher.
*
* @param eventName The event the subscriber is interested in.
* @param subscriber The subscriber to add.
*/
public void addSubscriber(String eventName, PropertyChangeListener subscriber) {
eventPublisher.addSubscriber(eventName, subscriber);
}
/**
* Removes an event subscriber from this publisher.
*
* @param eventNames The events the subscriber is no longer interested in.
* @param subscriber The subscriber to remove.
*/
public void removeSubscriber(Set<String> eventNames, PropertyChangeListener subscriber) {
eventPublisher.removeSubscriber(eventNames, subscriber);
}
/**
* Removes an event subscriber from this publisher.
*
* @param eventName The event the subscriber is no longer interested in.
* @param subscriber The subscriber to remove.
*/
public void removeSubscriber(String eventName, PropertyChangeListener subscriber) {
eventPublisher.removeSubscriber(eventName, subscriber);
}
/**
* Removes an event subscriber to this publisher. Subscriber will be removed
* from all event notifications from this publisher.
*
* @param subscriber The subscriber to remove.
*/
public void removeSubscriber(PropertyChangeListener subscriber) {
eventPublisher.removeSubscriber(servicesList, subscriber);
}
/**
* Verifies connectivity to all services.
*/
private void checkAllServices() {
if (!UserPreferences.getIsMultiUserModeEnabled()) {
return;
}
for (String service : servicesList) {
checkServiceStatus(service);
}
}
/**
* A Runnable task that periodically checks the availability of
* collaboration resources (remote database, remote keyword search service,
* message broker) and reports status to the user in case of a gap in
* service.
*/
private final class CrashDetectionTask implements Runnable {
/**
* Monitor the availability of collaboration resources
*/
@Override
public void run() {
checkAllServices();
}
}
/**
* Exception thrown when service status query results in an error.
*/
public class ServicesMonitorException extends Exception {
private static final long serialVersionUID = 1L;
public ServicesMonitorException(String message) {
super(message);
}
public ServicesMonitorException(String message, Throwable cause) {
super(message, cause);
}
}
}

View File

@ -18,9 +18,20 @@
*/
package org.sleuthkit.autopsy.core;
import java.util.Base64;
import java.util.prefs.BackingStoreException;
import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo;
import java.util.prefs.PreferenceChangeListener;
import java.util.prefs.Preferences;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import org.openide.util.NbBundle;
import org.openide.util.NbPreferences;
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
import org.sleuthkit.datamodel.TskData.DbType;
/**
* Provides convenient access to a Preferences node for user preferences with
@ -34,11 +45,50 @@ public final class UserPreferences {
public static final String HIDE_KNOWN_FILES_IN_VIEWS_TREE = "HideKnownFilesInViewsTree"; //NON-NLS
public static final String DISPLAY_TIMES_IN_LOCAL_TIME = "DisplayTimesInLocalTime"; //NON-NLS
public static final String NUMBER_OF_FILE_INGEST_THREADS = "NumberOfFileIngestThreads"; //NON-NLS
public static final String IS_MULTI_USER_MODE_ENABLED = "IsMultiUserModeEnabled"; //NON-NLS
public static final String EXTERNAL_DATABASE_HOSTNAME_OR_IP = "ExternalDatabaseHostnameOrIp"; //NON-NLS
public static final String EXTERNAL_DATABASE_PORTNUMBER = "ExternalDatabasePortNumber"; //NON-NLS
public static final String EXTERNAL_DATABASE_NAME = "ExternalDatabaseName"; //NON-NLS
public static final String EXTERNAL_DATABASE_USER = "ExternalDatabaseUsername"; //NON-NLS
public static final String EXTERNAL_DATABASE_PASSWORD = "ExternalDatabasePassword"; //NON-NLS
public static final String EXTERNAL_DATABASE_TYPE = "ExternalDatabaseType"; //NON-NLS
public static final String INDEXING_SERVER_HOST = "IndexingServerHost"; //NON-NLS
public static final String INDEXING_SERVER_PORT = "IndexingServerPort"; //NON-NLS
private static final String MESSAGE_SERVICE_PASSWORD = "MessageServicePassword"; //NON-NLS
private static final String MESSAGE_SERVICE_USER = "MessageServiceUser"; //NON-NLS
private static final String MESSAGE_SERVICE_HOST = "MessageServiceHost"; //NON-NLS
private static final String MESSAGE_SERVICE_PORT = "MessageServicePort"; //NON-NLS
public static final String PROCESS_TIME_OUT_ENABLED = "ProcessTimeOutEnabled"; //NON-NLS
public static final String PROCESS_TIME_OUT_HOURS = "ProcessTimeOutHours"; //NON-NLS
private static final int DEFAULT_PROCESS_TIMEOUT_HR = 60;
private static final String DEFAULT_PORT_STRING = "61616";
private static final int DEFAULT_PORT_INT = 61616;
// Prevent instantiation.
private UserPreferences() {
}
/**
* Reload all preferences from disk. This is only needed if the preferences
* file is being directly modified on disk while Autopsy is running.
*
* @throws BackingStoreException
*/
public static void reloadFromStorage() throws BackingStoreException {
preferences.sync();
}
/**
* Saves the current preferences to storage. This is only needed if the
* preferences files are going to be copied to another location while
* Autopsy is running.
*
* @throws BackingStoreException
*/
public static void saveToStorage() throws BackingStoreException {
preferences.flush();
}
public static void addChangeListener(PreferenceChangeListener listener) {
preferences.addPreferenceChangeListener(listener);
}
@ -87,4 +137,209 @@ public final class UserPreferences {
preferences.putInt(NUMBER_OF_FILE_INGEST_THREADS, value);
}
/**
* Reads persisted case database connection info.
* @return An object encapsulating the database connection info.
* @throws org.sleuthkit.autopsy.core.UserPreferencesException
*/
public static CaseDbConnectionInfo getDatabaseConnectionInfo() throws UserPreferencesException {
DbType dbType;
try {
dbType = DbType.valueOf(preferences.get(EXTERNAL_DATABASE_TYPE, "POSTGRESQL"));
} catch (Exception ex) {
dbType = DbType.SQLITE;
}
return new CaseDbConnectionInfo(
preferences.get(EXTERNAL_DATABASE_HOSTNAME_OR_IP, ""),
preferences.get(EXTERNAL_DATABASE_PORTNUMBER, "5432"),
preferences.get(EXTERNAL_DATABASE_USER, ""),
TextConverter.convertHexTextToText(preferences.get(EXTERNAL_DATABASE_PASSWORD, "")),
dbType);
}
/**
* Persists case database connection info.
*
* @param connectionInfo An object encapsulating the database connection
* info.
* @throws org.sleuthkit.autopsy.core.UserPreferencesException
*/
public static void setDatabaseConnectionInfo(CaseDbConnectionInfo connectionInfo) throws UserPreferencesException {
preferences.put(EXTERNAL_DATABASE_HOSTNAME_OR_IP, connectionInfo.getHost());
preferences.put(EXTERNAL_DATABASE_PORTNUMBER, connectionInfo.getPort());
preferences.put(EXTERNAL_DATABASE_USER, connectionInfo.getUserName());
preferences.put(EXTERNAL_DATABASE_PASSWORD, TextConverter.convertTextToHexText(connectionInfo.getPassword()));
preferences.put(EXTERNAL_DATABASE_TYPE, connectionInfo.getDbType().toString());
}
public static void setIsMultiUserModeEnabled(boolean enabled) {
preferences.putBoolean(IS_MULTI_USER_MODE_ENABLED, enabled);
}
public static boolean getIsMultiUserModeEnabled() {
return preferences.getBoolean(IS_MULTI_USER_MODE_ENABLED, false);
}
public static String getIndexingServerHost() {
return preferences.get(INDEXING_SERVER_HOST, "");
}
public static void setIndexingServerHost(String hostName) {
preferences.put(INDEXING_SERVER_HOST, hostName);
}
public static String getIndexingServerPort() {
return preferences.get(INDEXING_SERVER_PORT, "8983");
}
public static void setIndexingServerPort(int port) {
preferences.putInt(INDEXING_SERVER_PORT, port);
}
/**
* Persists message service connection info.
*
* @param info An object encapsulating the message service info.
* @throws org.sleuthkit.autopsy.core.UserPreferencesException
*/
public static void setMessageServiceConnectionInfo(MessageServiceConnectionInfo info) throws UserPreferencesException {
preferences.put(MESSAGE_SERVICE_HOST, info.getHost());
preferences.put(MESSAGE_SERVICE_PORT, Integer.toString(info.getPort()));
preferences.put(MESSAGE_SERVICE_USER, info.getUserName());
preferences.put(MESSAGE_SERVICE_PASSWORD, TextConverter.convertTextToHexText(info.getPassword()));
}
/**
* Reads persisted message service connection info.
*
* @return An object encapsulating the message service info.
* @throws org.sleuthkit.autopsy.core.UserPreferencesException
*/
public static MessageServiceConnectionInfo getMessageServiceConnectionInfo() throws UserPreferencesException {
int port;
try {
port = Integer.parseInt(preferences.get(MESSAGE_SERVICE_PORT, DEFAULT_PORT_STRING));
} catch (NumberFormatException ex) {
// if there is an error parsing the port number, use the default port number
port = DEFAULT_PORT_INT;
}
return new MessageServiceConnectionInfo(
preferences.get(MESSAGE_SERVICE_HOST, ""),
port,
preferences.get(MESSAGE_SERVICE_USER, ""),
TextConverter.convertHexTextToText(preferences.get(MESSAGE_SERVICE_PASSWORD, "")));
}
/**
* Reads persisted process time out value.
*
* @return int Process time out value (hours).
*/
public static int getProcessTimeOutHrs() {
int timeOut = preferences.getInt(PROCESS_TIME_OUT_HOURS, DEFAULT_PROCESS_TIMEOUT_HR);
if (timeOut < 0) {
timeOut = 0;
}
return timeOut;
}
/**
* Stores persisted process time out value.
*
* @param value Persisted process time out value (hours).
*/
public static void setProcessTimeOutHrs(int value) {
if (value < 0) {
value = 0;
}
preferences.putInt(PROCESS_TIME_OUT_HOURS, value);
}
/**
* Reads persisted setting of whether process time out functionality is
* enabled.
*
* @return boolean True if process time out is functionality enabled, false
* otherwise.
*/
public static boolean getIsTimeOutEnabled() {
boolean enabled = preferences.getBoolean(PROCESS_TIME_OUT_ENABLED, false);
return enabled;
}
/**
* Stores persisted setting of whether process time out functionality is
* enabled.
*
* @param enabled Persisted setting of whether process time out
* functionality is enabled.
*/
public static void setIsTimeOutEnabled(boolean enabled) {
preferences.putBoolean(PROCESS_TIME_OUT_ENABLED, enabled);
}
/**
* Provides ability to convert text to hex text.
*/
static final class TextConverter {
private static final char[] TMP = "hgleri21auty84fwe".toCharArray();
private static final byte[] SALT = {
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,};
/**
* Convert text to hex text.
*
* @param property Input text string.
*
* @return Converted hex string.
*
* @throws org.sleuthkit.autopsy.core.UserPreferencesException
*/
static String convertTextToHexText(String property) throws UserPreferencesException {
try {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(TMP));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
return base64Encode(pbeCipher.doFinal(property.getBytes("UTF-8")));
} catch (Exception ex) {
throw new UserPreferencesException(
NbBundle.getMessage(TextConverter.class, "TextConverter.convert.exception.txt"));
}
}
private static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
/**
* Convert hex text back to text.
*
* @param property Input hex text string.
*
* @return Converted text string.
*
* @throws org.sleuthkit.autopsy.core.UserPreferencesException
*/
static String convertHexTextToText(String property) throws UserPreferencesException {
try {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(TMP));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
} catch (Exception ex) {
throw new UserPreferencesException(
NbBundle.getMessage(TextConverter.class, "TextConverter.convertFromHex.exception.txt"));
}
}
private static byte[] base64Decode(String property) {
return Base64.getDecoder().decode(property);
}
}
}

View File

@ -16,19 +16,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.events;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.ContentTag;
package org.sleuthkit.autopsy.core;
/**
* An event that is fired when a ContentTag is deleted.
* Exception thrown when text conversion (such as from text to hex text or vice versa) resulted in
* an error
*/
@Immutable
public class ContentTagDeletedEvent extends TagDeletedEvent<ContentTag> {
public ContentTagDeletedEvent(ContentTag deletedTag) {
super(Case.Events.CONTENT_TAG_DELETED.toString(), deletedTag);
public class UserPreferencesException extends Exception {
private static final long serialVersionUID = 1L;
public UserPreferencesException(String message) {
super(message);
}
public UserPreferencesException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,49 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.core.events;
import java.io.Serializable;
import org.sleuthkit.autopsy.events.AutopsyEvent;
/**
* A class for events to be published to registered subscribers of Service
* Monitor on this Autopsy node. The class extends PropertyChangeEvent (via
* AutopsyEvent) to integrate with legacy use of JavaBeans PropertyChangeEvents
* and PropertyChangeListeners as an application event system, and implements
* Serializable to allow it to be published over a network in serialized form.
*/
public final class ServiceEvent extends AutopsyEvent implements Serializable {
private static final long serialVersionUID = 1L;
private final String details;
public ServiceEvent(String serviceName, String status, String details) {
super(serviceName, null, status);
this.details = details;
}
/**
* Gets details string passed as input to ServiceEvent constructor.
*
* @return String Details of the event.
*/
public String getDetails() {
return details;
}
}

View File

@ -19,7 +19,7 @@
<folder name="Java.instance_hidden"/>
<folder name="Advanced.instance_hidden"/> <!-- Miscellaneous -->
<file name="org-sleuthkit-autopsy-corecomponents-AutopsyOptionsPanelController.instance">
<attr name="iconBase" stringvalue="org/sleuthkit/autopsy/corecomponents/checkbox.png"/>
<attr name="iconBase" stringvalue="org/sleuthkit/autopsy/corecomponents/checkbox32.png"/>
<attr name="instanceCreate" methodvalue="org.netbeans.spi.options.OptionsCategory.createCategory"/>
<attr name="keywordsCategory" stringvalue="General"/>
<attr name="position" intvalue="1"/>
@ -44,7 +44,6 @@
<file name="org-sleuthkit-autopsy-casemodule-CaseNewAction.instance">
<attr name="delegate" newvalue="org.sleuthkit.autopsy.casemodule.CaseNewAction"/>
<attr name="displayName" bundlevalue="org.sleuthkit.autopsy.casemodule.Bundle#CTL_CaseNewAction"/>
<attr name="instanceCreate" methodvalue="org.openide.awt.Actions.alwaysEnabled"/>
<attr name="noIconInMenu" boolvalue="false"/>
</file>
<file name="org-sleuthkit-autopsy-casemodule-CasePropertiesAction.instance"/>
@ -203,6 +202,13 @@
<attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-filesearch-FileSearchAction.instance"/>
<attr name="position" intvalue="200"/>
</file>
<folder name="RunIngestModules">
<attr name="position" intvalue="201"/>
<attr name="SystemFileSystem.localizingBundle" stringvalue="org.sleuthkit.autopsy.ingest.Bundle"/>
<file name="org-sleuthkit-autopsy-ingest-RunIngestAction.shadow">
<attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-ingest-RunIngestAction.instance"/>
</file>
</folder>
<file name="org-sleuthkit-autopsy-report-ReportWizardAction.shadow">
<attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-report-ReportWizardAction.instance"/>
<attr name="position" intvalue="100"/>
@ -215,6 +221,8 @@
<file name="Separator3.instance_hidden"/>-->
</folder>
<folder name="Window">
<file name="GroupsMenuAction.shadow_hidden"/>
<file name="Tools_hidden"/>
<file name="Web_hidden"/>
<file name="org-netbeans-modules-favorites-View.shadow_hidden"/>
<file name="CloneDocumentAction.shadow_hidden"/>
@ -227,6 +235,7 @@
<file name="ViewFavoritesTabAction.shadow_hidden"/>
<file name="org-netbeans-core-windows-actions-ResetWindowsAction.shadow_hidden"/>
<file name="testAction.shadow_hidden"/>
<file name="org-netbeans-core-io-ui-IOWindowAction.shadow_hidden"/>
<file name="org-sleuthkit-autopsy-menuactions-DataResultMenu-separatoBefore.instance">
<attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
<attr name="position" intvalue="75"/>

View File

@ -26,7 +26,7 @@ import java.net.URL;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JPanel;

View File

@ -6,8 +6,6 @@
</Component>
<Component class="javax.swing.ButtonGroup" name="buttonGroup3">
</Component>
<Component class="javax.swing.ButtonGroup" name="buttonGroupProcTimeOut">
</Component>
</NonVisualComponents>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
@ -58,6 +56,20 @@
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Component id="jCheckBoxEnableProcTimeout" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jFormattedTextFieldProcTimeOutHrs" min="-2" pref="27" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabelProcessTimeOutUnits" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="jLabelSetProcessTimeOut" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
@ -89,7 +101,17 @@
<Component id="numberOfFileIngestThreadsComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="restartRequiredLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="155" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jLabelSetProcessTimeOut" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jCheckBoxEnableProcTimeout" min="-2" max="-2" attributes="0"/>
<Group type="103" alignment="0" groupAlignment="3" attributes="0">
<Component id="jFormattedTextFieldProcTimeOutHrs" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabelProcessTimeOutUnits" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace pref="103" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -205,5 +227,39 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabelSetProcessTimeOut">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelSetProcessTimeOut.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="jCheckBoxEnableProcTimeout">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jCheckBoxEnableProcTimeout.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jCheckBoxEnableProcTimeoutActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="jLabelProcessTimeOutUnits">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelProcessTimeOutUnits.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JFormattedTextField" name="jFormattedTextFieldProcTimeOutHrs">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jFormattedTextFieldProcTimeOutHrs.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JFormattedTextField(NumberFormat.getIntegerInstance());"/>
</AuxValues>
</Component>
</SubComponents>
</Form>

View File

@ -18,7 +18,9 @@
*/
package org.sleuthkit.autopsy.corecomponents;
import java.text.NumberFormat;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JFormattedTextField;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.core.UserPreferences;
@ -81,6 +83,19 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
useLocalTimeRB.setSelected(useLocalTime);
useGMTTimeRB.setSelected(!useLocalTime);
numberOfFileIngestThreadsComboBox.setSelectedItem(UserPreferences.numberOfFileIngestThreads());
if (UserPreferences.getIsTimeOutEnabled()) {
// user specified time out
jCheckBoxEnableProcTimeout.setSelected(true);
jFormattedTextFieldProcTimeOutHrs.setEditable(true);
int timeOutHrs = UserPreferences.getProcessTimeOutHrs();
jFormattedTextFieldProcTimeOutHrs.setValue((long) timeOutHrs);
} else {
// never time out
jCheckBoxEnableProcTimeout.setSelected(false);
jFormattedTextFieldProcTimeOutHrs.setEditable(false);
int timeOutHrs = UserPreferences.getProcessTimeOutHrs();
jFormattedTextFieldProcTimeOutHrs.setValue((long) timeOutHrs);
}
}
void store() {
@ -89,6 +104,13 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
UserPreferences.setHideKnownFilesInViewsTree(viewsHideKnownCB.isSelected());
UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRB.isSelected());
UserPreferences.setNumberOfFileIngestThreads((Integer) numberOfFileIngestThreadsComboBox.getSelectedItem());
UserPreferences.setIsTimeOutEnabled(jCheckBoxEnableProcTimeout.isSelected());
if (jCheckBoxEnableProcTimeout.isSelected()) {
// only store time out if it is enabled
long timeOutHrs = (long) jFormattedTextFieldProcTimeOutHrs.getValue();
UserPreferences.setProcessTimeOutHrs((int) timeOutHrs);
}
}
boolean valid() {
@ -105,7 +127,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
buttonGroup1 = new javax.swing.ButtonGroup();
buttonGroup3 = new javax.swing.ButtonGroup();
buttonGroupProcTimeOut = new javax.swing.ButtonGroup();
useBestViewerRB = new javax.swing.JRadioButton();
keepCurrentViewerRB = new javax.swing.JRadioButton();
jLabelSelectFile = new javax.swing.JLabel();
@ -118,6 +139,10 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
jLabelNumThreads = new javax.swing.JLabel();
numberOfFileIngestThreadsComboBox = new javax.swing.JComboBox<Integer>();
restartRequiredLabel = new javax.swing.JLabel();
jLabelSetProcessTimeOut = new javax.swing.JLabel();
jCheckBoxEnableProcTimeout = new javax.swing.JCheckBox();
jLabelProcessTimeOutUnits = new javax.swing.JLabel();
jFormattedTextFieldProcTimeOutHrs = new JFormattedTextField(NumberFormat.getIntegerInstance());
buttonGroup1.add(useBestViewerRB);
useBestViewerRB.setSelected(true);
@ -150,6 +175,19 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
restartRequiredLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/warning16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(restartRequiredLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.restartRequiredLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabelSetProcessTimeOut, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelSetProcessTimeOut.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jCheckBoxEnableProcTimeout, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jCheckBoxEnableProcTimeout.text")); // NOI18N
jCheckBoxEnableProcTimeout.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jCheckBoxEnableProcTimeoutActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(jLabelProcessTimeOutUnits, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelProcessTimeOutUnits.text")); // NOI18N
jFormattedTextFieldProcTimeOutHrs.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jFormattedTextFieldProcTimeOutHrs.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@ -180,7 +218,18 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
.addComponent(useGMTTimeRB)))
.addComponent(jLabelSelectFile)
.addComponent(jLabelNumThreads))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(jCheckBoxEnableProcTimeout)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jFormattedTextFieldProcTimeOutHrs, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabelProcessTimeOutUnits))
.addComponent(jLabelSetProcessTimeOut))
.addGap(0, 0, Short.MAX_VALUE))))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -208,18 +257,33 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(numberOfFileIngestThreadsComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(restartRequiredLabel))
.addContainerGap(155, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jLabelSetProcessTimeOut)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jCheckBoxEnableProcTimeout)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jFormattedTextFieldProcTimeOutHrs, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabelProcessTimeOutUnits)))
.addContainerGap(103, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
private void jCheckBoxEnableProcTimeoutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBoxEnableProcTimeoutActionPerformed
jFormattedTextFieldProcTimeOutHrs.setEditable(jCheckBoxEnableProcTimeout.isSelected());
}//GEN-LAST:event_jCheckBoxEnableProcTimeoutActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.ButtonGroup buttonGroup3;
private javax.swing.ButtonGroup buttonGroupProcTimeOut;
private javax.swing.JCheckBox dataSourcesHideKnownCB;
private javax.swing.JCheckBox jCheckBoxEnableProcTimeout;
private javax.swing.JFormattedTextField jFormattedTextFieldProcTimeOutHrs;
private javax.swing.JLabel jLabelHideKnownFiles;
private javax.swing.JLabel jLabelNumThreads;
private javax.swing.JLabel jLabelProcessTimeOutUnits;
private javax.swing.JLabel jLabelSelectFile;
private javax.swing.JLabel jLabelSetProcessTimeOut;
private javax.swing.JLabel jLabelTimeDisplay;
private javax.swing.JRadioButton keepCurrentViewerRB;
private javax.swing.JComboBox<Integer> numberOfFileIngestThreadsComboBox;

View File

@ -30,7 +30,7 @@ import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
@OptionsPanelController.TopLevelRegistration(categoryName = "#OptionsCategory_Name_General",
iconBase = "org/sleuthkit/autopsy/corecomponents/checkbox.png",
iconBase = "org/sleuthkit/autopsy/corecomponents/checkbox32.png",
position = 1,
keywords = "#OptionsCategory_Keywords_General",
keywordsCategory = "General")

View File

@ -147,7 +147,52 @@ AutopsyOptionsPanel.jLabelNumThreads.text=Number of threads to use for file inge
FXVideoPanel.progress.bufferingCancelled=media buffering was canceled
FXVideoPanel.progress.bufferingInterrupted=media buffering was interrupted
FXVideoPanel.progress.errorWritingVideoToDisk=Error writing video to disk
OptionsCategory_Name_Multi_User_Settings=Multi-user
OptionsCategory_Keywords_Multi_User_Options=Multi-user Options
MultiUserSettingsPanel.lbSolrSettings.text=Solr Settings
MultiUserSettingsPanel.cbEnableMultiUser.text=Enable Multi-user cases
MultiUserSettingsPanel.lbDatabaseSettings.text=Database Settings
MultiUserSettingsPanel.validationErrMsg.incomplete=Fill in all values
MultiUserSettingsPanel.validationErrMsg.invalidDatabasePort=Invalid database port number
MultiUserSettingsPanel.validationErrMsg.invalidMessageServicePort=Invalid message service port number
MultiUserSettingsPanel.validationErrMsg.invalidIndexingServerPort=Invalid Solr server port number
MultiUserSettingsPanel.validationErrMsg.invalidMessgeServiceURI=Message service host and/or port not valid
AutopsyOptionsPanel.jCheckBoxEnableProcTimeout.text=
AutopsyOptionsPanel.jFormattedTextFieldProcTimeOutHrs.text=60
AutopsyOptionsPanel.jLabelProcessTimeOutUnits.text=hour(s)
AutopsyOptionsPanel.jLabelSetProcessTimeOut.text=Enable timeout to allow modules to automatically terminate after a set amount of time:
DataContentViewerHex.goToOffsetLabel.text=Jump to Offset
DataContentViewerHex.goToOffsetTextField.text=
DataContentViewerHex.goToOffsetTextField.msgDlg=Invalid Offset: {0}
DataContentViewerHex.setDataView.invalidOffset.negativeOffsetValue=Cannot jump to the resultant offset
DataContentViewerHex.setDataView.invalidOffset.negativeOffsetValue=Cannot jump to the resultant offset
MultiUserSettingsPanel.tbOops.text=
MultiUserSettingsPanel.lbTestDatabase.text=
MultiUserSettingsPanel.bnTestDatabase.text=Test
MultiUserSettingsPanel.tbDbHostname.toolTipText=Hostname or IP Address
MultiUserSettingsPanel.tbDbHostname.text=
MultiUserSettingsPanel.tbDbPort.toolTipText=Port Number
MultiUserSettingsPanel.tbDbPort.text=
MultiUserSettingsPanel.tbDbUsername.toolTipText=User Name
MultiUserSettingsPanel.tbDbUsername.text=
MultiUserSettingsPanel.tbDbPassword.toolTipText=Password
MultiUserSettingsPanel.tbDbPassword.text=
MultiUserSettingsPanel.lbTestSolr.text=
MultiUserSettingsPanel.bnTestSolr.text=Test
MultiUserSettingsPanel.tbSolrHostname.toolTipText=Hostname or IP Address
MultiUserSettingsPanel.tbSolrPort.toolTipText=Port Number
MultiUserSettingsPanel.lbTestMessageService.text=
MultiUserSettingsPanel.bnTestMessageService.text=Test
MultiUserSettingsPanel.lbMessageServiceSettings.text=ActiveMQ Message Service Settings
MultiUserSettingsPanel.tbMsgPort.toolTipText=Port Number
MultiUserSettingsPanel.tbMsgPort.text=
MultiUserSettingsPanel.tbMsgUsername.toolTipText=User Name
MultiUserSettingsPanel.tbMsgUsername.text=
MultiUserSettingsPanel.tbMsgPassword.toolTipText=Password
MultiUserSettingsPanel.tbMsgPassword.text=
MultiUserSettingsPanel.tbMsgHostname.toolTipText=Hostname or IP Address
MultiUserSettingsPanel.tbMsgHostname.text=
MultiUserSettingsPanel.lbTestMessageWarning.text=
MultiUserSettingsPanel.lbTestSolrWarning.text=
MultiUserSettingsPanel.lbTestDbWarning.text=
MultiUserSettingsPanel.KeywordSearchNull=Cannot find Keyword Search service
MultiUserSettingsPanel.InvalidPortNumber=Invalid port number.

View File

@ -171,7 +171,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
}
/**
* is the given file a video we can display?
* Is the given file a video we can display?
*
* @param file
*
@ -185,14 +185,13 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
}
/**
* is the given file an image that we can display?
* Is the given file an image that we can display?
*
* @param file
*
* @return True if an image file that can be displayed
*/
private boolean isImageSupported(AbstractFile file) {
if (null == file || file.getSize() == 0) {
return false;
}

View File

@ -45,11 +45,7 @@
</Group>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="iconView" pref="563" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
<Component id="iconView" alignment="0" pref="563" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>

View File

@ -578,6 +578,5 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
}
}
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -69,25 +69,26 @@ public class Installer extends ModuleInstall {
/*
* Open the passed in case, if an aut file was double clicked.
*/
WindowManager.getDefault().invokeWhenUIReady(new Runnable() {
@Override
public void run() {
Collection<? extends OptionProcessor> processors = Lookup.getDefault().lookupAll(OptionProcessor.class);
for (OptionProcessor processor : processors) {
if (processor instanceof OpenFromArguments) {
OpenFromArguments argsProcessor = (OpenFromArguments) processor;
String caseFile = argsProcessor.getDefaultArg();
if (caseFile != null && !caseFile.equals("") && caseFile.endsWith(".aut") && new File(caseFile).exists()) { //NON-NLS
WindowManager.getDefault().invokeWhenUIReady(() -> {
Collection<? extends OptionProcessor> processors = Lookup.getDefault().lookupAll(OptionProcessor.class);
for (OptionProcessor processor : processors) {
if (processor instanceof OpenFromArguments) {
OpenFromArguments argsProcessor = (OpenFromArguments) processor;
final String caseFile = argsProcessor.getDefaultArg();
if (caseFile != null && !caseFile.equals("") && caseFile.endsWith(".aut") && new File(caseFile).exists()) { //NON-NLS
new Thread(() -> {
// Create case.
try {
Case.open(caseFile);
return;
} catch (Exception e) {
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error opening case: ", ex); //NON-NLS
}
}
}).start();
return;
}
}
Case.invokeStartupDialog(); // bring up the startup dialog
}
Case.invokeStartupDialog(); // bring up the startup dialog
});
}
@ -95,18 +96,19 @@ public class Installer extends ModuleInstall {
@Override
public void uninstalled() {
super.uninstalled();
}
@Override
public void close() {
try {
if (Case.isCaseOpen()) {
Case.getCurrentCase().closeCase();
new Thread(() -> {
try {
if (Case.isCaseOpen()) {
Case.getCurrentCase().closeCase();
}
} catch (CaseActionException | IllegalStateException unused) {
// Exception already logged. Shutting down, no need to do popup.
}
} catch (CaseActionException ex) {
logger.log(Level.WARNING, "Error closing case. ", ex); //NON-NLS
}
}).start();
}
private void setupLAF() {
@ -157,8 +159,8 @@ public class Installer extends ModuleInstall {
}
// Overwrite the Metal menu item keys to use the Aqua versions
for (Map.Entry<Object, Object> entry : uiEntries.entrySet()) {
uiEntries.entrySet().stream().forEach((entry) -> {
UIManager.put(entry.getKey(), entry.getValue());
}
});
}
}

View File

@ -239,5 +239,4 @@ public class MediaViewImagePanel extends JPanel implements DataContentViewerMedi
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,520 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="pnOverallPanel" min="-2" pref="555" max="-2" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="pnOverallPanel" alignment="0" min="-2" pref="559" max="-2" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="pnOverallPanel">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="cbEnableMultiUser" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="tbOops" max="32767" attributes="0"/>
</Group>
<Component id="pnSolrSettings" alignment="0" max="32767" attributes="0"/>
<Component id="pnDatabaseSettings" alignment="0" max="32767" attributes="0"/>
<Component id="pnMessagingSettings" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="2" attributes="0">
<Component id="tbOops" alignment="2" min="-2" max="-2" attributes="0"/>
<Component id="cbEnableMultiUser" alignment="2" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="pnDatabaseSettings" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="pnSolrSettings" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="pnMessagingSettings" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="39" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="pnDatabaseSettings">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
<EtchetBorder/>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="tbDbHostname" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="lbDatabaseSettings" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="bnTestDatabase" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="lbTestDatabase" min="-2" pref="16" max="-2" attributes="0"/>
</Group>
<Component id="tbDbPort" alignment="0" max="32767" attributes="0"/>
<Component id="tbDbUsername" alignment="0" max="32767" attributes="0"/>
<Component id="tbDbPassword" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="lbTestDbWarning" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="bnTestDatabase" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lbTestDatabase" alignment="0" min="-2" pref="23" max="-2" attributes="0"/>
<Component id="lbDatabaseSettings" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Component id="tbDbHostname" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="tbDbPort" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="tbDbUsername" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="tbDbPassword" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lbTestDbWarning" min="-2" pref="16" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JTextField" name="tbDbHostname">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbDbHostname.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbDbHostname.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="tbDbPort">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbDbPort.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbDbPort.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="tbDbUsername">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbDbUsername.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbDbUsername.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JPasswordField" name="tbDbPassword">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbDbPassword.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbDbPassword.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lbDatabaseSettings">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.lbDatabaseSettings.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="verticalAlignment" type="int" value="1"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="bnTestDatabase">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.bnTestDatabase.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnTestDatabaseActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lbTestDatabase">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.lbTestDatabase.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="autoscrolls" type="boolean" value="true"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lbTestDbWarning">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.lbTestDbWarning.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="pnSolrSettings">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
<EtchetBorder/>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="tbSolrHostname" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="lbSolrSettings" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="bnTestSolr" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="lbTestSolr" min="-2" pref="16" max="-2" attributes="0"/>
</Group>
<Component id="tbSolrPort" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="lbTestSolrWarning" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="bnTestSolr" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="lbSolrSettings" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="lbTestSolr" alignment="1" min="-2" pref="23" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="tbSolrHostname" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="tbSolrPort" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lbTestSolrWarning" min="-2" pref="16" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="lbSolrSettings">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.lbSolrSettings.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="tbSolrHostname">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="0"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbSolrHostname.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="tbSolrPort">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="0"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbSolrPort.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="bnTestSolr">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.bnTestSolr.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnTestSolrActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lbTestSolr">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.lbTestSolr.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lbTestSolrWarning">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.lbTestSolrWarning.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="pnMessagingSettings">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
<EtchetBorder/>
</Border>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="tbMsgHostname" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="lbMessageServiceSettings" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="229" max="32767" attributes="0"/>
<Component id="bnTestMessageService" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="lbTestMessageService" min="-2" pref="16" max="-2" attributes="0"/>
</Group>
<Component id="tbMsgPort" alignment="0" max="32767" attributes="0"/>
<Component id="tbMsgUsername" alignment="0" max="32767" attributes="0"/>
<Component id="tbMsgPassword" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="lbTestMessageWarning" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="bnTestMessageService" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="lbMessageServiceSettings" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="lbTestMessageService" min="-2" pref="23" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="tbMsgHostname" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="tbMsgPort" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="tbMsgUsername" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="tbMsgPassword" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lbTestMessageWarning" min="-2" pref="16" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="lbMessageServiceSettings">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.lbMessageServiceSettings.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="tbMsgHostname">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbMsgHostname.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbMsgHostname.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="tbMsgUsername">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbMsgUsername.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbMsgUsername.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="tbMsgPort">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbMsgPort.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbMsgPort.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JPasswordField" name="tbMsgPassword">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbMsgPassword.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbMsgPassword.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="bnTestMessageService">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.bnTestMessageService.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnTestMessageServiceActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="lbTestMessageService">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.lbTestMessageService.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lbTestMessageWarning">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.lbTestMessageWarning.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JCheckBox" name="cbEnableMultiUser">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.cbEnableMultiUser.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="cbEnableMultiUserItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="tbOops">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="1"/>
</Property>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MultiUserSettingsPanel.tbOops.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,862 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.corecomponents;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Collection;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
import org.sleuthkit.datamodel.TskData.DbType;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo;
import org.sleuthkit.autopsy.coreutils.Logger;
import java.awt.Cursor;
import java.util.logging.Level;
import javax.swing.ImageIcon;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.core.UserPreferencesException;
import org.sleuthkit.autopsy.events.MessageServiceException;
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
public final class MultiUserSettingsPanel extends javax.swing.JPanel {
private static final String HOST_NAME_OR_IP_PROMPT = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbDbHostname.toolTipText");
private static final String PORT_PROMPT = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbDbPort.toolTipText");
private static final String USER_NAME_PROMPT = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbDbUsername.toolTipText");
private static final String PASSWORD_PROMPT = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbDbPassword.toolTipText");
private static final String INCOMPLETE_SETTINGS_MSG = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.validationErrMsg.incomplete");
private static final String INVALID_DB_PORT_MSG = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.validationErrMsg.invalidDatabasePort");
private static final String INVALID_MESSAGE_SERVICE_PORT_MSG = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.validationErrMsg.invalidMessageServicePort");
private static final String INVALID_INDEXING_SERVER_PORT_MSG = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.validationErrMsg.invalidIndexingServerPort");
private static final int DEFAULT_MESSAGE_SERVICE_PORT = 61616;
private static final long serialVersionUID = 1L;
private final MultiUserSettingsPanelController controller;
private final Collection<JTextField> textBoxes = new ArrayList<>();
private final TextBoxChangedListener textBoxChangedListener;
private static final Logger logger = Logger.getLogger(MultiUserSettingsPanel.class.getName());
private final ImageIcon goodIcon;
private final ImageIcon badIcon;
/**
* Creates new form AutopsyMultiUserSettingsPanel
*
* @param theController Controller to notify of changes.
*/
public MultiUserSettingsPanel(MultiUserSettingsPanelController theController) {
initComponents();
controller = theController;
setSize(555, 600);
/**
* Add text prompts to all of the text fields.
*/
Collection<TextPrompt> textPrompts = new ArrayList<>();
textPrompts.add(new TextPrompt(HOST_NAME_OR_IP_PROMPT, tbDbHostname));
textPrompts.add(new TextPrompt(PORT_PROMPT, tbDbPort));
textPrompts.add(new TextPrompt(USER_NAME_PROMPT, tbDbUsername));
textPrompts.add(new TextPrompt(PASSWORD_PROMPT, tbDbPassword));
textPrompts.add(new TextPrompt(HOST_NAME_OR_IP_PROMPT, tbMsgHostname));
textPrompts.add(new TextPrompt(PORT_PROMPT, tbMsgPort));
textPrompts.add(new TextPrompt(USER_NAME_PROMPT, tbMsgUsername));
textPrompts.add(new TextPrompt(PASSWORD_PROMPT, tbMsgPassword));
textPrompts.add(new TextPrompt(HOST_NAME_OR_IP_PROMPT, tbSolrHostname));
textPrompts.add(new TextPrompt(PORT_PROMPT, tbSolrPort));
configureTextPrompts(textPrompts);
/* Set each textbox with a "statusIcon" property enabling the
DocumentListeners to know which icon to erase when changes are made */
tbDbHostname.getDocument().putProperty("statusIcon", lbTestDatabase);
tbDbPort.getDocument().putProperty("statusIcon", lbTestDatabase);
tbDbUsername.getDocument().putProperty("statusIcon", lbTestDatabase);
tbDbPassword.getDocument().putProperty("statusIcon", lbTestDatabase);
tbSolrHostname.getDocument().putProperty("statusIcon", lbTestSolr);
tbSolrPort.getDocument().putProperty("statusIcon", lbTestSolr);
tbMsgHostname.getDocument().putProperty("statusIcon", lbTestMessageService);
tbMsgPort.getDocument().putProperty("statusIcon", lbTestMessageService);
tbMsgUsername.getDocument().putProperty("statusIcon", lbTestMessageService);
tbMsgPassword.getDocument().putProperty("statusIcon", lbTestMessageService);
/// Register for notifications when the text boxes get updated.
textBoxChangedListener = new TextBoxChangedListener();
textBoxes.add(tbDbHostname);
textBoxes.add(tbDbPort);
textBoxes.add(tbDbUsername);
textBoxes.add(tbDbPassword);
textBoxes.add(tbMsgHostname);
textBoxes.add(tbMsgPort);
textBoxes.add(tbMsgUsername);
textBoxes.add(tbMsgPassword);
textBoxes.add(tbSolrHostname);
textBoxes.add(tbSolrPort);
addDocumentListeners(textBoxes, textBoxChangedListener);
goodIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/good.png", false));
badIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/bad.png", false));
enableMultiUserComponents(textBoxes, cbEnableMultiUser.isSelected());
}
/**
* Sets the foreground color and transparency of a collection of text
* prompts.
*
* @param textPrompts The text prompts to configure.
*/
private static void configureTextPrompts(Collection<TextPrompt> textPrompts) {
float alpha = 0.9f; // Mostly opaque
for (TextPrompt textPrompt : textPrompts) {
textPrompt.setForeground(Color.LIGHT_GRAY);
textPrompt.changeAlpha(alpha);
}
}
/**
* Adds a change listener to a collection of text fields.
*
* @param textFields The text fields.
* @param listener The change listener.
*/
private static void addDocumentListeners(Collection<JTextField> textFields, TextBoxChangedListener listener) {
for (JTextField textField : textFields) {
textField.getDocument().addDocumentListener(listener);
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
pnOverallPanel = new javax.swing.JPanel();
pnDatabaseSettings = new javax.swing.JPanel();
tbDbHostname = new javax.swing.JTextField();
tbDbPort = new javax.swing.JTextField();
tbDbUsername = new javax.swing.JTextField();
tbDbPassword = new javax.swing.JPasswordField();
lbDatabaseSettings = new javax.swing.JLabel();
bnTestDatabase = new javax.swing.JButton();
lbTestDatabase = new javax.swing.JLabel();
lbTestDbWarning = new javax.swing.JLabel();
pnSolrSettings = new javax.swing.JPanel();
lbSolrSettings = new javax.swing.JLabel();
tbSolrHostname = new javax.swing.JTextField();
tbSolrPort = new javax.swing.JTextField();
bnTestSolr = new javax.swing.JButton();
lbTestSolr = new javax.swing.JLabel();
lbTestSolrWarning = new javax.swing.JLabel();
pnMessagingSettings = new javax.swing.JPanel();
lbMessageServiceSettings = new javax.swing.JLabel();
tbMsgHostname = new javax.swing.JTextField();
tbMsgUsername = new javax.swing.JTextField();
tbMsgPort = new javax.swing.JTextField();
tbMsgPassword = new javax.swing.JPasswordField();
bnTestMessageService = new javax.swing.JButton();
lbTestMessageService = new javax.swing.JLabel();
lbTestMessageWarning = new javax.swing.JLabel();
cbEnableMultiUser = new javax.swing.JCheckBox();
tbOops = new javax.swing.JTextField();
pnDatabaseSettings.setBorder(javax.swing.BorderFactory.createEtchedBorder());
tbDbHostname.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
tbDbHostname.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbDbHostname.text")); // NOI18N
tbDbHostname.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbDbHostname.toolTipText")); // NOI18N
tbDbPort.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
tbDbPort.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbDbPort.text")); // NOI18N
tbDbPort.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbDbPort.toolTipText")); // NOI18N
tbDbUsername.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
tbDbUsername.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbDbUsername.text")); // NOI18N
tbDbUsername.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbDbUsername.toolTipText")); // NOI18N
tbDbPassword.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
tbDbPassword.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbDbPassword.text")); // NOI18N
tbDbPassword.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbDbPassword.toolTipText")); // NOI18N
lbDatabaseSettings.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(lbDatabaseSettings, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.lbDatabaseSettings.text")); // NOI18N
lbDatabaseSettings.setVerticalAlignment(javax.swing.SwingConstants.TOP);
org.openide.awt.Mnemonics.setLocalizedText(bnTestDatabase, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.bnTestDatabase.text")); // NOI18N
bnTestDatabase.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
bnTestDatabaseActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(lbTestDatabase, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.lbTestDatabase.text")); // NOI18N
lbTestDatabase.setAutoscrolls(true);
lbTestDbWarning.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(lbTestDbWarning, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.lbTestDbWarning.text")); // NOI18N
javax.swing.GroupLayout pnDatabaseSettingsLayout = new javax.swing.GroupLayout(pnDatabaseSettings);
pnDatabaseSettings.setLayout(pnDatabaseSettingsLayout);
pnDatabaseSettingsLayout.setHorizontalGroup(
pnDatabaseSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnDatabaseSettingsLayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnDatabaseSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tbDbHostname)
.addGroup(pnDatabaseSettingsLayout.createSequentialGroup()
.addComponent(lbDatabaseSettings)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(bnTestDatabase)
.addGap(18, 18, 18)
.addComponent(lbTestDatabase, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(tbDbPort)
.addComponent(tbDbUsername)
.addComponent(tbDbPassword)
.addGroup(pnDatabaseSettingsLayout.createSequentialGroup()
.addComponent(lbTestDbWarning)
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
pnDatabaseSettingsLayout.setVerticalGroup(
pnDatabaseSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnDatabaseSettingsLayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnDatabaseSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(bnTestDatabase)
.addComponent(lbTestDatabase, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lbDatabaseSettings))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(tbDbHostname, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tbDbPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tbDbUsername, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tbDbPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lbTestDbWarning, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
pnSolrSettings.setBorder(javax.swing.BorderFactory.createEtchedBorder());
lbSolrSettings.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(lbSolrSettings, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.lbSolrSettings.text")); // NOI18N
tbSolrHostname.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
tbSolrHostname.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbSolrHostname.toolTipText")); // NOI18N
tbSolrPort.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
tbSolrPort.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbSolrPort.toolTipText")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(bnTestSolr, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.bnTestSolr.text")); // NOI18N
bnTestSolr.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
bnTestSolrActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(lbTestSolr, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.lbTestSolr.text")); // NOI18N
lbTestSolrWarning.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(lbTestSolrWarning, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.lbTestSolrWarning.text")); // NOI18N
javax.swing.GroupLayout pnSolrSettingsLayout = new javax.swing.GroupLayout(pnSolrSettings);
pnSolrSettings.setLayout(pnSolrSettingsLayout);
pnSolrSettingsLayout.setHorizontalGroup(
pnSolrSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnSolrSettingsLayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnSolrSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tbSolrHostname)
.addGroup(pnSolrSettingsLayout.createSequentialGroup()
.addComponent(lbSolrSettings)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(bnTestSolr)
.addGap(18, 18, 18)
.addComponent(lbTestSolr, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(tbSolrPort)
.addGroup(pnSolrSettingsLayout.createSequentialGroup()
.addComponent(lbTestSolrWarning)
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
pnSolrSettingsLayout.setVerticalGroup(
pnSolrSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnSolrSettingsLayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnSolrSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnSolrSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(bnTestSolr, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lbSolrSettings))
.addComponent(lbTestSolr, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tbSolrHostname, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(tbSolrPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lbTestSolrWarning, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
pnMessagingSettings.setBorder(javax.swing.BorderFactory.createEtchedBorder());
lbMessageServiceSettings.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(lbMessageServiceSettings, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.lbMessageServiceSettings.text")); // NOI18N
tbMsgHostname.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
tbMsgHostname.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbMsgHostname.text")); // NOI18N
tbMsgHostname.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbMsgHostname.toolTipText")); // NOI18N
tbMsgUsername.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
tbMsgUsername.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbMsgUsername.text")); // NOI18N
tbMsgUsername.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbMsgUsername.toolTipText")); // NOI18N
tbMsgPort.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
tbMsgPort.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbMsgPort.text")); // NOI18N
tbMsgPort.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbMsgPort.toolTipText")); // NOI18N
tbMsgPassword.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
tbMsgPassword.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbMsgPassword.text")); // NOI18N
tbMsgPassword.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbMsgPassword.toolTipText")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(bnTestMessageService, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.bnTestMessageService.text")); // NOI18N
bnTestMessageService.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
bnTestMessageServiceActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(lbTestMessageService, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.lbTestMessageService.text")); // NOI18N
lbTestMessageWarning.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(lbTestMessageWarning, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.lbTestMessageWarning.text")); // NOI18N
javax.swing.GroupLayout pnMessagingSettingsLayout = new javax.swing.GroupLayout(pnMessagingSettings);
pnMessagingSettings.setLayout(pnMessagingSettingsLayout);
pnMessagingSettingsLayout.setHorizontalGroup(
pnMessagingSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnMessagingSettingsLayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnMessagingSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tbMsgHostname)
.addGroup(pnMessagingSettingsLayout.createSequentialGroup()
.addComponent(lbMessageServiceSettings)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 229, Short.MAX_VALUE)
.addComponent(bnTestMessageService)
.addGap(18, 18, 18)
.addComponent(lbTestMessageService, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(tbMsgPort)
.addComponent(tbMsgUsername)
.addComponent(tbMsgPassword)
.addGroup(pnMessagingSettingsLayout.createSequentialGroup()
.addComponent(lbTestMessageWarning)
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
pnMessagingSettingsLayout.setVerticalGroup(
pnMessagingSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnMessagingSettingsLayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnMessagingSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(pnMessagingSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(bnTestMessageService, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lbMessageServiceSettings))
.addComponent(lbTestMessageService, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tbMsgHostname, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tbMsgPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tbMsgUsername, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tbMsgPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lbTestMessageWarning, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
org.openide.awt.Mnemonics.setLocalizedText(cbEnableMultiUser, org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.cbEnableMultiUser.text")); // NOI18N
cbEnableMultiUser.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
cbEnableMultiUserItemStateChanged(evt);
}
});
tbOops.setEditable(false);
tbOops.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
tbOops.setForeground(new java.awt.Color(255, 0, 0));
tbOops.setText(org.openide.util.NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.tbOops.text")); // NOI18N
tbOops.setBorder(null);
javax.swing.GroupLayout pnOverallPanelLayout = new javax.swing.GroupLayout(pnOverallPanel);
pnOverallPanel.setLayout(pnOverallPanelLayout);
pnOverallPanelLayout.setHorizontalGroup(
pnOverallPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnOverallPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnOverallPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addGroup(pnOverallPanelLayout.createSequentialGroup()
.addComponent(cbEnableMultiUser)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tbOops))
.addComponent(pnSolrSettings, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(pnDatabaseSettings, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(pnMessagingSettings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap())
);
pnOverallPanelLayout.setVerticalGroup(
pnOverallPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnOverallPanelLayout.createSequentialGroup()
.addGroup(pnOverallPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(cbEnableMultiUser))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(pnDatabaseSettings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(pnSolrSettings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(pnMessagingSettings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(39, Short.MAX_VALUE))
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pnOverallPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 555, javax.swing.GroupLayout.PREFERRED_SIZE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pnOverallPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 559, javax.swing.GroupLayout.PREFERRED_SIZE)
);
}// </editor-fold>//GEN-END:initComponents
/**
* Enables/disables the multi-user settings, based upon input provided
*
* @param enabled true means enable, false means disable
*/
private static void enableMultiUserComponents(Collection<JTextField> textFields, boolean enabled) {
for (JTextField textField : textFields) {
textField.setEnabled(enabled);
}
}
private void cbEnableMultiUserItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cbEnableMultiUserItemStateChanged
if (!cbEnableMultiUser.isSelected()) {
tbOops.setText("");
bnTestDatabase.setEnabled(false);
lbTestDatabase.setIcon(null);
bnTestSolr.setEnabled(false);
lbTestSolr.setIcon(null);
bnTestMessageService.setEnabled(false);
lbTestMessageService.setIcon(null);
lbTestDbWarning.setText("");
lbTestSolrWarning.setText("");
lbTestMessageWarning.setText("");
}
enableMultiUserComponents(textBoxes, cbEnableMultiUser.isSelected());
controller.changed();
}//GEN-LAST:event_cbEnableMultiUserItemStateChanged
private void bnTestDatabaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnTestDatabaseActionPerformed
lbTestDatabase.setIcon(null);
lbTestDbWarning.setText("");
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
try {
CaseDbConnectionInfo info = new CaseDbConnectionInfo(
this.tbDbHostname.getText().trim(),
this.tbDbPort.getText().trim(),
this.tbDbUsername.getText().trim(),
new String(this.tbDbPassword.getPassword()),
DbType.POSTGRESQL);
SleuthkitCase.tryConnect(info);
lbTestDatabase.setIcon(goodIcon);
lbTestDbWarning.setText("");
} catch (TskCoreException ex) {
lbTestDatabase.setIcon(badIcon);
lbTestDbWarning.setText(ex.getMessage());
} finally {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}//GEN-LAST:event_bnTestDatabaseActionPerformed
private void bnTestMessageServiceActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnTestMessageServiceActionPerformed
lbTestMessageService.setIcon(null);
lbTestMessageWarning.setText("");
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
int port;
try {
port = Integer.parseInt(this.tbMsgPort.getText().trim());
} catch (NumberFormatException ex) {
lbTestMessageService.setIcon(badIcon);
lbTestMessageWarning.setText(NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.InvalidPortNumber"));
return;
}
MessageServiceConnectionInfo info = new MessageServiceConnectionInfo(
this.tbMsgHostname.getText().trim(),
port,
this.tbMsgUsername.getText().trim(),
new String(this.tbMsgPassword.getPassword()));
try {
info.tryConnect();
lbTestMessageService.setIcon(goodIcon);
lbTestMessageWarning.setText("");
} catch (MessageServiceException ex) {
lbTestMessageService.setIcon(badIcon);
lbTestMessageWarning.setText(ex.getMessage());
} finally {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}//GEN-LAST:event_bnTestMessageServiceActionPerformed
private void bnTestSolrActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnTestSolrActionPerformed
lbTestSolr.setIcon(null);
lbTestSolrWarning.setText("");
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
KeywordSearchService kwsService = Lookup.getDefault().lookup(KeywordSearchService.class);
try {
if (kwsService != null) {
int port = Integer.parseInt(tbSolrPort.getText().trim());
kwsService.tryConnect(tbSolrHostname.getText().trim(), port);
lbTestSolr.setIcon(goodIcon);
lbTestSolrWarning.setText("");
} else {
lbTestSolr.setIcon(badIcon);
lbTestSolrWarning.setText(NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.KeywordSearchNull"));
}
} catch (NumberFormatException ex) {
lbTestSolr.setIcon(badIcon);
lbTestSolrWarning.setText(NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.InvalidPortNumber"));
} catch (KeywordSearchServiceException ex) {
lbTestSolr.setIcon(badIcon);
lbTestSolrWarning.setText(ex.getMessage());
} finally {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}//GEN-LAST:event_bnTestSolrActionPerformed
void load() {
lbTestDatabase.setIcon(null);
lbTestSolr.setIcon(null);
lbTestMessageService.setIcon(null);
lbTestDbWarning.setText("");
lbTestSolrWarning.setText("");
lbTestMessageWarning.setText("");
try {
CaseDbConnectionInfo dbInfo = UserPreferences.getDatabaseConnectionInfo();
tbDbHostname.setText(dbInfo.getHost().trim());
tbDbPort.setText(dbInfo.getPort().trim());
tbDbUsername.setText(dbInfo.getUserName().trim());
tbDbPassword.setText(dbInfo.getPassword());
} catch (UserPreferencesException ex) {
logger.log(Level.SEVERE, "Error accessing case database connection info", ex); //NON-NLS
}
try {
MessageServiceConnectionInfo msgServiceInfo = UserPreferences.getMessageServiceConnectionInfo();
tbMsgHostname.setText(msgServiceInfo.getHost().trim());
tbMsgPort.setText(Integer.toString(msgServiceInfo.getPort()));
tbMsgUsername.setText(msgServiceInfo.getUserName().trim());
tbMsgPassword.setText(msgServiceInfo.getPassword());
} catch (UserPreferencesException ex) {
logger.log(Level.SEVERE, "Error accessing case database connection info", ex); //NON-NLS
}
String indexingServerHost = UserPreferences.getIndexingServerHost().trim();
if (!indexingServerHost.isEmpty()) {
tbSolrHostname.setText(indexingServerHost);
}
String indexingServerPort = UserPreferences.getIndexingServerPort().trim();
if (portNumberIsValid(indexingServerPort)) {
tbSolrPort.setText(indexingServerPort);
}
lbTestDatabase.setIcon(null);
lbTestSolr.setIcon(null);
lbTestMessageService.setIcon(null);
bnTestDatabase.setEnabled(false);
bnTestSolr.setEnabled(false);
bnTestMessageService.setEnabled(false);
cbEnableMultiUser.setSelected(UserPreferences.getIsMultiUserModeEnabled());
this.valid(); // trigger validation to enable buttons based on current settings
}
/**
* Tests whether or not values have been entered in all of the database
* settings text fields.
*
* @return True or false.
*/
private boolean databaseFieldsArePopulated() {
return !tbDbHostname.getText().trim().isEmpty()
&& !tbDbPort.getText().trim().isEmpty()
&& !tbDbUsername.getText().trim().isEmpty()
&& tbDbPassword.getPassword().length != 0;
}
/**
* Tests whether or not values have been entered in all of the Solr settings
* text fields.
*
* @return True or false.
*/
private boolean solrFieldsArePopulated() {
return !tbSolrHostname.getText().trim().isEmpty()
&& !tbSolrPort.getText().trim().isEmpty();
}
/**
* Tests whether or not values have been entered in all of the message
* service settings text fields.
*
* @return True or false.
*/
private boolean messageServiceFieldsArePopulated() {
return !tbMsgHostname.getText().trim().isEmpty()
&& !tbMsgPort.getText().trim().isEmpty()
&& !tbMsgUsername.getText().trim().isEmpty()
&& tbMsgPassword.getPassword().length != 0;
}
void store() {
DbType dbType = DbType.SQLITE;
if (cbEnableMultiUser.isSelected()) {
dbType = DbType.POSTGRESQL;
}
UserPreferences.setIsMultiUserModeEnabled(cbEnableMultiUser.isSelected());
CaseDbConnectionInfo info = new CaseDbConnectionInfo(
tbDbHostname.getText().trim(),
tbDbPort.getText().trim(),
tbDbUsername.getText().trim(),
new String(tbDbPassword.getPassword()),
dbType);
try {
UserPreferences.setDatabaseConnectionInfo(info);
} catch (UserPreferencesException ex) {
logger.log(Level.SEVERE, "Error accessing case database connection info", ex); //NON-NLS
}
int port = 0;
try {
port = Integer.parseInt(this.tbMsgPort.getText().trim());
} catch (NumberFormatException ex) {
logger.log(Level.SEVERE, "Bad port setting", ex);
}
MessageServiceConnectionInfo msgServiceInfo = new MessageServiceConnectionInfo(
tbMsgHostname.getText().trim(),
port,
tbMsgUsername.getText().trim(),
new String(tbMsgPassword.getPassword()));
try {
UserPreferences.setMessageServiceConnectionInfo(msgServiceInfo);
} catch (UserPreferencesException ex) {
logger.log(Level.SEVERE, "Error accessing messaging service connection info", ex); //NON-NLS
}
UserPreferences.setIndexingServerHost(tbSolrHostname.getText().trim());
UserPreferences.setIndexingServerPort(Integer.parseInt(tbSolrPort.getText().trim()));
}
/**
* Validates that the form is filled out correctly for our usage.
*
* @return true if it's okay, false otherwise.
*/
boolean valid() {
tbOops.setText("");
if (cbEnableMultiUser.isSelected()) {
return checkFieldsAndEnableButtons()
&& databaseSettingsAreValid()
&& indexingServerSettingsAreValid()
&& messageServiceSettingsAreValid();
} else {
return true;
}
}
/**
* Tests whether or not all of the settings components are populated and
* sets the test buttons appropriately.
*
* @return True or false.
*/
boolean checkFieldsAndEnableButtons() {
boolean result = true;
boolean dbPopulated = databaseFieldsArePopulated();
boolean solrPopulated = solrFieldsArePopulated();
boolean messageServicePopulated = messageServiceFieldsArePopulated();
// PostgreSQL Database
bnTestDatabase.setEnabled(dbPopulated);
// Solr Indexing
bnTestSolr.setEnabled(solrPopulated);
// ActiveMQ Messaging
bnTestMessageService.setEnabled(messageServicePopulated);
if (!dbPopulated || !solrPopulated || !messageServicePopulated) {
// We don't even have everything filled out
result = false;
tbOops.setText(INCOMPLETE_SETTINGS_MSG);
}
return result;
}
/**
* Tests whether or not the database settings are valid.
*
* @return True or false.
*/
boolean databaseSettingsAreValid() {
if (portNumberIsValid(tbDbPort.getText().trim())) {
return true;
} else {
tbOops.setText(INVALID_DB_PORT_MSG);
return false;
}
}
/**
* Tests whether or not the message service settings are valid.
*
* @return True or false.
*/
boolean messageServiceSettingsAreValid() {
if (!portNumberIsValid(tbMsgPort.getText().trim())) {
tbOops.setText(INVALID_MESSAGE_SERVICE_PORT_MSG);
return false;
}
return true;
}
/**
* Tests whether or not the indexing server settings are valid.
*
* @return True or false.
*/
boolean indexingServerSettingsAreValid() {
if (!portNumberIsValid(tbSolrPort.getText().trim())) {
tbOops.setText(INVALID_INDEXING_SERVER_PORT_MSG);
return false;
}
return true;
}
/**
* Determines whether or not a port number is within the range of valid port
* numbers.
*
* @param portNumber The port number as a string.
*
* @return True or false.
*/
private static boolean portNumberIsValid(String portNumber) {
try {
int value = Integer.parseInt(portNumber);
if (value < 0 || value > 65535) { // invalid port numbers
return false;
}
} catch (NumberFormatException detailsNotImportant) {
return false;
}
return true;
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton bnTestDatabase;
private javax.swing.JButton bnTestMessageService;
private javax.swing.JButton bnTestSolr;
private javax.swing.JCheckBox cbEnableMultiUser;
private javax.swing.JLabel lbDatabaseSettings;
private javax.swing.JLabel lbMessageServiceSettings;
private javax.swing.JLabel lbSolrSettings;
private javax.swing.JLabel lbTestDatabase;
private javax.swing.JLabel lbTestDbWarning;
private javax.swing.JLabel lbTestMessageService;
private javax.swing.JLabel lbTestMessageWarning;
private javax.swing.JLabel lbTestSolr;
private javax.swing.JLabel lbTestSolrWarning;
private javax.swing.JPanel pnDatabaseSettings;
private javax.swing.JPanel pnMessagingSettings;
private javax.swing.JPanel pnOverallPanel;
private javax.swing.JPanel pnSolrSettings;
private javax.swing.JTextField tbDbHostname;
private javax.swing.JPasswordField tbDbPassword;
private javax.swing.JTextField tbDbPort;
private javax.swing.JTextField tbDbUsername;
private javax.swing.JTextField tbMsgHostname;
private javax.swing.JPasswordField tbMsgPassword;
private javax.swing.JTextField tbMsgPort;
private javax.swing.JTextField tbMsgUsername;
private javax.swing.JTextField tbOops;
private javax.swing.JTextField tbSolrHostname;
private javax.swing.JTextField tbSolrPort;
// End of variables declaration//GEN-END:variables
/**
* Used to listen for changes in text boxes. It lets the panel know things
* have been updated and that validation needs to happen.
*/
class TextBoxChangedListener implements DocumentListener {
@Override
public void changedUpdate(DocumentEvent e) {
Object statusIcon = e.getDocument().getProperty("statusIcon");
if (statusIcon != null) {
((javax.swing.JLabel) statusIcon).setIcon(null);
}
controller.changed();
}
@Override
public void insertUpdate(DocumentEvent e) {
Object statusIcon = e.getDocument().getProperty("statusIcon");
if (statusIcon != null) {
((javax.swing.JLabel) statusIcon).setIcon(null);
}
controller.changed();
}
@Override
public void removeUpdate(DocumentEvent e) {
Object statusIcon = e.getDocument().getProperty("statusIcon");
if (statusIcon != null) {
((javax.swing.JLabel) statusIcon).setIcon(null);
}
controller.changed();
}
}
}

View File

@ -0,0 +1,130 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.corecomponents;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import javax.swing.JComponent;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
@OptionsPanelController.TopLevelRegistration(categoryName = "#OptionsCategory_Name_Multi_User_Settings",
iconBase = "org/sleuthkit/autopsy/images/User-Group-icon-green32.png",
position = 2,
keywords = "#OptionsCategory_Keywords_Multi_User_Options",
keywordsCategory = "Multi-user")
public final class MultiUserSettingsPanelController extends OptionsPanelController {
private MultiUserSettingsPanel panel;
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private boolean changed;
private static final Logger logger = Logger.getLogger(MultiUserSettingsPanelController.class.getName());
@Override
public void update() {
getPanel().load();
changed = false;
}
@Override
public void applyChanges() {
getPanel().store();
changed = false;
}
@Override
public void cancel() {
}
@Override
public boolean isValid() {
return getPanel().valid();
}
@Override
public boolean isChanged() {
return changed;
}
@Override
public HelpCtx getHelpCtx() {
return null;
}
@Override
public JComponent getComponent(Lookup masterLookup) {
return getPanel();
}
@Override
public void addPropertyChangeListener(PropertyChangeListener l) {
if (pcs.getPropertyChangeListeners().length == 0) {
pcs.addPropertyChangeListener(l);
}
}
@Override
public void removePropertyChangeListener(PropertyChangeListener l) {
/**
* Note the NetBeans Framework does not appear to call this at all. We
* are using NetBeans 7.3.1 Build 201306052037. Perhaps in a future
* version of the Framework this will be resolved, but for now, simply
* don't unregister anything and add one time only in the
* addPropertyChangeListener() method above.
*/
}
private MultiUserSettingsPanel getPanel() {
if (panel == null) {
panel = new MultiUserSettingsPanel(this);
}
return panel;
}
void changed() {
if (!changed) {
changed = true;
try {
pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true);
} catch (Exception e) {
logger.log(Level.SEVERE, "GeneralOptionsPanelController listener threw exception", e); //NON-NLS
MessageNotifyUtil.Notify.show(
NbBundle.getMessage(this.getClass(), "GeneralOptionsPanelController.moduleErr"),
NbBundle.getMessage(this.getClass(), "GeneralOptionsPanelController.moduleErr.msg"),
MessageNotifyUtil.MessageType.ERROR);
}
}
try {
pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
} catch (Exception e) {
logger.log(Level.SEVERE, "GeneralOptionsPanelController listener threw exception", e); //NON-NLS
MessageNotifyUtil.Notify.show(
NbBundle.getMessage(this.getClass(), "GeneralOptionsPanelController.moduleErr"),
NbBundle.getMessage(this.getClass(), "GeneralOptionsPanelController.moduleErr.msg"),
MessageNotifyUtil.MessageType.ERROR);
}
}
}

View File

@ -33,7 +33,7 @@ import org.openide.awt.HtmlBrowser;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Implements a hyperlink to the Offline Documentation.

View File

@ -35,7 +35,7 @@ import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Implements a hyperlink to the Online Documentation.

View File

@ -0,0 +1,206 @@
package org.sleuthkit.autopsy.corecomponents;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.text.*;
/**
* The TextPrompt class will display a prompt over top of a text component when
* the Document of the text field is empty. The Show property is used to
* determine the visibility of the prompt.
*
* The Font and foreground Color of the prompt will default to those properties
* of the parent text component. You are free to change the properties after
* class construction. From:
* https://tips4java.wordpress.com/2009/11/29/text-prompt/
*/
public final class TextPrompt extends JLabel
implements FocusListener, DocumentListener {
public enum Show {
ALWAYS,
FOCUS_GAINED,
FOCUS_LOST;
}
private JTextComponent component;
private Document document;
private Show show;
private boolean showPromptOnce;
private int focusLost;
public TextPrompt(String text, JTextComponent component) {
this(text, component, Show.ALWAYS);
}
public TextPrompt(String text, JTextComponent component, Show show) {
this.component = component;
setShow(show);
document = component.getDocument();
setText(text);
setFont(component.getFont());
setForeground(component.getForeground());
setBorder(new EmptyBorder(component.getInsets()));
setHorizontalAlignment(JLabel.LEADING);
component.addFocusListener(this);
document.addDocumentListener(this);
component.setLayout(new BorderLayout());
component.add(this);
checkForPrompt();
}
/**
* Convenience method to change the alpha value of the current foreground
* Color to the specifice value.
*
* @param alpha value in the range of 0 - 1.0.
*/
public void changeAlpha(float alpha) {
changeAlpha((int) (alpha * 255));
}
/**
* Convenience method to change the alpha value of the current foreground
* Color to the specifice value.
*
* @param alpha value in the range of 0 - 255.
*/
public void changeAlpha(int alpha) {
alpha = alpha > 255 ? 255 : alpha < 0 ? 0 : alpha;
Color foreground = getForeground();
int red = foreground.getRed();
int green = foreground.getGreen();
int blue = foreground.getBlue();
Color withAlpha = new Color(red, green, blue, alpha);
super.setForeground(withAlpha);
}
/**
* Convenience method to change the style of the current Font. The style
* values are found in the Font class. Common values might be: Font.BOLD,
* Font.ITALIC and Font.BOLD + Font.ITALIC.
*
* @param style value representing the the new style of the Font.
*/
public void changeStyle(int style) {
setFont(getFont().deriveFont(style));
}
/**
* Get the Show property
*
* @return the Show property.
*/
public Show getShow() {
return show;
}
/**
* Set the prompt Show property to control when the promt is shown. Valid
* values are:
*
* Show.AWLAYS (default) - always show the prompt Show.Focus_GAINED - show
* the prompt when the component gains focus (and hide the prompt when focus
* is lost) Show.Focus_LOST - show the prompt when the component loses focus
* (and hide the prompt when focus is gained)
*
* @param show a valid Show enum
*/
public void setShow(Show show) {
this.show = show;
}
/**
* Get the showPromptOnce property
*
* @return the showPromptOnce property.
*/
public boolean getShowPromptOnce() {
return showPromptOnce;
}
/**
* Show the prompt once. Once the component has gained/lost focus once, the
* prompt will not be shown again.
*
* @param showPromptOnce when true the prompt will only be shown once,
* otherwise it will be shown repeatedly.
*/
public void setShowPromptOnce(boolean showPromptOnce) {
this.showPromptOnce = showPromptOnce;
}
/**
* Check whether the prompt should be visible or not. The visibility will
* change on updates to the Document and on focus changes.
*/
private void checkForPrompt() {
// Text has been entered, remove the prompt
if (document.getLength() > 0) {
setVisible(false);
return;
}
// Prompt has already been shown once, remove it
if (showPromptOnce && focusLost > 0) {
setVisible(false);
return;
}
// Check the Show property and component focus to determine if the
// prompt should be displayed.
if (component.hasFocus()) {
if (show == Show.ALWAYS
|| show == Show.FOCUS_GAINED) {
setVisible(true);
} else {
setVisible(false);
}
} else {
if (show == Show.ALWAYS
|| show == Show.FOCUS_LOST) {
setVisible(true);
} else {
setVisible(false);
}
}
}
// Implement FocusListener
@Override
public void focusGained(FocusEvent e) {
checkForPrompt();
}
@Override
public void focusLost(FocusEvent e) {
focusLost++;
checkForPrompt();
}
// Implement DocumentListener
@Override
public void insertUpdate(DocumentEvent e) {
checkForPrompt();
}
@Override
public void removeUpdate(DocumentEvent e) {
checkForPrompt();
}
@Override
public void changedUpdate(DocumentEvent e) {
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -18,14 +18,12 @@
*/
package org.sleuthkit.autopsy.coreutils;
import java.awt.Component;
import java.util.logging.Filter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.SimpleFormatter;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.openide.util.lookup.ServiceProvider;
import org.netbeans.core.NbErrorManager;
@ -62,32 +60,12 @@ public class AutopsyExceptionHandler extends Handler {
public void publish(LogRecord record) {
if (isLoggable(record)) {
final String title = getTitleForLevelValue(record.getLevel().intValue());
final String message = formatExplanation(record);
if (record.getMessage() != null) {
// Throwable was anticipated, caught and logged. Display log message and throwable message.
final int levelValue = record.getLevel().intValue();
final Component parentComponent = null; // Use default window frame.
final String message = formatExplanation(record);
final String title = getTitleForLevelValue(levelValue);
final int messageType = getMessageTypeForLevelValue(levelValue);
// publish() was probably not called from the EDT, so run the message box there instead of here.
//only show the dialog in dev builds
if (buildType == Version.Type.DEVELOPMENT) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JOptionPane.showMessageDialog(
parentComponent,
message,
title,
messageType);
}
});
}
MessageNotifyUtil.Notify.error(title, message);
logger.log(Level.SEVERE, "Unexpected error: " + title + ", " + message); //NON-NLS
} else {
// Throwable (unanticipated) error. Use built-in exception handler to offer details, stacktrace.

View File

@ -28,6 +28,7 @@ import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.sleuthkit.autopsy.core.UserPreferences;
/**
* Executes a command line using an operating system process with a configurable
@ -41,7 +42,10 @@ public final class ExecUtil {
/**
* The execute() methods do a wait() with a timeout on the executing process
* and query a process terminator each time the timeout expires to determine
* whether or not to kill the process.
* whether or not to kill the process. See
* DataSourceIngestModuleProcessTerminator and
* FileIngestModuleProcessTerminator as examples of ProcessTerminator
* implementations.
*/
public interface ProcessTerminator {
@ -74,6 +78,24 @@ public final class ExecUtil {
this.startTimeInSeconds = (new Date().getTime()) / 1000;
}
/**
* Creates a process terminator that can be used to kill a process after
* it has run for a given period of time. Maximum allowable run time is
* set via Autopsy Options panel. If the process termination
* functionality is disabled then the maximum allowable time is set to
* MAX_INT seconds.
*/
public TimedProcessTerminator() {
if (UserPreferences.getIsTimeOutEnabled() && UserPreferences.getProcessTimeOutHrs() > 0) {
// user specified time out
this.maxRunTimeInSeconds = UserPreferences.getProcessTimeOutHrs() * 3600;
} else {
// never time out
this.maxRunTimeInSeconds = Long.MAX_VALUE;
}
this.startTimeInSeconds = (new Date().getTime()) / 1000;
}
/**
* @inheritDoc
*/

View File

@ -163,8 +163,8 @@ public class FileUtil {
* @return escaped string
*/
public static String escapeFileName(String fileName) {
//for now escaping / (not valid in file name, at least on Windows)
//with underscores. Windows/Java seem to ignore \\/ and \\\\/ escapings
return fileName.replaceAll("/", "_");
//for now escaping /:"*?<>| (not valid in file name, at least on Windows)
//with underscores. We are only keeping \ as it could be part of the path.
return fileName.replaceAll("[/:\"*?<>|]+", "_");
}
}

View File

@ -18,6 +18,7 @@
*/
package org.sleuthkit.autopsy.coreutils;
import java.util.Deque;
import java.util.Objects;
import javafx.beans.property.Property;
import javafx.beans.property.ReadOnlyBooleanProperty;
@ -143,7 +144,6 @@ public class History<T> {
* @throws IllegalArgumentException if newState == null
*/
synchronized public void advance(T newState) throws IllegalArgumentException {
if (newState != null && Objects.equals(currentState.get(), newState) == false) {
if (currentState.get() != null) {
historyStack.push(currentState.get());

View File

@ -56,7 +56,6 @@ import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.TskCoreException;
/**
*
* Utilities for working with Images and creating thumbnails. Reuses thumbnails
* by storing them in the case's cache directory.
*/
@ -140,9 +139,6 @@ public class ImageUtils {
= Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder()
.namingPattern("icon saver-%d").build());
private ImageUtils() {
}
public static List<String> getSupportedImageExtensions() {
return Collections.unmodifiableList(SUPPORTED_IMAGE_EXTENSIONS);
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012-2014 Basis Technology Corp.
* Copyright 2012-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,17 +18,20 @@
*/
package org.sleuthkit.autopsy.coreutils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.LogRecord;
/**
* Autopsy specialization of the Java Logger class with custom file handlers.
* Note that the custom loggers are not obtained from the global log manager.
*/
public final class Logger extends java.util.logging.Logger {
@ -37,66 +40,81 @@ public final class Logger extends java.util.logging.Logger {
private static final int LOG_FILE_COUNT = 10;
private static final String LOG_WITHOUT_STACK_TRACES = "autopsy.log"; //NON-NLS
private static final String LOG_WITH_STACK_TRACES = "autopsy_traces.log"; //NON-NLS
private static final Handler console = new java.util.logging.ConsoleHandler();
private static final Object fileHandlerLock = new Object();
private static FileHandler userFriendlyLogFile = createFileHandler(PlatformUtil.getLogDirectory(), LOG_WITHOUT_STACK_TRACES);
private static FileHandler developersLogFile = createFileHandler(PlatformUtil.getLogDirectory(), LOG_WITH_STACK_TRACES);
private static final Map<String, Logger> namesToLoggers = new HashMap<>();
private static final Handler consoleHandler = new java.util.logging.ConsoleHandler();
private static FileHandler userFriendlyHandler = createFileHandlerWithoutTraces(PlatformUtil.getLogDirectory());
private static FileHandler developerFriendlyHandler = createFileHandlerWithTraces(PlatformUtil.getLogDirectory());
private static FileHandler createFileHandler(String logDirectory, String fileName) {
/**
* Creates a custom file handler with a custom message formatter that does
* not include stack traces.
*
* @param logDirectory The directory where the log files should reside.
*
* @return A custom file handler.
*/
private static FileHandler createFileHandlerWithoutTraces(String logDirectory) {
String logFilePath = Paths.get(logDirectory, LOG_WITHOUT_STACK_TRACES).toString();
try {
FileHandler f = new FileHandler(logDirectory + File.separator + fileName, LOG_SIZE, LOG_FILE_COUNT);
f.setEncoding(LOG_ENCODING);
switch (fileName) {
case LOG_WITHOUT_STACK_TRACES:
f.setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
synchronized (fileHandlerLock) {
return (new Date(record.getMillis())).toString() + " "
+ record.getSourceClassName() + " "
+ record.getSourceMethodName() + "\n"
+ record.getLevel() + ": "
+ this.formatMessage(record) + "\n";
}
}
});
break;
case LOG_WITH_STACK_TRACES:
f.setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
synchronized (fileHandlerLock) {
if (record.getThrown() != null) {
FileHandler fileHandler = new FileHandler(logFilePath, LOG_SIZE, LOG_FILE_COUNT);
fileHandler.setEncoding(LOG_ENCODING);
fileHandler.setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return (new Date(record.getMillis())).toString() + " "
+ record.getSourceClassName() + " "
+ record.getSourceMethodName() + "\n"
+ record.getLevel() + ": "
+ this.formatMessage(record) + "\n";
}
});
return fileHandler;
} catch (IOException ex) {
throw new RuntimeException(String.format("Error initializing file handler for %s", logFilePath), ex); //NON-NLS
}
}
StackTraceElement ele[] = record.getThrown().getStackTrace();
String StackTrace = "";
for (StackTraceElement ele1 : ele) {
StackTrace += "\t" + ele1.toString() + "\n";
}
return (new Timestamp(record.getMillis())).toString() + " "
+ record.getSourceClassName() + " "
+ record.getSourceMethodName() + "\n"
+ record.getLevel() + ": "
+ this.formatMessage(record) + "\n"
+ record.getThrown().toString() + ":\n"
+ StackTrace
+ "\n";
} else {
return (new Timestamp(record.getMillis())).toString() + " "
+ record.getSourceClassName() + " "
+ record.getSourceMethodName() + "\n"
+ record.getLevel() + ": "
+ this.formatMessage(record) + "\n";
}
}
/**
* Creates a custom file handler with a custom message formatter that
* incldues stack traces.
*
* @param logDirectory The directory where the log files should reside.
*
* @return A custom file handler.
*/
private static FileHandler createFileHandlerWithTraces(String logDirectory) {
String logFilePath = Paths.get(logDirectory, LOG_WITH_STACK_TRACES).toString();
try {
FileHandler fileHandler = new FileHandler(logFilePath, LOG_SIZE, LOG_FILE_COUNT);
fileHandler.setEncoding(LOG_ENCODING);
fileHandler.setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
if (record.getThrown() != null) {
String stackTrace = ""; //NON-NLS
for (StackTraceElement traceElem : record.getThrown().getStackTrace()) {
stackTrace += "\t" + traceElem.toString() + "\n"; //NON-NLS
}
});
break;
}
return f;
} catch (IOException e) {
throw new RuntimeException("Error initializing " + fileName + " file handler", e); //NON-NLS
return (new Timestamp(record.getMillis())).toString() + " " //NON-NLS
+ record.getSourceClassName() + " " //NON-NLS
+ record.getSourceMethodName() + "\n" //NON-NLS
+ record.getLevel() + ": " //NON-NLS
+ this.formatMessage(record) + "\n" //NON-NLS
+ record.getThrown().toString() + ":\n" //NON-NLS
+ stackTrace
+ "\n"; //NON-NLS
} else {
return (new Timestamp(record.getMillis())).toString() + " " //NON-NLS
+ record.getSourceClassName() + " " //NON-NLS
+ record.getSourceMethodName() + "\n" //NON-NLS
+ record.getLevel() + ": " //NON-NLS
+ this.formatMessage(record) + "\n"; //NON-NLS
}
}
});
return fileHandler;
} catch (IOException ex) {
throw new RuntimeException(String.format("Error initializing file handler for %s", logFilePath), ex); //NON-NLS
}
}
@ -105,63 +123,88 @@ public final class Logger extends java.util.logging.Logger {
*
* @param directoryPath The path to the desired log directory as a string.
*/
public static void setLogDirectory(String directoryPath) {
if (null != directoryPath && !directoryPath.isEmpty()) {
File directory = new File(directoryPath);
if (directory.exists() && directory.canWrite()) {
synchronized (fileHandlerLock) {
userFriendlyLogFile.close();
userFriendlyLogFile = createFileHandler(directoryPath, LOG_WITHOUT_STACK_TRACES);
developersLogFile.close();
developersLogFile = createFileHandler(directoryPath, LOG_WITH_STACK_TRACES);
}
}
synchronized public static void setLogDirectory(String directoryPath) {
/*
* Create file handlers for the new directory and swap them into all of
* the existing loggers using thread-safe Logger methods. The new
* handlers are added before the old handlers so that no messages will
* be lost, but this makes it possible for log messages to be written
* via the old handlers if logging calls are interleaved with the
* add/remove handler calls (currently, the base class handlers
* collection is a CopyOnWriteArrayList).
*/
FileHandler newUserFriendlyHandler = createFileHandlerWithoutTraces(directoryPath);
FileHandler newDeveloperFriendlyHandler = createFileHandlerWithTraces(directoryPath);
for (Logger logger : namesToLoggers.values()) {
logger.addHandler(newUserFriendlyHandler);
logger.addHandler(newDeveloperFriendlyHandler);
logger.removeHandler(userFriendlyHandler);
logger.removeHandler(userFriendlyHandler);
}
/*
* Close the old file handlers and save references to the new handlers
* so they can be added to any new loggers. This swap is why this method
* and the two overloads of getLogger() are synchronized, serializing
* access to userFriendlyHandler and developerFriendlyHandler.
*/
userFriendlyHandler.close();
userFriendlyHandler = newUserFriendlyHandler;
developerFriendlyHandler.close();
developerFriendlyHandler = newDeveloperFriendlyHandler;
}
/**
* Factory method to retrieve a org.sleuthkit.autopsy.coreutils.Logger
* instance derived from java.util.logging.Logger. Hides the base class
* factory method.
* Finds or creates a customized logger. Hides the base class factory
* method.
*
* @param name A name for the logger. This should be a dot-separated name
* and should normally be based on the package name or class
* name.
* @param name A name for the logger. This should normally be a
* dot-separated name based on a package name or class name.
*
* @return org.sleuthkit.autopsy.coreutils.Logger instance
*/
public static Logger getLogger(String name) {
return new Logger(name, null);
synchronized public static Logger getLogger(String name) {
return getLogger(name, null);
}
/**
* Factory method to retrieve a org.sleuthkit.autopsy.coreutils.Logger
* instance derived from java.util.logging.Logger. Hides the base class
* factory method.
* Finds or creates a customized logger. Hides the base class factory
* method.
*
* @param name A name for the logger. This should be a
* dot-separated name and should normally be based
* on the package name or class name.
* @param resourceBundleName - name of ResourceBundle to be used for
* @param name A name for the logger. This should normally be
* a dot-separated name based on a package name or
* class name.
* @param resourceBundleName Name of ResourceBundle to be used for
* localizing messages for this logger. May be
* null if none of the messages require
* localization.
* null.
*
* @return org.sleuthkit.autopsy.coreutils.Logger instance
*/
public static Logger getLogger(String name, String resourceBundleName) {
return new Logger(name, resourceBundleName);
synchronized public static Logger getLogger(String name, String resourceBundleName) {
if (!namesToLoggers.containsKey(name)) {
Logger logger = new Logger(name, resourceBundleName);
logger.addHandler(userFriendlyHandler);
logger.addHandler(developerFriendlyHandler);
namesToLoggers.put(name, logger);
}
return namesToLoggers.get(name);
}
/**
* Constructs a customized logger.
*
* @param name A name for the logger. This should normally be
* a dot-separated name based on a package name or
* class name.
* @param resourceBundleName Name of ResourceBundle to be used for
* localizing messages for this logger. May be
* null.
*/
private Logger(String name, String resourceBundleName) {
super(name, resourceBundleName);
super.setUseParentHandlers(false);
if (Version.getBuildType() == Version.Type.DEVELOPMENT) {
super.addHandler(console);
}
synchronized (fileHandlerLock) {
super.setUseParentHandlers(false);
super.addHandler(userFriendlyLogFile);
super.addHandler(developersLogFile);
super.addHandler(consoleHandler);
}
}
}

View File

@ -39,6 +39,7 @@ public class ModuleSettings {
private final static String moduleDirPath = PlatformUtil.getUserConfigDirectory();
public static final String DEFAULT_CONTEXT = "GeneralContext"; //NON-NLS
public static final String MAIN_SETTINGS = "Case"; //NON-NLS
public static final String CURRENT_CASE_TYPE = "Current_Case_Type"; //NON-NLS
/**
* the constructor

View File

@ -0,0 +1,44 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012-2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.coreutils;
import java.net.UnknownHostException;
public class NetworkUtils {
/**
* Set the host name variable. Sometimes the network can be finicky, so the
* answer returned by getHostName() could throw an exception or be null.
* Have it read the environment variable if getHostName() is unsuccessful.
*/
public static String getLocalHostName() {
String hostName = "";
try {
hostName = java.net.InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException ex) {
// getLocalHost().getHostName() can fail in some situations.
// Use environment variable if so.
hostName = System.getenv("COMPUTERNAME");
}
if (hostName == null || hostName.isEmpty()) {
hostName = System.getenv("COMPUTERNAME");
}
return hostName;
}
}

View File

@ -0,0 +1,58 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.coreutils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.sleuthkit.autopsy.casemodule.Case;
/**
* Validates absolute path (e.g. to a data source or case output folder)
* depending on case type.
*/
public final class PathValidator {
private static final Pattern driveLetterPattern = Pattern.compile("^[Cc]:.*$");
public static boolean isValid(String path, Case.CaseType caseType) {
if (caseType == Case.CaseType.MULTI_USER_CASE) {
// check that path is not on "C:" drive
if (pathOnCDrive(path)) {
return false;
}
} else {
// single user case - no validation needed
}
return true;
}
/**
* Checks whether a file path contains drive letter defined by pattern.
*
* @param filePath Input file absolute path
*
* @return true if path matches the pattern, false otherwise.
*/
private static boolean pathOnCDrive(String filePath) {
Matcher m = driveLetterPattern.matcher(filePath);
return m.find();
}
}

View File

@ -0,0 +1,97 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.coreutils;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Class offers utility functions to identify and process time stamped folders.
*/
public final class TimeStampUtils {
// Pattern to identify whether case name contains a generated time stamp.
// Sample case name with time stamp: Case 1_2015_02_02_12_10_31 for case "Case 1"
private static final Pattern timeStampPattern = Pattern.compile("\\d{4}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{2}$");
private static final int LENGTH_OF_DATE_TIME_STAMP = 20; // length of the above time stamp
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
/**
* Checks whether a string ends with a time stamp defined by pattern.
*
* @param inputString Input string
*
* @return true if string ends with a time stamp, false otherwise.
*/
public static boolean endsWithTimeStamp(String inputString) {
Matcher m = timeStampPattern.matcher(inputString);
return m.find();
}
/**
* Returns length of time stamp string.
*
* @return length of time stamp string.
*/
public static int getTimeStampLength() {
return LENGTH_OF_DATE_TIME_STAMP;
}
/**
* Create a timestamp using the current time
*
* @return the timestamp as a String
*/
public static String createTimeStamp() {
return dateFormat.format(Calendar.getInstance().getTime());
}
/**
* Remove a timestamp if it exists
*
* @param input the String to remove the trailing timestamp from
*
* @return the String without timestamp
*/
public static String removeTimeStamp(String input) {
String result = input;
if (input != null && endsWithTimeStamp(input)) {
result = input.substring(0, input.length() - getTimeStampLength());
}
return result;
}
/**
* Return the timestamp portion of the name passed in
*
* @param input the name to check for a timestamp
*
* @return the timestamp only, or empty String if none
*/
public static String getTimeStampOnly(String input) {
String result = "";
if (input != null && endsWithTimeStamp(input)) {
result = input.substring(input.length() - getTimeStampLength(), input.length());
}
return result;
}
}

View File

@ -1,48 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.coreutils;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
/*
* Formatter to wrap another formatter and prepend a timestampe to each
* formatted string Not currently used.
*/
class TimestampingFormatter extends Formatter {
Formatter original;
DateFormat timestampFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.US);
String lineSeparator = System.getProperty("line.separator");
TimestampingFormatter(Formatter original) {
this.original = original;
}
@Override
public String format(LogRecord record) {
long millis = record.getMillis();
String timestamp = timestampFormat.format(new Date(millis));
return timestamp + lineSeparator + original.format(record);
}
}

View File

@ -0,0 +1,308 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.coreutils;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
public class UNCPathUtilities {
private static Map<String, String> drives;
private static final String MAPPED_DRIVES = "_mapped_drives.txt"; //NON-NLS
private static final String TEMP_FOLDER = "TEMP";
private static final String DATA_TRIGGER = "----------"; //NON-NLS
private static final String OK_TXT = "OK"; //NON-NLS
private static final String COLON = ":"; //NON-NLS
private static final String UNC_PATH_START = "\\\\"; //NON-NLS
private static final String C_DRIVE = "C:"; //NON-NLS
private static final int DRIVE_LEN = 2;
private static final int STARTING_OFFSET = 0;
private static final int REPLACEMENT_SIZE = 2;
private static final int FIRST_ITEM = 0;
private final String nameString;
/**
* Constructor
*/
public UNCPathUtilities() {
// get UUID for this instance
this.nameString = UUID.randomUUID().toString();
drives = getMappedDrives();
}
/**
* This method converts a passed in path to UNC if it is not already UNC.
* The UNC path will end up in one of the following two forms:
* \\hostname\somefolder\otherfolder or \\IP_ADDRESS\somefolder\otherfolder
*
* This is accomplished by checking the mapped drives list the operating
* system maintains and substituting where required. If the drive of the
* path passed in does not exist in the cached mapped drives list, you can
* force a rescan of the mapped drives list with rescanDrives(), then call
* this method again. This would be of use if the end user added a mapped
* drive while your dialog was up, for example.
*
* @param inputPath a String of the path to convert
*
* @return returns a successfully converted inputPath or null if unable to
* find a matching drive and convert it to UNC
*/
synchronized public String mappedDriveToUNC(String inputPath) {
if (inputPath != null) {
// If it is a C:, do not attempt to convert. This is for the single-user case.
if (inputPath.toUpperCase().startsWith(C_DRIVE)) {
return null;
}
if (false == isUNC(inputPath)) {
String uncPath = null;
try {
String currentDrive = Paths.get(inputPath).getRoot().toString().substring(STARTING_OFFSET, REPLACEMENT_SIZE);
String uncMapping = drives.get(currentDrive);
if (uncMapping != null) {
uncPath = uncMapping + inputPath.substring(REPLACEMENT_SIZE, inputPath.length());
}
} catch (Exception ex) {
// Didn't work. Skip it.
}
return uncPath;
} else {
return inputPath;
}
} else {
return null;
}
}
/**
* This method converts a passed in path to UNC if it is not already UNC.
* The UNC path will end up in one of the following two forms:
* \\hostname\somefolder\otherfolder or \\IP_ADDRESS\somefolder\otherfolder
*
* This is accomplished by checking the mapped drives list the operating
* system maintains and substituting where required. If the drive of the
* path passed in does not exist in the cached mapped drives list, you can
* force a rescan of the mapped drives list with rescanDrives(), then call
* this method again. This would be of use if the end user added a mapped
* drive while your dialog was up, for example.
*
* @param inputPath the path to convert
*
* @return returns a successfully converted inputPath or null if unable to
* find a matching drive and convert it to UNC
*/
synchronized public Path mappedDriveToUNC(Path inputPath) {
if (inputPath != null) {
String uncPath = UNCPathUtilities.this.mappedDriveToUNC(inputPath.toString());
if (uncPath == null) {
return null;
} else {
return Paths.get(uncPath);
}
} else {
return null;
}
}
/**
* Tests if the drive in the passed in path is a mapped drive.
*
* @param inputPath the Path to test.
*
* @return true if the passed in drive is mapped, false otherwise
*/
synchronized public boolean isDriveMapped(Path inputPath) {
if (inputPath != null) {
return isDriveMapped(inputPath.toString());
} else {
return false;
}
}
/**
* Tests if the drive in the passed in path is a mapped drive.
*
* @param inputPath the Path to test.
*
* @return true if the passed in drive is mapped, false otherwise
*/
synchronized public boolean isDriveMapped(String inputPath) {
if (inputPath != null) {
String shortenedPath = inputPath.substring(STARTING_OFFSET, DRIVE_LEN);
for (String s : drives.keySet()) {
if (shortenedPath.equals(s)) {
return true;
}
}
}
return false;
}
/**
* Takes a UNC path that may have an IP address in it and converts it to
* hostname, if it can resolve the hostname. Given
* \\10.11.12.13\some\folder, the result will be \\TEDS_COMPUTER\some\folder
* if the IP address 10.11.12.13 belongs to a machine with the hostname
* TEDS_COMPUTER and the local machine is able to resolve the hostname.
*
* @param inputPath the path to convert to a hostname UNC path
*
* @return the successfully converted path or null if unable to resolve
*/
synchronized public Path ipToHostName(Path inputPath) {
if (inputPath != null) {
return Paths.get(ipToHostName(inputPath.toString()));
} else {
return null;
}
}
/**
* Takes a UNC path that may have an IP address in it and converts it to
* hostname, if it can resolve the hostname. Given
* \\10.11.12.13\some\folder, the result will be \\TEDS_COMPUTER\some\folder
* if the IP address 10.11.12.13 belongs to a machine with the hostname
* TEDS_COMPUTER and the local machine is able to resolve the hostname.
*
* @param inputPath a String of the path to convert to a hostname UNC path
*
* @return the successfully converted path or null if unable to resolve
*/
synchronized public String ipToHostName(String inputPath) {
if (inputPath != null) {
String result = null;
try {
if (isUNC(Paths.get(inputPath))) {
String potentialIP = Paths.get(inputPath.substring(REPLACEMENT_SIZE)).getName(FIRST_ITEM).toString();
String hostname = InetAddress.getByName(potentialIP).getHostName();
result = inputPath.replaceAll(potentialIP, hostname);
}
} catch (Exception ex) {
// Could not resolve hostname for IP address, return null result
}
return result;
} else {
return null;
}
}
/**
* Test if a Path is UNC. It is considered UNC if it begins with \\
*
* @param inputPath the path to check
*
* @return true if the passed in Path is UNC, false otherwise
*/
synchronized public static boolean isUNC(Path inputPath) {
if (inputPath != null) {
return isUNC(inputPath.toString());
} else {
return false;
}
}
/**
* Test if a String path is UNC. It is considered UNC if it begins with \\
*
* @param inputPath the String of the path to check
*
* @return true if the passed in Path is UNC, false otherwise
*/
synchronized public static boolean isUNC(String inputPath) {
if (inputPath != null) {
return inputPath.startsWith(UNC_PATH_START);
} else {
return false;
}
}
/**
* Updates the list of mapped drives this class contains. This list is used
* to resolve mappedDriveToUNC and isDriveMapped calls. This is useful to
* call if the user has potentially added mapped drives to their system
* after the module calling mappedDriveToUNC has already begun running. Note
* this uses system I/O, so call it with some care.
*
*/
synchronized public void rescanDrives() {
drives = getMappedDrives();
}
/**
* Populates the list of mapped drives this class contains. The list is used
* to resolve mappedDriveToUNC and isDriveMapped calls. Note this uses
* system I/O, so call it with some care.
*
* @return the hashmap
*/
synchronized private Map<String, String> getMappedDrives() {
Map<String, String> driveMap = new HashMap<>();
File mappedDrive = Paths.get(System.getenv(TEMP_FOLDER), nameString + MAPPED_DRIVES).toFile();
try {
Files.deleteIfExists(mappedDrive.toPath());
ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "net", "use"); //NON-NLS
builder.redirectOutput(mappedDrive);
builder.redirectError(mappedDrive);
Process p = builder.start(); // throws IOException
p.waitFor(10, TimeUnit.SECONDS);
try (Scanner scanner = new Scanner(mappedDrive)) {
// parse the data and place it in the hashmap
while (scanner.hasNext()) {
String entry1 = scanner.next();
if (entry1.startsWith(DATA_TRIGGER)) {
continue;
}
String entry2 = scanner.next();
if (entry2.startsWith(DATA_TRIGGER)) {
continue;
}
String entry3 = scanner.next();
if (entry3.startsWith(DATA_TRIGGER)) {
continue;
}
scanner.nextLine();
if (entry1.length() == DRIVE_LEN && !entry1.equals(OK_TXT) && entry1.endsWith(COLON)) {
driveMap.put(entry1, entry2); // if there was no leading status, populate drive
} else if (entry2.length() == DRIVE_LEN && entry2.endsWith(COLON)) {
driveMap.put(entry2, entry3); // if there was a leading status, populate drive
}
}
}
} catch (IOException | InterruptedException ex) {
// if we couldn't do it, no big deal
Logger.getLogger(UNCPathUtilities.class.getName()).log(Level.WARNING, "Unable to parse 'net use' output", ex); //NON-NLS
} finally {
try {
Files.deleteIfExists(mappedDrive.toPath());
} catch (IOException ex) {
// if we couldn't do it, no big deal
}
}
return driveMap;
}
}

Some files were not shown because too many files have changed in this diff Show More