mirror of
https://github.com/elisspace/autopsy.git
synced 2026-09-06 02:24:30 +00:00
Merge branch 'develop' of https://github.com/sleuthkit/autopsy into newMboxParser
Conflicts: Core/src/org/sleuthkit/autopsy/ingest/GeneralIngestConfigurator.java
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
Manifest-Version: 1.0
|
||||
OpenIDE-Module: org.sleuthkit.autopsy.core/9
|
||||
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties
|
||||
OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml
|
||||
OpenIDE-Module-Implementation-Version: 9
|
||||
OpenIDE-Module-Requires: org.openide.windows.WindowManager, org.netbeans.api.javahelp.Help
|
||||
AutoUpdate-Show-In-Client: true
|
||||
AutoUpdate-Essential-Module: true
|
||||
OpenIDE-Module-Install: org/sleuthkit/autopsy/core/Installer.class
|
||||
|
||||
Manifest-Version: 1.0
|
||||
OpenIDE-Module: org.sleuthkit.autopsy.core/9
|
||||
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties
|
||||
OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml
|
||||
OpenIDE-Module-Implementation-Version: 9
|
||||
OpenIDE-Module-Requires: org.openide.windows.WindowManager, org.netbeans.api.javahelp.Help
|
||||
AutoUpdate-Show-In-Client: true
|
||||
AutoUpdate-Essential-Module: true
|
||||
OpenIDE-Module-Install: org/sleuthkit/autopsy/core/Installer.class
|
||||
|
||||
|
||||
@@ -191,6 +191,7 @@
|
||||
</dependency>
|
||||
</module-dependencies>
|
||||
<public-packages>
|
||||
<package>org.sleuthkit.autopsy.actions</package>
|
||||
<package>org.sleuthkit.autopsy.casemodule</package>
|
||||
<package>org.sleuthkit.autopsy.casemodule.services</package>
|
||||
<package>org.sleuthkit.autopsy.core</package>
|
||||
|
||||
69
Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java
Executable file
69
Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java
Executable file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.util.Collection;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JOptionPane;
|
||||
import org.openide.util.Utilities;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Instances of this Action allow users to apply tags to blackboard artifacts.
|
||||
*/
|
||||
public class AddBlackboardArtifactTagAction 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 AddBlackboardArtifactTagAction instance;
|
||||
|
||||
public static synchronized AddBlackboardArtifactTagAction getInstance() {
|
||||
if (null == instance) {
|
||||
instance = new AddBlackboardArtifactTagAction();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private AddBlackboardArtifactTagAction() {
|
||||
super("");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getActionDisplayName() {
|
||||
return Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).size() > 1 ? "Tag Results" : "Tag Result";
|
||||
}
|
||||
|
||||
@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);
|
||||
JOptionPane.showMessageDialog(null, "Unable to tag " + artifact.getDisplayName() + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
99
Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java
Executable file
99
Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java
Executable file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.util.Collection;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JOptionPane;
|
||||
import org.openide.util.Utilities;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Instances of this Action allow users to apply tags to content.
|
||||
*/
|
||||
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() {
|
||||
if (null == instance) {
|
||||
instance = new AddContentTagAction();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private AddContentTagAction() {
|
||||
super("");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getActionDisplayName() {
|
||||
return Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File";
|
||||
}
|
||||
|
||||
@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 (file.getName().equals(".")) {
|
||||
Content parentFile = file.getParent();
|
||||
if (parentFile instanceof AbstractFile) {
|
||||
file = (AbstractFile)parentFile;
|
||||
}
|
||||
else {
|
||||
JOptionPane.showMessageDialog(null, "Unable to tag " + parentFile.getName() + ", not a regular file.", "Cannot Apply Tag", JOptionPane.WARNING_MESSAGE);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
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 {
|
||||
JOptionPane.showMessageDialog(null, "Unable to tag " + parentFile.getName() + ", not a regular file.", "Cannot Apply Tag", JOptionPane.WARNING_MESSAGE);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
JOptionPane.showMessageDialog(null, "Unable to tag " + parentFile.getName() + ", not a regular file.", "Cannot Apply Tag", JOptionPane.WARNING_MESSAGE);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment);
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex);
|
||||
JOptionPane.showMessageDialog(null, "Unable to tag " + file.getName() + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
148
Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java
Executable file
148
Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java
Executable file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import org.openide.util.actions.Presenter;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
/**
|
||||
* An abstract base class for Actions that allow users to tag SleuthKit data
|
||||
* model objects.
|
||||
*/
|
||||
abstract class AddTagAction extends TagAction implements Presenter.Popup {
|
||||
private static final String NO_COMMENT = "";
|
||||
|
||||
AddTagAction(String menuText) {
|
||||
super(menuText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JMenuItem getPopupPresenter() {
|
||||
return new TagMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAction(ActionEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method to allow derived classes to provide a string for for a
|
||||
* menu item label.
|
||||
*/
|
||||
abstract protected String getActionDisplayName();
|
||||
|
||||
/**
|
||||
* Template method to allow derived classes to add the indicated tag and
|
||||
* comment to one or more a SleuthKit data model objects.
|
||||
*/
|
||||
abstract protected void addTag(TagName tagName, String comment);
|
||||
|
||||
/**
|
||||
* Instances of this class implement a context menu user interface for
|
||||
* creating or selecting a tag name for a tag and specifying an optional tag
|
||||
* comment.
|
||||
*/
|
||||
// @@@ This user interface has some significant usability issues and needs
|
||||
// to be reworked.
|
||||
private class TagMenu extends JMenu {
|
||||
TagMenu() {
|
||||
super(getActionDisplayName());
|
||||
|
||||
// Get the current set of tag names.
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
List<TagName> tagNames = null;
|
||||
try {
|
||||
tagNames = tagsManager.getAllTagNames();
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
|
||||
}
|
||||
|
||||
// Create a "Quick Tag" sub-menu.
|
||||
JMenu quickTagMenu = new JMenu("Quick Tag");
|
||||
add(quickTagMenu);
|
||||
|
||||
// Each tag name in the current set of tags gets its own menu item in
|
||||
// the "Quick Tags" sub-menu. Selecting one of these menu items adds
|
||||
// a tag with the associated tag name.
|
||||
if (null != tagNames && !tagNames.isEmpty()) {
|
||||
for (final TagName tagName : tagNames) {
|
||||
JMenuItem tagNameItem = new JMenuItem(tagName.getDisplayName());
|
||||
tagNameItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
addTag(tagName, NO_COMMENT);
|
||||
refreshDirectoryTree();
|
||||
}
|
||||
});
|
||||
quickTagMenu.add(tagNameItem);
|
||||
}
|
||||
}
|
||||
else {
|
||||
JMenuItem empty = new JMenuItem("No tags");
|
||||
empty.setEnabled(false);
|
||||
quickTagMenu.add(empty);
|
||||
}
|
||||
|
||||
quickTagMenu.addSeparator();
|
||||
|
||||
// The "Quick Tag" menu also gets an "Choose Tag..." menu item.
|
||||
// Selecting this item initiates a dialog that can be used to create
|
||||
// or select a tag name and adds a tag with the resulting name.
|
||||
JMenuItem newTagMenuItem = new JMenuItem("New Tag...");
|
||||
newTagMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
TagName tagName = GetTagNameDialog.doDialog();
|
||||
if (tagName != null) {
|
||||
addTag(tagName, NO_COMMENT);
|
||||
refreshDirectoryTree();
|
||||
}
|
||||
}
|
||||
});
|
||||
quickTagMenu.add(newTagMenuItem);
|
||||
|
||||
// Create a "Choose Tag and Comment..." menu item. Selecting this item initiates
|
||||
// a dialog that can be used to create or select a tag name with an
|
||||
// optional comment and adds a tag with the resulting name.
|
||||
JMenuItem tagAndCommentItem = new JMenuItem("Tag and Comment...");
|
||||
tagAndCommentItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog();
|
||||
if (null != tagNameAndComment) {
|
||||
addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment());
|
||||
refreshDirectoryTree();
|
||||
}
|
||||
}
|
||||
});
|
||||
add(tagAndCommentItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Core/src/org/sleuthkit/autopsy/actions/Bundle.properties
Executable file
16
Core/src/org/sleuthkit/autopsy/actions/Bundle.properties
Executable file
@@ -0,0 +1,16 @@
|
||||
GetTagNameDialog.tagNameField.text=
|
||||
GetTagNameDialog.cancelButton.text=Cancel
|
||||
GetTagNameDialog.okButton.text=OK
|
||||
GetTagNameDialog.preexistingLabel.text=Pre-existing Tags:
|
||||
GetTagNameDialog.newTagPanel.border.title=New Tag
|
||||
GetTagNameDialog.tagNameLabel.text=Tag Name:
|
||||
GetTagNameAndCommentDialog.newTagButton.text=New Tag
|
||||
GetTagNameAndCommentDialog.okButton.text=OK
|
||||
GetTagNameAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank
|
||||
GetTagNameAndCommentDialog.commentText.text=
|
||||
GetTagNameAndCommentDialog.commentLabel.text=Comment:
|
||||
# To change this template, choose Tools | Templates
|
||||
# and open the template in the editor.
|
||||
GetTagNameAndCommentDialog.cancelButton.text=Cancel
|
||||
GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use
|
||||
GetTagNameAndCommentDialog.tagLabel.text=Tag:
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.util.Collection;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.JOptionPane;
|
||||
import org.openide.util.Utilities;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Instances of this Action allow users to delete tags applied to blackboard artifacts.
|
||||
*/
|
||||
public class DeleteBlackboardArtifactTagAction extends TagAction {
|
||||
private static final String MENU_TEXT = "Delete Tag(s)";
|
||||
|
||||
// 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 DeleteBlackboardArtifactTagAction instance;
|
||||
|
||||
public static synchronized DeleteBlackboardArtifactTagAction getInstance() {
|
||||
if (null == instance) {
|
||||
instance = new DeleteBlackboardArtifactTagAction();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private DeleteBlackboardArtifactTagAction() {
|
||||
super(MENU_TEXT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAction(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);
|
||||
JOptionPane.showMessageDialog(null, "Unable to delete tag " + tag.getName() + ".", "Tag Deletion Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
66
Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java
Executable file
66
Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java
Executable file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.util.Collection;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.JOptionPane;
|
||||
import org.openide.util.Utilities;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Instances of this Action allow users to delete tags applied to content.
|
||||
*/
|
||||
public class DeleteContentTagAction extends TagAction {
|
||||
private static final String MENU_TEXT = "Delete Tag(s)";
|
||||
|
||||
// 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 DeleteContentTagAction instance;
|
||||
|
||||
public static synchronized DeleteContentTagAction getInstance() {
|
||||
if (null == instance) {
|
||||
instance = new DeleteContentTagAction();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private DeleteContentTagAction() {
|
||||
super(MENU_TEXT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAction(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);
|
||||
JOptionPane.showMessageDialog(null, "Unable to delete tag " + tag.getName() + ".", "Tag Deletion Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,7 +78,7 @@
|
||||
<Component class="javax.swing.JButton" name="okButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
@@ -91,7 +91,7 @@
|
||||
<Component class="javax.swing.JButton" name="cancelButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
@@ -104,7 +104,7 @@
|
||||
<StringArray count="0"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.tagCombo.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.tagCombo.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
@@ -114,31 +114,31 @@
|
||||
<Component class="javax.swing.JLabel" name="tagLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.tagLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.tagLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="commentLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.commentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="commentText">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.commentText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.commentText.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentText.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="newTagButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.newTagButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.newTagButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
@@ -16,11 +16,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.directorytree;
|
||||
package org.sleuthkit.autopsy.actions;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.TreeSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.InputMap;
|
||||
@@ -29,28 +31,28 @@ import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.KeyStroke;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Tag dialog for tagging files and results. User enters an optional comment.
|
||||
*/
|
||||
public class TagAndCommentDialog extends JDialog {
|
||||
public class GetTagNameAndCommentDialog extends JDialog {
|
||||
private static final String NO_TAG_NAMES_MESSAGE = "No Tags";
|
||||
private final HashMap<String, TagName> tagNames = new HashMap<>();
|
||||
private TagNameAndComment tagNameAndComment = null;
|
||||
|
||||
private static final String NO_TAG_MESSAGE = "No Tags";
|
||||
private String tagName = "";
|
||||
private String comment = "";
|
||||
|
||||
public static class CommentedTag {
|
||||
private String name;
|
||||
public static class TagNameAndComment {
|
||||
private TagName tagName;
|
||||
private String comment;
|
||||
|
||||
CommentedTag(String name, String comment) {
|
||||
this.name = name;
|
||||
private TagNameAndComment(TagName tagName, String comment) {
|
||||
this.tagName = tagName;
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
public TagName getTagName() {
|
||||
return tagName;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
@@ -58,25 +60,16 @@ public class TagAndCommentDialog extends JDialog {
|
||||
}
|
||||
}
|
||||
|
||||
public static CommentedTag doDialog() {
|
||||
TagAndCommentDialog dialog = new TagAndCommentDialog();
|
||||
if (!dialog.tagName.isEmpty()) {
|
||||
return new CommentedTag(dialog.tagName, dialog.comment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
public static TagNameAndComment doDialog() {
|
||||
GetTagNameAndCommentDialog dialog = new GetTagNameAndCommentDialog();
|
||||
return dialog.tagNameAndComment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new form TagDialog
|
||||
*/
|
||||
private TagAndCommentDialog() {
|
||||
super((JFrame)WindowManager.getDefault().getMainWindow(), "Tag and Comment", true);
|
||||
|
||||
private GetTagNameAndCommentDialog() {
|
||||
super((JFrame)WindowManager.getDefault().getMainWindow(), "Create Tag", true);
|
||||
initComponents();
|
||||
|
||||
// Close the dialog when Esc is pressed
|
||||
// Set up the dialog to close when Esc is pressed.
|
||||
String cancelName = "cancel";
|
||||
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
|
||||
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
|
||||
@@ -87,24 +80,30 @@ public class TagAndCommentDialog extends JDialog {
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
|
||||
// get the current list of tag names
|
||||
TreeSet<String> tags = Tags.getAllTagNames();
|
||||
|
||||
// if there are no tags, add the NO_TAG_MESSAGE
|
||||
if (tags.isEmpty()) {
|
||||
tags.add(NO_TAG_MESSAGE);
|
||||
|
||||
// Populate the combo box with the available tag names and save the
|
||||
// tag name DTOs to be enable to return the one the user selects.
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
List<TagName> currentTagNames = null;
|
||||
try {
|
||||
currentTagNames = tagsManager.getAllTagNames();
|
||||
}
|
||||
|
||||
// add the tags to the combo box
|
||||
for (String tag : tags) {
|
||||
tagCombo.addItem(tag);
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
|
||||
}
|
||||
if (null != currentTagNames && currentTagNames.isEmpty()) {
|
||||
tagCombo.addItem(NO_TAG_NAMES_MESSAGE);
|
||||
}
|
||||
else {
|
||||
for (TagName tagName : currentTagNames) {
|
||||
tagNames.put(tagName.getDisplayName(), tagName);
|
||||
tagCombo.addItem(tagName.getDisplayName());
|
||||
}
|
||||
}
|
||||
|
||||
//center it
|
||||
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
||||
|
||||
setVisible(true); // blocks
|
||||
// Center and show the dialog box.
|
||||
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,30 +129,30 @@ public class TagAndCommentDialog extends JDialog {
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.okButton.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.okButton.text")); // NOI18N
|
||||
okButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
okButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.cancelButton.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.cancelButton.text")); // NOI18N
|
||||
cancelButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
cancelButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
tagCombo.setToolTipText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.tagCombo.toolTipText")); // NOI18N
|
||||
tagCombo.setToolTipText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.tagCombo.toolTipText")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(tagLabel, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.tagLabel.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(tagLabel, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.tagLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentLabel.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentLabel.text")); // NOI18N
|
||||
|
||||
commentText.setText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentText.text")); // NOI18N
|
||||
commentText.setToolTipText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentText.toolTipText")); // NOI18N
|
||||
commentText.setText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.text")); // NOI18N
|
||||
commentText.setToolTipText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.toolTipText")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(newTagButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.newTagButton.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(newTagButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.newTagButton.text")); // NOI18N
|
||||
newTagButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
newTagButtonActionPerformed(evt);
|
||||
@@ -212,27 +211,26 @@ public class TagAndCommentDialog extends JDialog {
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
||||
tagName = (String)tagCombo.getSelectedItem();
|
||||
comment = commentText.getText();
|
||||
tagNameAndComment = new TagNameAndComment(tagNames.get((String)tagCombo.getSelectedItem()), commentText.getText());
|
||||
dispose();
|
||||
}//GEN-LAST:event_okButtonActionPerformed
|
||||
|
||||
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
||||
tagNameAndComment = null;
|
||||
dispose();
|
||||
}//GEN-LAST:event_cancelButtonActionPerformed
|
||||
|
||||
/**
|
||||
* Closes the dialog
|
||||
*/
|
||||
private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
|
||||
tagNameAndComment = null;
|
||||
dispose();
|
||||
}//GEN-LAST:event_closeDialog
|
||||
|
||||
private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed
|
||||
String newTagName = CreateTagDialog.getNewTagNameDialog(null);
|
||||
TagName newTagName = GetTagNameDialog.doDialog();
|
||||
if (newTagName != null) {
|
||||
tagCombo.addItem(newTagName);
|
||||
tagCombo.setSelectedItem(newTagName);
|
||||
tagNames.put(newTagName.getDisplayName(), newTagName);
|
||||
tagCombo.addItem(newTagName.getDisplayName());
|
||||
tagCombo.setSelectedItem(newTagName.getDisplayName());
|
||||
}
|
||||
}//GEN-LAST:event_newTagButtonActionPerformed
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
<Component class="javax.swing.JButton" name="cancelButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
@@ -82,7 +82,7 @@
|
||||
<Component class="javax.swing.JButton" name="okButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
@@ -124,7 +124,7 @@
|
||||
<Component class="javax.swing.JLabel" name="preexistingLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.preexistingLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.preexistingLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
@@ -133,7 +133,7 @@
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="New Tag">
|
||||
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.newTagPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.newTagPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
@@ -168,14 +168,14 @@
|
||||
<Component class="javax.swing.JLabel" name="tagNameLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.tagNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.tagNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tagNameField">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.tagNameField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.tagNameField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
@@ -16,72 +16,130 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.directorytree;
|
||||
package org.sleuthkit.autopsy.actions;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import org.openide.util.ImageUtilities;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
public class CreateTagDialog extends JDialog {
|
||||
public class GetTagNameDialog extends JDialog {
|
||||
private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
|
||||
private static String newTagName;
|
||||
private final HashMap<String, TagName> tagNames = new HashMap<>();
|
||||
private TagName tagName = null;
|
||||
|
||||
/**
|
||||
* Creates new form CreateTagDialog
|
||||
*/
|
||||
private CreateTagDialog(JFrame parent) {
|
||||
super(parent, true);
|
||||
init();
|
||||
}
|
||||
public static TagName doDialog() {
|
||||
GetTagNameDialog dialog = new GetTagNameDialog();
|
||||
return dialog.tagName;
|
||||
}
|
||||
|
||||
public static String getNewTagNameDialog(JFrame parent) {
|
||||
new CreateTagDialog(parent);
|
||||
return newTagName;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
|
||||
setTitle("Create a new tag");
|
||||
|
||||
private GetTagNameDialog() {
|
||||
super((JFrame)WindowManager.getDefault().getMainWindow(), "Create Tag", true);
|
||||
setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH));
|
||||
initComponents();
|
||||
|
||||
tagsTable.setModel(new TagsTableModel());
|
||||
// Set up the dialog to close when Esc is pressed.
|
||||
String cancelName = "cancel";
|
||||
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
|
||||
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
|
||||
ActionMap actionMap = getRootPane().getActionMap();
|
||||
actionMap.put(cancelName, new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
|
||||
// Get the current set of tag names and hash them for a speedy lookup in
|
||||
// case the user chooses an existing tag name from the tag names table.
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
List<TagName> currentTagNames = null;
|
||||
try {
|
||||
currentTagNames = tagsManager.getAllTagNames();
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(GetTagNameDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
|
||||
}
|
||||
if (null != currentTagNames) {
|
||||
for (TagName name : currentTagNames) {
|
||||
this.tagNames.put(name.getDisplayName(), name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentTagNames = new ArrayList<>();
|
||||
}
|
||||
|
||||
// Populate the tag names table.
|
||||
tagsTable.setModel(new TagsTableModel(currentTagNames));
|
||||
tagsTable.setTableHeader(null);
|
||||
|
||||
//completely disable selections
|
||||
tagsTable.setCellSelectionEnabled(false);
|
||||
tagsTable.setFocusable(false);
|
||||
tagsTable.setRowHeight(tagsTable.getRowHeight() + 5);
|
||||
|
||||
setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH));
|
||||
|
||||
Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
// set the popUp window / JFrame
|
||||
int w = this.getSize().width;
|
||||
int h = this.getSize().height;
|
||||
|
||||
// set the location of the popUp Window on the center of the screen
|
||||
setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2);
|
||||
setVisible(true); //blocks
|
||||
|
||||
// Center and show the dialog box.
|
||||
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
private boolean containsIllegalCharacters(String content) {
|
||||
if ((content.contains("\\") || content.contains(":") || content.contains("*")
|
||||
|| content.contains("?") || content.contains("\"") || content.contains("<")
|
||||
|| content.contains(">") || content.contains("|"))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return (content.contains("\\")||
|
||||
content.contains(":") ||
|
||||
content.contains("*") ||
|
||||
content.contains("?") ||
|
||||
content.contains("\"")||
|
||||
content.contains("<") ||
|
||||
content.contains(">") ||
|
||||
content.contains("|"));
|
||||
}
|
||||
|
||||
private class TagsTableModel extends AbstractTableModel {
|
||||
private final ArrayList<TagName> tagNames = new ArrayList<>();
|
||||
|
||||
TagsTableModel(List<TagName> tagNames) {
|
||||
for (TagName tagName : tagNames) {
|
||||
this.tagNames.add(tagName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return tagNames.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueAt(int rowIndex, int columnIndex) {
|
||||
return tagNames.get(rowIndex).getDisplayName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -107,14 +165,14 @@ public class CreateTagDialog extends JDialog {
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.cancelButton.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.cancelButton.text")); // NOI18N
|
||||
cancelButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
cancelButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.okButton.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.okButton.text")); // NOI18N
|
||||
okButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
okButtonActionPerformed(evt);
|
||||
@@ -137,13 +195,13 @@ public class CreateTagDialog extends JDialog {
|
||||
tagsTable.setTableHeader(null);
|
||||
jScrollPane1.setViewportView(tagsTable);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(preexistingLabel, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.preexistingLabel.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(preexistingLabel, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.preexistingLabel.text")); // NOI18N
|
||||
|
||||
newTagPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.newTagPanel.border.title"))); // NOI18N
|
||||
newTagPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.newTagPanel.border.title"))); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(tagNameLabel, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.tagNameLabel.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(tagNameLabel, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.tagNameLabel.text")); // NOI18N
|
||||
|
||||
tagNameField.setText(org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.tagNameField.text")); // NOI18N
|
||||
tagNameField.setText(org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.tagNameField.text")); // NOI18N
|
||||
tagNameField.addKeyListener(new java.awt.event.KeyAdapter() {
|
||||
public void keyReleased(java.awt.event.KeyEvent evt) {
|
||||
tagNameFieldKeyReleased(evt);
|
||||
@@ -211,20 +269,39 @@ public class CreateTagDialog extends JDialog {
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
||||
newTagName = null;
|
||||
tagName = null;
|
||||
dispose();
|
||||
}//GEN-LAST:event_cancelButtonActionPerformed
|
||||
|
||||
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
||||
String tagName = tagNameField.getText();
|
||||
if (tagName.isEmpty()) {
|
||||
String tagDisplayName = tagNameField.getText();
|
||||
if (tagDisplayName.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(null, "Must supply a tag name to continue.", "Tag Name", JOptionPane.ERROR_MESSAGE);
|
||||
} else if (containsIllegalCharacters(tagName)) {
|
||||
JOptionPane.showMessageDialog(null, "The tag name contains illegal characters.\nCannot contain any of the following symbols: \\ : * ? \" < > |",
|
||||
"Illegal Characters", JOptionPane.ERROR_MESSAGE);
|
||||
} else {
|
||||
newTagName = tagName;
|
||||
dispose();
|
||||
}
|
||||
else if (containsIllegalCharacters(tagDisplayName)) {
|
||||
JOptionPane.showMessageDialog(null, "The tag name contains illegal characters.\nCannot contain any of the following symbols: \\ : * ? \" < > |", "Illegal Characters", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
else {
|
||||
tagName = tagNames.get(tagDisplayName);
|
||||
if (tagName == null) {
|
||||
try {
|
||||
tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName);
|
||||
dispose();
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex);
|
||||
JOptionPane.showMessageDialog(null, "Unable to add the " + tagDisplayName + " tag name to the case.", "Tagging Error", JOptionPane.ERROR_MESSAGE);
|
||||
tagName = null;
|
||||
}
|
||||
catch (TagsManager.TagNameAlreadyExistsException ex) {
|
||||
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex);
|
||||
JOptionPane.showMessageDialog(null, "A " + tagDisplayName + " tag name has already been defined.", "Duplicate Tag Error", JOptionPane.ERROR_MESSAGE);
|
||||
tagName = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
}//GEN-LAST:event_okButtonActionPerformed
|
||||
|
||||
@@ -251,32 +328,5 @@ public class CreateTagDialog extends JDialog {
|
||||
private javax.swing.JTable tagsTable;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
private class TagsTableModel extends AbstractTableModel {
|
||||
List<String> tagNames;
|
||||
|
||||
TagsTableModel() {
|
||||
tagNames = new ArrayList<>(Tags.getAllTagNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return tagNames.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueAt(int rowIndex, int columnIndex) {
|
||||
return tagNames.get(rowIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
62
Core/src/org/sleuthkit/autopsy/actions/TagAction.java
Executable file
62
Core/src/org/sleuthkit/autopsy/actions/TagAction.java
Executable file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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 javax.swing.AbstractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
|
||||
/**
|
||||
* Abstract base class for Actions involving tags.
|
||||
*/
|
||||
public abstract class TagAction extends AbstractAction {
|
||||
public TagAction(String menuText) {
|
||||
super(menuText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
doAction(event);
|
||||
refreshDirectoryTree();
|
||||
}
|
||||
|
||||
/**
|
||||
* Derived classes must implement this Template Method for actionPerformed().
|
||||
* @param event ActionEvent object passed to actionPerformed()
|
||||
*/
|
||||
abstract protected void doAction(ActionEvent event);
|
||||
|
||||
/**
|
||||
* Derived classes should call this method any time a tag is created, updated
|
||||
* or deleted outside of an actionPerformed() call.
|
||||
*/
|
||||
protected void refreshDirectoryTree() {
|
||||
// The way the "directory tree" currently works, a new tags sub-tree
|
||||
// needs to be made to reflect the results of invoking tag Actions. The
|
||||
// way to do this is to call DirectoryTreeTopComponent.refreshTree(),
|
||||
// which calls RootContentChildren.refreshKeys(BlackboardArtifact.ARTIFACT_TYPE... types)
|
||||
// for the RootContentChildren object that is the child factory for the
|
||||
// ResultsNode that is the root of the tags sub-tree. There is a switch
|
||||
// statement in RootContentChildren.refreshKeys() that maps both
|
||||
// BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE and BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT
|
||||
// to making a call to refreshKey(TagsNodeKey).
|
||||
DirectoryTreeTopComponent.findInstance().refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
|
||||
}
|
||||
}
|
||||
358
Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java
Normal file
358
Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java
Normal file
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.SleuthkitJNI;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskDataException;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
|
||||
/*
|
||||
* A background task (swingworker) that adds the given image to
|
||||
* database using the Sleuthkit JNI interface.
|
||||
*
|
||||
* It updates the given ProgressMonitor as it works through adding the image,
|
||||
* and et the end, calls the specified Callback.
|
||||
*/
|
||||
public class AddImageTask implements Runnable {
|
||||
|
||||
private Logger logger = Logger.getLogger(AddImageTask.class.getName());
|
||||
|
||||
private Case currentCase;
|
||||
// true if the process was requested to stop
|
||||
private volatile boolean cancelled = false;
|
||||
//true if revert has been invoked.
|
||||
private boolean reverted = false;
|
||||
private boolean hasCritError = false;
|
||||
|
||||
private volatile boolean addImageDone = false;
|
||||
|
||||
private List<String> errorList = new ArrayList<String>();
|
||||
|
||||
private DSPProgressMonitor progressMonitor;
|
||||
private DSPCallback callbackObj;
|
||||
|
||||
private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>());
|
||||
|
||||
private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess;
|
||||
private Thread dirFetcher;
|
||||
|
||||
private String imagePath;
|
||||
private String dataSourcetype;
|
||||
String timeZone;
|
||||
boolean noFatOrphans;
|
||||
|
||||
|
||||
/*
|
||||
* A Swingworker that updates the progressMonitor with the name of the
|
||||
* directory currently being processed by the AddImageTask
|
||||
*/
|
||||
private class CurrentDirectoryFetcher implements Runnable {
|
||||
|
||||
DSPProgressMonitor progressMonitor;
|
||||
SleuthkitJNI.CaseDbHandle.AddImageProcess process;
|
||||
|
||||
CurrentDirectoryFetcher(DSPProgressMonitor aProgressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess proc) {
|
||||
this.progressMonitor = aProgressMonitor;
|
||||
this.process = proc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently processing directory
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
String currDir = process.currentDirectory();
|
||||
if (currDir != null) {
|
||||
if (!currDir.isEmpty() ) {
|
||||
progressMonitor.setProgressText("Adding: " + currDir);
|
||||
}
|
||||
}
|
||||
Thread.sleep(2 * 1000);
|
||||
}
|
||||
return;
|
||||
} catch (InterruptedException ie) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected AddImageTask(String imgPath, String tz, boolean noOrphans, DSPProgressMonitor aProgressMonitor, DSPCallback cbObj ) {
|
||||
|
||||
currentCase = Case.getCurrentCase();
|
||||
|
||||
|
||||
this.imagePath = imgPath;
|
||||
this.timeZone = tz;
|
||||
this.noFatOrphans = noOrphans;
|
||||
|
||||
this.callbackObj = cbObj;
|
||||
this.progressMonitor = aProgressMonitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the addImage process, but does not commit the results.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
|
||||
errorList.clear();
|
||||
|
||||
//lock DB for writes in this thread
|
||||
SleuthkitCase.dbWriteLock();
|
||||
|
||||
addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans);
|
||||
dirFetcher = new Thread( new CurrentDirectoryFetcher(progressMonitor, addImageProcess));
|
||||
|
||||
try {
|
||||
progressMonitor.setIndeterminate(true);
|
||||
progressMonitor.setProgress(0);
|
||||
|
||||
dirFetcher.start();
|
||||
|
||||
addImageProcess.run(new String[]{this.imagePath});
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Core errors occurred while running add image. ", ex);
|
||||
//critical core/system error and process needs to be interrupted
|
||||
hasCritError = true;
|
||||
errorList.add(ex.getMessage());
|
||||
} catch (TskDataException ex) {
|
||||
logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex);
|
||||
errorList.add(ex.getMessage());
|
||||
}
|
||||
finally {
|
||||
|
||||
}
|
||||
|
||||
// handle addImage done
|
||||
postProcess();
|
||||
|
||||
// unclock the DB
|
||||
SleuthkitCase.dbWriteUnlock();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the newly added image to DB
|
||||
*
|
||||
*
|
||||
* @throws Exception if commit or adding the image to the case failed
|
||||
*/
|
||||
private void commitImage() throws Exception {
|
||||
|
||||
long imageId = 0;
|
||||
try {
|
||||
imageId = addImageProcess.commit();
|
||||
} catch (TskException e) {
|
||||
logger.log(Level.WARNING, "Errors occured while committing the image", e);
|
||||
errorList.add(e.getMessage());
|
||||
} finally {
|
||||
|
||||
if (imageId != 0) {
|
||||
// get the newly added Image so we can return to caller
|
||||
Image newImage = currentCase.getSleuthkitCase().getImageById(imageId);
|
||||
|
||||
//while we have the image, verify the size of its contents
|
||||
String verificationErrors = newImage.verifyImageSize();
|
||||
if (verificationErrors.equals("") == false) {
|
||||
//data error (non-critical)
|
||||
errorList.add(verificationErrors);
|
||||
}
|
||||
|
||||
// Add the image to the list of new content
|
||||
newContents.add(newImage);
|
||||
}
|
||||
|
||||
logger.log(Level.INFO, "Image committed, imageId: " + imageId);
|
||||
logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post processing after the addImageProcess is done.
|
||||
*
|
||||
*/
|
||||
private void postProcess() {
|
||||
|
||||
|
||||
// cancel the directory fetcher
|
||||
dirFetcher.interrupt();
|
||||
|
||||
addImageDone = true;
|
||||
// attempt actions that might fail and force the process to stop
|
||||
|
||||
if (cancelled || hasCritError) {
|
||||
logger.log(Level.WARNING, "Critical errors or interruption in add image process. Image will not be comitted.");
|
||||
revert();
|
||||
}
|
||||
|
||||
if (!errorList.isEmpty()) {
|
||||
logger.log(Level.INFO, "There were errors that occured in add image process");
|
||||
}
|
||||
|
||||
|
||||
// When everything happens without an error:
|
||||
if (!(cancelled || hasCritError)) {
|
||||
|
||||
try {
|
||||
// Tell the progress monitor we're done
|
||||
progressMonitor.setProgress(100);
|
||||
|
||||
if (newContents.isEmpty()) {
|
||||
if (addImageProcess != null) { // and if we're done configuring ingest
|
||||
// commit anything
|
||||
try {
|
||||
commitImage();
|
||||
} catch (Exception ex) {
|
||||
errorList.add(ex.getMessage());
|
||||
// Log error/display warning
|
||||
logger.log(Level.SEVERE, "Error adding image to case.", ex);
|
||||
}
|
||||
} else {
|
||||
logger.log(Level.SEVERE, "Missing image process object");
|
||||
}
|
||||
}
|
||||
|
||||
else { //already commited?
|
||||
logger.log(Level.INFO, "Assuming image already committed, will not commit.");
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
//handle unchecked exceptions post image add
|
||||
errorList.add(ex.getMessage());
|
||||
|
||||
logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex);
|
||||
logger.log(Level.SEVERE, "Error adding image to case", ex);
|
||||
} finally {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// invoke the callBack, unless the caller cancelled
|
||||
if (!cancelled) {
|
||||
doCallBack();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Call the callback with results, new content, and errors, if any
|
||||
*/
|
||||
private void doCallBack()
|
||||
{
|
||||
DSPCallback.DSP_Result result;
|
||||
|
||||
if (hasCritError) {
|
||||
result = DSPCallback.DSP_Result.CRITICAL_ERRORS;
|
||||
}
|
||||
else if (!errorList.isEmpty()) {
|
||||
result = DSPCallback.DSP_Result.NONCRITICAL_ERRORS;
|
||||
}
|
||||
else {
|
||||
result = DSPCallback.DSP_Result.NO_ERRORS;
|
||||
}
|
||||
|
||||
// invoke the callcak, passing it the result, list of new contents, and list of errors
|
||||
callbackObj.done(result, errorList, newContents);
|
||||
}
|
||||
|
||||
/*
|
||||
* cancel the image addition, if possible
|
||||
*/
|
||||
public void cancelTask() {
|
||||
|
||||
cancelled = true;
|
||||
|
||||
if (!addImageDone) {
|
||||
try {
|
||||
interrupt();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "Failed to interrup the add image task...");
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
revert();
|
||||
}
|
||||
catch(Exception ex) {
|
||||
logger.log(Level.SEVERE, "Failed to revert the add image task...");
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Interrurp the add image process if it is still running
|
||||
*/
|
||||
private void interrupt() throws Exception {
|
||||
|
||||
try {
|
||||
logger.log(Level.INFO, "interrupt() add image process");
|
||||
addImageProcess.stop(); //it might take time to truly stop processing and writing to db
|
||||
} catch (TskException ex) {
|
||||
throw new Exception("Error stopping add-image process.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Revert - if image has already been added but not committed yet
|
||||
*/
|
||||
void revert() {
|
||||
|
||||
if (!reverted) {
|
||||
try {
|
||||
logger.log(Level.INFO, "Revert after add image process");
|
||||
try {
|
||||
addImageProcess.revert();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Error reverting add image process", ex);
|
||||
}
|
||||
} finally {
|
||||
|
||||
}
|
||||
reverted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,9 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.EventQueue;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
@@ -27,6 +29,7 @@ import javax.swing.event.ChangeListener;
|
||||
import org.openide.WizardDescriptor;
|
||||
import org.openide.util.HelpCtx;
|
||||
import org.openide.util.Lookup;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
|
||||
|
||||
/**
|
||||
* The final panel of the add image wizard. It displays a progress bar and
|
||||
@@ -50,6 +53,49 @@ class AddImageWizardAddingProgressPanel implements WizardDescriptor.FinishablePa
|
||||
private AddImageWizardAddingProgressVisual component;
|
||||
private final Set<ChangeListener> listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0
|
||||
|
||||
private DSPProgressMonitorImpl dspProgressMonitorImpl = new DSPProgressMonitorImpl();
|
||||
|
||||
public DSPProgressMonitorImpl getDSPProgressMonitorImpl() {
|
||||
return dspProgressMonitorImpl;
|
||||
}
|
||||
|
||||
private class DSPProgressMonitorImpl implements DSPProgressMonitor {
|
||||
@Override
|
||||
public void setIndeterminate(final boolean indeterminate) {
|
||||
// update the progress bar asynchronously
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getComponent().getProgressBar().setIndeterminate(indeterminate);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgress(final int progress) {
|
||||
// update the progress bar asynchronously
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getComponent().getProgressBar().setValue(progress);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgressText(final String text) {
|
||||
// update the progress UI asynchronously
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getComponent().setProgressMsgText(text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
/**
|
||||
* Get the visual component for the panel. In this template, the component
|
||||
* is kept separate. This can be more efficient: if the wizard is created
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<Component id="inProgressPanel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="donePanel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="69" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="67" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@@ -136,16 +136,19 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="subTitle2Label" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="progressBar" min="-2" pref="475" max="-2" attributes="1"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" max="-2" attributes="0">
|
||||
<Component id="progressTextArea" max="32767" attributes="0"/>
|
||||
<Component id="progressLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="subTitle1Label" alignment="0" max="32767" attributes="1"/>
|
||||
<Component id="TextArea_CurrentDirectory" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="progressBar" alignment="0" max="32767" attributes="1"/>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="8" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@@ -153,12 +156,10 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="subTitle1Label" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="subTitle2Label" min="-2" pref="14" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="19" max="-2" attributes="0"/>
|
||||
<Component id="progressBar" min="-2" pref="23" max="-2" attributes="1"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="TextArea_CurrentDirectory" min="-2" pref="91" max="-2" attributes="0"/>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="progressTextArea" min="-2" pref="91" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="progressLabel" min="-2" pref="23" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
@@ -185,7 +186,7 @@
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="4"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextArea" name="TextArea_CurrentDirectory">
|
||||
<Component class="javax.swing.JTextArea" name="progressTextArea">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
@@ -196,11 +197,11 @@
|
||||
<Property name="wrapStyleWord" type="boolean" value="true"/>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="Currently Adding:">
|
||||
<TitledBorder title="Status">
|
||||
<Border PropertyName="innerBorder" info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardAddingProgressVisual.TextArea_CurrentDirectory.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardAddingProgressVisual.progressTextArea.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
@@ -213,16 +214,6 @@
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="4"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="subTitle2Label">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardAddingProgressVisual.subTitle2Label.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="4"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="subTitle1Label">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
|
||||
@@ -71,7 +71,7 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
|
||||
donePanel.setVisible(false);
|
||||
viewLogButton.setVisible(false);
|
||||
//match visual background of panel
|
||||
this.TextArea_CurrentDirectory.setBackground(this.getBackground());
|
||||
this.progressTextArea.setBackground(this.getBackground());
|
||||
|
||||
}
|
||||
|
||||
@@ -95,10 +95,10 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
|
||||
/**
|
||||
* Updates the currently processing directory
|
||||
*
|
||||
* @param dir the text to update with
|
||||
* @param msg the text to update with
|
||||
*/
|
||||
public void setCurrentDirText(String dir) {
|
||||
this.TextArea_CurrentDirectory.setText(dir);
|
||||
public void setProgressMsgText(String msg) {
|
||||
this.progressTextArea.setText(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,8 +114,10 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
|
||||
|
||||
//progressBar.setValue(100); //always invoked when process completed
|
||||
if (hasCriticalErrors) {
|
||||
statusLabel.setText("*Failed to add image (critical errors encountered). Click below to view the log.");
|
||||
statusLabel.setForeground(Color.RED);
|
||||
statusLabel.setText("*Failed to add data source (critical errors encountered). Click below to view the log.");
|
||||
} else {
|
||||
statusLabel.setForeground(Color.BLACK);
|
||||
statusLabel.setText("*Data Source added (non-critical errors encountered). Click below to view the log.");
|
||||
}
|
||||
|
||||
@@ -140,8 +142,7 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
|
||||
inProgressPanel = new javax.swing.JPanel();
|
||||
progressBar = new javax.swing.JProgressBar();
|
||||
progressLabel = new javax.swing.JLabel();
|
||||
TextArea_CurrentDirectory = new javax.swing.JTextArea();
|
||||
subTitle2Label = new javax.swing.JLabel();
|
||||
progressTextArea = new javax.swing.JTextArea();
|
||||
subTitle1Label = new javax.swing.JLabel();
|
||||
|
||||
javax.swing.GroupLayout loadingPanelLayout = new javax.swing.GroupLayout(loadingPanel);
|
||||
@@ -193,16 +194,14 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
|
||||
org.openide.awt.Mnemonics.setLocalizedText(progressLabel, org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.progressLabel.text")); // NOI18N
|
||||
progressLabel.setPreferredSize(null);
|
||||
|
||||
TextArea_CurrentDirectory.setEditable(false);
|
||||
TextArea_CurrentDirectory.setBackground(new java.awt.Color(240, 240, 240));
|
||||
TextArea_CurrentDirectory.setLineWrap(true);
|
||||
TextArea_CurrentDirectory.setRows(5);
|
||||
TextArea_CurrentDirectory.setWrapStyleWord(true);
|
||||
TextArea_CurrentDirectory.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.TextArea_CurrentDirectory.border.title"))); // NOI18N
|
||||
TextArea_CurrentDirectory.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR));
|
||||
TextArea_CurrentDirectory.setFocusable(false);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(subTitle2Label, org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.subTitle2Label.text")); // NOI18N
|
||||
progressTextArea.setEditable(false);
|
||||
progressTextArea.setBackground(new java.awt.Color(240, 240, 240));
|
||||
progressTextArea.setLineWrap(true);
|
||||
progressTextArea.setRows(5);
|
||||
progressTextArea.setWrapStyleWord(true);
|
||||
progressTextArea.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.progressTextArea.border.title"))); // NOI18N
|
||||
progressTextArea.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR));
|
||||
progressTextArea.setFocusable(false);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(subTitle1Label, org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.subTitle1Label.text")); // NOI18N
|
||||
|
||||
@@ -210,26 +209,26 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
|
||||
inProgressPanel.setLayout(inProgressPanelLayout);
|
||||
inProgressPanelLayout.setHorizontalGroup(
|
||||
inProgressPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, inProgressPanelLayout.createSequentialGroup()
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, 475, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap())
|
||||
.addGroup(inProgressPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(inProgressPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addComponent(subTitle2Label)
|
||||
.addComponent(progressLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(subTitle1Label, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(TextArea_CurrentDirectory)
|
||||
.addComponent(progressBar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addGap(0, 8, Short.MAX_VALUE))
|
||||
.addGroup(inProgressPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
|
||||
.addComponent(progressTextArea)
|
||||
.addComponent(progressLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(subTitle1Label, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addGap(0, 0, Short.MAX_VALUE))
|
||||
);
|
||||
inProgressPanelLayout.setVerticalGroup(
|
||||
inProgressPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(inProgressPanelLayout.createSequentialGroup()
|
||||
.addComponent(subTitle1Label)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(subTitle2Label, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGap(19, 19, 19)
|
||||
.addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(TextArea_CurrentDirectory, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(progressTextArea, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(progressLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap())
|
||||
@@ -245,7 +244,7 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
|
||||
.addComponent(titleLabel)
|
||||
.addComponent(inProgressPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(donePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGap(0, 69, Short.MAX_VALUE))
|
||||
.addGap(0, 67, Short.MAX_VALUE))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
@@ -268,15 +267,14 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel {
|
||||
dialog.setVisible(true);
|
||||
}//GEN-LAST:event_viewLogButtonActionPerformed
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
protected javax.swing.JTextArea TextArea_CurrentDirectory;
|
||||
protected javax.swing.JPanel donePanel;
|
||||
protected javax.swing.JPanel inProgressPanel;
|
||||
private javax.swing.JPanel loadingPanel;
|
||||
private javax.swing.JProgressBar progressBar;
|
||||
protected javax.swing.JLabel progressLabel;
|
||||
protected javax.swing.JTextArea progressTextArea;
|
||||
protected javax.swing.JLabel statusLabel;
|
||||
protected javax.swing.JLabel subTitle1Label;
|
||||
protected javax.swing.JLabel subTitle2Label;
|
||||
protected javax.swing.JLabel titleLabel;
|
||||
protected javax.swing.JButton viewLogButton;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
@@ -43,6 +43,7 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<Wiza
|
||||
* The visual component that displays this panel. If you need to access the
|
||||
* component from this class, just use getComponent().
|
||||
*/
|
||||
private AddImageWizardAddingProgressPanel progressPanel;
|
||||
private AddImageWizardChooseDataSourceVisual component;
|
||||
private boolean isNextEnable = false;
|
||||
private static final String PROP_LASTDATASOURCE_PATH = "LBL_LastDataSource_PATH";
|
||||
@@ -50,6 +51,12 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<Wiza
|
||||
// paths to any set hash lookup databases (can be null)
|
||||
private String NSRLPath, knownBadPath;
|
||||
|
||||
|
||||
AddImageWizardChooseDataSourcePanel(AddImageWizardAddingProgressPanel proPanel) {
|
||||
|
||||
this.progressPanel = proPanel;
|
||||
|
||||
}
|
||||
/**
|
||||
* Get the visual component for the panel. In this template, the component
|
||||
* is kept separate. This can be more efficient: if the wizard is created
|
||||
@@ -173,13 +180,6 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<Wiza
|
||||
|
||||
// Prepopulate the image directory from the properties file
|
||||
try {
|
||||
String lastDataSourceDirectory = ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_LASTDATASOURCE_PATH);
|
||||
String lastDataSourceType = ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_LASTDATASOURCE_TYPE);
|
||||
|
||||
//set the last path for the content panel for which it was saved
|
||||
if (component.getContentType().toString().equals(lastDataSourceType)) {
|
||||
component.setContentPath(lastDataSourceDirectory);
|
||||
}
|
||||
|
||||
// Load hash database settings, enable or disable the checkbox
|
||||
this.NSRLPath = null;
|
||||
@@ -216,19 +216,8 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel<Wiza
|
||||
*/
|
||||
@Override
|
||||
public void storeSettings(WizardDescriptor settings) {
|
||||
settings.putProperty(AddImageAction.DATASOURCEPATH_PROP, getComponent().getContentPaths());
|
||||
settings.putProperty(AddImageAction.DATASOURCETYPE_PROP, getComponent().getContentType());
|
||||
settings.putProperty(AddImageAction.TIMEZONE_PROP, getComponent().getSelectedTimezone()); // store the timezone
|
||||
settings.putProperty(AddImageAction.NOFATORPHANS_PROP, Boolean.valueOf(getComponent().getNoFatOrphans()));
|
||||
//settings.putProperty(AddImageAction.LOOKUPFILES_PROP, getComponent().getLookupFilesCheckboxChecked());
|
||||
//settings.putProperty(AddImageAction.SOLR_PROP, getComponent().getIndexImageCheckboxChecked());
|
||||
|
||||
// Store the path to the first image selected into the properties file
|
||||
String firstImage = getComponent().getContentPaths();
|
||||
String firstImagePath = firstImage.substring(0, firstImage.lastIndexOf(File.separator) + 1);
|
||||
ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_LASTDATASOURCE_PATH, firstImagePath);
|
||||
ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, PROP_LASTDATASOURCE_TYPE, getComponent().getContentType().toString());
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,16 +39,6 @@
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="nextLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="timeZoneLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="timeZoneComboBox" min="-2" pref="252" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
|
||||
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="imgInfoLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="54" max="32767" attributes="0"/>
|
||||
@@ -65,16 +55,7 @@
|
||||
<Component id="imgInfoLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="inputPanel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" 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"/>
|
||||
</Group>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<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="64" max="32767" attributes="0"/>
|
||||
<EmptySpace pref="45" max="32767" attributes="0"/>
|
||||
<Component id="nextLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
@@ -89,41 +70,6 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="timeZoneLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardChooseDataSourceVisual.timeZoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="timeZoneComboBox">
|
||||
<Properties>
|
||||
<Property name="maximumRowCount" type="int" value="30"/>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="0"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="noFatOrphansCheckbox">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="descLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="AddImageWizardChooseDataSourceVisual.descLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="inputPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
@@ -160,7 +106,7 @@
|
||||
<Component id="typeComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="typePanel" pref="77" max="32767" attributes="0"/>
|
||||
<Component id="typePanel" pref="173" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
@@ -192,7 +138,7 @@
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="77" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="173" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
@@ -204,7 +150,7 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<ContentTypePanel>"/>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
|
||||
@@ -18,49 +18,44 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.Component;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.SimpleTimeZone;
|
||||
import java.util.TimeZone;
|
||||
import javax.swing.ComboBoxModel;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.ListDataListener;
|
||||
import org.sleuthkit.autopsy.casemodule.ContentTypePanel.ContentType;
|
||||
import javax.swing.ListCellRenderer;
|
||||
import org.openide.util.Lookup;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
|
||||
/**
|
||||
* visual component for the first panel of add image wizard. Allows user to pick
|
||||
* data source and timezone.
|
||||
* visual component for the first panel of add image wizard.
|
||||
* Allows the user to choose the data source type and then select the data source
|
||||
*
|
||||
*/
|
||||
final class AddImageWizardChooseDataSourceVisual extends JPanel {
|
||||
|
||||
enum EVENT {
|
||||
|
||||
UPDATE_UI, FOCUS_NEXT
|
||||
};
|
||||
static final List<String> rawExt = Arrays.asList(new String[]{".img", ".dd", ".001", ".aa", ".raw"});
|
||||
static final String rawDesc = "Raw Images (*.img, *.dd, *.001, *.aa, *.raw)";
|
||||
static GeneralFilter rawFilter = new GeneralFilter(rawExt, rawDesc);
|
||||
static final List<String> encaseExt = Arrays.asList(new String[]{".e01"});
|
||||
static final String encaseDesc = "Encase Images (*.e01)";
|
||||
static GeneralFilter encaseFilter = new GeneralFilter(encaseExt, encaseDesc);
|
||||
static final List<String> allExt = new ArrayList<String>();
|
||||
|
||||
static {
|
||||
allExt.addAll(rawExt);
|
||||
allExt.addAll(encaseExt);
|
||||
}
|
||||
static final String allDesc = "All Supported Types";
|
||||
static GeneralFilter allFilter = new GeneralFilter(allExt, allDesc);
|
||||
static final Logger logger = Logger.getLogger(AddImageWizardChooseDataSourceVisual.class.getName());
|
||||
|
||||
private AddImageWizardChooseDataSourcePanel wizPanel;
|
||||
private ContentTypeModel model;
|
||||
private ContentTypePanel currentPanel;
|
||||
|
||||
private JPanel currentPanel;
|
||||
private Map<String, DataSourceProcessor> datasourceProcessorsMap = new HashMap<String, DataSourceProcessor>();
|
||||
|
||||
|
||||
List<String> coreDSPTypes = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Creates new form AddImageVisualPanel1
|
||||
@@ -70,24 +65,83 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
|
||||
AddImageWizardChooseDataSourceVisual(AddImageWizardChooseDataSourcePanel wizPanel) {
|
||||
initComponents();
|
||||
this.wizPanel = wizPanel;
|
||||
createTimeZoneList();
|
||||
|
||||
customInit();
|
||||
}
|
||||
|
||||
private void customInit() {
|
||||
model = new ContentTypeModel();
|
||||
typeComboBox.setModel(model);
|
||||
typeComboBox.setSelectedIndex(0);
|
||||
|
||||
typePanel.setLayout(new BorderLayout());
|
||||
updateCurrentPanel(ImageFilePanel.getDefault());
|
||||
|
||||
discoverDataSourceProcessors();
|
||||
|
||||
// set up the DSP type combobox
|
||||
typeComboBox.removeAllItems();
|
||||
|
||||
Set<String> dspTypes = datasourceProcessorsMap.keySet();
|
||||
|
||||
// make a list of core DSPs
|
||||
// ensure that the core DSPs are at the top and in a fixed order
|
||||
coreDSPTypes.add(ImageDSProcessor.dsType);
|
||||
coreDSPTypes.add(LocalDiskDSProcessor.dsType);
|
||||
coreDSPTypes.add(LocalFilesDSProcessor.dsType);
|
||||
|
||||
for(String dspType:coreDSPTypes){
|
||||
typeComboBox.addItem(dspType);
|
||||
}
|
||||
|
||||
// now add any addtional DSPs that haven't already been added
|
||||
for(String dspType:dspTypes){
|
||||
if (!coreDSPTypes.contains(dspType)) {
|
||||
typeComboBox.addItem(dspType);
|
||||
}
|
||||
}
|
||||
|
||||
// set a custom renderer that draws a separator at the end of the core DSPs in the combobox
|
||||
typeComboBox.setRenderer(new ComboboxSeparatorRenderer(typeComboBox.getRenderer()){
|
||||
@Override
|
||||
protected boolean addSeparatorAfter(JList list, Object value, int index){
|
||||
return (index == coreDSPTypes.size() - 1);
|
||||
}
|
||||
});
|
||||
|
||||
//add actionlistner to listen for change
|
||||
ActionListener cbActionListener = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
dspSelectionChanged();
|
||||
}
|
||||
};
|
||||
typeComboBox.addActionListener(cbActionListener);
|
||||
typeComboBox.setSelectedIndex(0);
|
||||
}
|
||||
|
||||
private void discoverDataSourceProcessors() {
|
||||
|
||||
for (DataSourceProcessor dsProcessor: Lookup.getDefault().lookupAll(DataSourceProcessor.class)) {
|
||||
|
||||
if (!datasourceProcessorsMap.containsKey(dsProcessor.getType()) ) {
|
||||
dsProcessor.reset();
|
||||
datasourceProcessorsMap.put(dsProcessor.getType(), dsProcessor);
|
||||
}
|
||||
else {
|
||||
logger.log(Level.SEVERE, "discoverDataSourceProcessors(): A DataSourceProcessor already exists for type = " + dsProcessor.getType() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dspSelectionChanged() {
|
||||
// update the current panel to selection
|
||||
currentPanel = getCurrentDSProcessor().getPanel();
|
||||
updateCurrentPanel(currentPanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the current panel to the given panel.
|
||||
*
|
||||
* @param panel instance of ImageTypePanel to change to
|
||||
*/
|
||||
private void updateCurrentPanel(ContentTypePanel panel) {
|
||||
private void updateCurrentPanel(JPanel panel) {
|
||||
currentPanel = panel;
|
||||
typePanel.removeAll();
|
||||
typePanel.add((JPanel) currentPanel, BorderLayout.CENTER);
|
||||
@@ -96,28 +150,32 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
|
||||
currentPanel.addPropertyChangeListener(new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString())) {
|
||||
if (evt.getPropertyName().equals(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString())) {
|
||||
updateUI(null);
|
||||
}
|
||||
if (evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.FOCUS_NEXT.toString())) {
|
||||
if (evt.getPropertyName().equals(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString())) {
|
||||
wizPanel.moveFocusToNext();
|
||||
}
|
||||
}
|
||||
});
|
||||
currentPanel.select();
|
||||
if (currentPanel.getContentType().equals(ContentType.LOCAL)) {
|
||||
//disable image specific options
|
||||
noFatOrphansCheckbox.setEnabled(false);
|
||||
descLabel.setEnabled(false);
|
||||
timeZoneComboBox.setEnabled(false);
|
||||
} else {
|
||||
noFatOrphansCheckbox.setEnabled(true);
|
||||
descLabel.setEnabled(true);
|
||||
timeZoneComboBox.setEnabled(true);
|
||||
}
|
||||
|
||||
updateUI(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently selected DS Processor
|
||||
* @return DataSourceProcessor the DataSourceProcessor corresponding to the data source type selected in the combobox
|
||||
*/
|
||||
public DataSourceProcessor getCurrentDSProcessor() {
|
||||
// get the type of the currently selected panel and then look up
|
||||
// the correspodning DS Handler in the map
|
||||
String dsType = (String) typeComboBox.getSelectedItem();
|
||||
DataSourceProcessor dsProcessor = datasourceProcessorsMap.get(dsType);
|
||||
|
||||
return dsProcessor;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the this panel. This name will be shown on the left
|
||||
* panel of the "Add Image" wizard panel.
|
||||
@@ -129,94 +187,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
|
||||
return "Enter Data Source Information";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data sources path from the Image Path Text Field.
|
||||
*
|
||||
* @return data source path, can be comma separated for multiples
|
||||
*/
|
||||
public String getContentPaths() {
|
||||
return currentPanel.getContentPaths();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data sources type selected
|
||||
*
|
||||
* @return data source selected
|
||||
*/
|
||||
public ContentType getContentType() {
|
||||
return currentPanel.getContentType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the data sources panel selected
|
||||
*/
|
||||
public void reset() {
|
||||
currentPanel.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the image path of the current panel.
|
||||
*
|
||||
* @param s the image path to set
|
||||
*/
|
||||
public void setContentPath(String s) {
|
||||
currentPanel.setContentPath(s);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if no fat orphans processing is selected
|
||||
*/
|
||||
boolean getNoFatOrphans() {
|
||||
return noFatOrphansCheckbox.isSelected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time zone that selected on the drop down list.
|
||||
*
|
||||
* @return timeZone the time zone that selected
|
||||
*/
|
||||
public String getSelectedTimezone() {
|
||||
String tz = timeZoneComboBox.getSelectedItem().toString();
|
||||
return tz.substring(tz.indexOf(")") + 2).trim();
|
||||
}
|
||||
|
||||
// add the timeZone list to the timeZoneComboBox
|
||||
/**
|
||||
* Creates the drop down list for the time zones and then makes the local
|
||||
* machine time zones to be selected.
|
||||
*/
|
||||
public void createTimeZoneList() {
|
||||
// load and add all timezone
|
||||
String[] ids = SimpleTimeZone.getAvailableIDs();
|
||||
for (String id : ids) {
|
||||
TimeZone zone = TimeZone.getTimeZone(id);
|
||||
int offset = zone.getRawOffset() / 1000;
|
||||
int hour = offset / 3600;
|
||||
int minutes = (offset % 3600) / 60;
|
||||
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
|
||||
|
||||
/*
|
||||
* DateFormat dfm = new SimpleDateFormat("z");
|
||||
* dfm.setTimeZone(zone); boolean hasDaylight =
|
||||
* zone.useDaylightTime(); String first = dfm.format(new Date(2010,
|
||||
* 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid
|
||||
* = hour * -1; String result = first + Integer.toString(mid);
|
||||
* if(hasDaylight){ result = result + second; }
|
||||
* timeZoneComboBox.addItem(item + " (" + result + ")");
|
||||
*/
|
||||
timeZoneComboBox.addItem(item);
|
||||
}
|
||||
// get the current timezone
|
||||
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
|
||||
int thisOffset = thisTimeZone.getRawOffset() / 1000;
|
||||
int thisHour = thisOffset / 3600;
|
||||
int thisMinutes = (thisOffset % 3600) / 60;
|
||||
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
|
||||
|
||||
// set the selected timezone
|
||||
timeZoneComboBox.setSelectedItem(formatted);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
@@ -229,14 +199,10 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
|
||||
buttonGroup1 = new javax.swing.ButtonGroup();
|
||||
jLabel2 = new javax.swing.JLabel();
|
||||
nextLabel = new javax.swing.JLabel();
|
||||
timeZoneLabel = new javax.swing.JLabel();
|
||||
timeZoneComboBox = new javax.swing.JComboBox<String>();
|
||||
noFatOrphansCheckbox = new javax.swing.JCheckBox();
|
||||
descLabel = new javax.swing.JLabel();
|
||||
inputPanel = new javax.swing.JPanel();
|
||||
typeTabel = new javax.swing.JLabel();
|
||||
typePanel = new javax.swing.JPanel();
|
||||
typeComboBox = new javax.swing.JComboBox<ContentTypePanel>();
|
||||
typeComboBox = new javax.swing.JComboBox<String>();
|
||||
imgInfoLabel = new javax.swing.JLabel();
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.jLabel2.text")); // NOI18N
|
||||
@@ -245,15 +211,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(nextLabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.nextLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.timeZoneLabel.text")); // NOI18N
|
||||
|
||||
timeZoneComboBox.setMaximumRowCount(30);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.text")); // NOI18N
|
||||
noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.toolTipText")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.descLabel.text")); // NOI18N
|
||||
|
||||
inputPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(typeTabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.typeTabel.text")); // NOI18N
|
||||
@@ -269,7 +226,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
|
||||
);
|
||||
typePanelLayout.setVerticalGroup(
|
||||
typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 77, Short.MAX_VALUE)
|
||||
.addGap(0, 173, Short.MAX_VALUE)
|
||||
);
|
||||
|
||||
javax.swing.GroupLayout inputPanelLayout = new javax.swing.GroupLayout(inputPanel);
|
||||
@@ -295,7 +252,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
|
||||
.addComponent(typeTabel)
|
||||
.addComponent(typeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 77, Short.MAX_VALUE)
|
||||
.addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 173, Short.MAX_VALUE)
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
@@ -313,14 +270,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(nextLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(timeZoneLabel)
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 252, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addComponent(noFatOrphansCheckbox)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(21, 21, 21)
|
||||
.addComponent(descLabel))
|
||||
.addComponent(imgInfoLabel))
|
||||
.addGap(0, 54, Short.MAX_VALUE)))
|
||||
.addContainerGap())
|
||||
@@ -332,30 +281,18 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
|
||||
.addComponent(imgInfoLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(inputPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.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))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(noFatOrphansCheckbox)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(descLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 64, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 45, Short.MAX_VALUE)
|
||||
.addComponent(nextLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.ButtonGroup buttonGroup1;
|
||||
private javax.swing.JLabel descLabel;
|
||||
private javax.swing.JLabel imgInfoLabel;
|
||||
private javax.swing.JPanel inputPanel;
|
||||
private javax.swing.JLabel jLabel2;
|
||||
private javax.swing.JLabel nextLabel;
|
||||
private javax.swing.JCheckBox noFatOrphansCheckbox;
|
||||
private javax.swing.JComboBox<String> timeZoneComboBox;
|
||||
private javax.swing.JLabel timeZoneLabel;
|
||||
private javax.swing.JComboBox<ContentTypePanel> typeComboBox;
|
||||
private javax.swing.JComboBox<String> typeComboBox;
|
||||
private javax.swing.JPanel typePanel;
|
||||
private javax.swing.JLabel typeTabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
@@ -369,44 +306,31 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
|
||||
* @param e the document event
|
||||
*/
|
||||
public void updateUI(DocumentEvent e) {
|
||||
this.wizPanel.enableNextButton(currentPanel.enableNext());
|
||||
// Enable the Next button if the current DSP panel is valid
|
||||
this.wizPanel.enableNextButton(getCurrentDSProcessor().validatePanel());
|
||||
}
|
||||
|
||||
/**
|
||||
* ComboBoxModel to control typeComboBox and supply ImageTypePanels.
|
||||
*/
|
||||
private class ContentTypeModel implements ComboBoxModel<ContentTypePanel> {
|
||||
|
||||
public abstract class ComboboxSeparatorRenderer implements ListCellRenderer{
|
||||
private ListCellRenderer delegate;
|
||||
private JPanel separatorPanel = new JPanel(new BorderLayout());
|
||||
private JSeparator separator = new JSeparator();
|
||||
|
||||
private ContentTypePanel selected;
|
||||
private ContentTypePanel[] types = ContentTypePanel.getPanels();
|
||||
|
||||
@Override
|
||||
public void setSelectedItem(Object anItem) {
|
||||
selected = (ContentTypePanel) anItem;
|
||||
updateCurrentPanel(selected);
|
||||
public ComboboxSeparatorRenderer(ListCellRenderer delegate){
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSelectedItem() {
|
||||
return selected;
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus){
|
||||
Component comp = delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
if(index!=-1 && addSeparatorAfter(list, value, index)){
|
||||
separatorPanel.removeAll();
|
||||
separatorPanel.add(comp, BorderLayout.CENTER);
|
||||
separatorPanel.add(separator, BorderLayout.SOUTH);
|
||||
return separatorPanel;
|
||||
}else
|
||||
return comp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return types.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentTypePanel getElementAt(int index) {
|
||||
return types[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListDataListener(ListDataListener l) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListDataListener(ListDataListener l) {
|
||||
}
|
||||
protected abstract boolean addSeparatorAfter(JList list, Object value, int index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,41 +18,25 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
|
||||
import org.sleuthkit.autopsy.ingest.IngestConfigurator;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Window;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JProgressBar;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import org.openide.WizardDescriptor;
|
||||
import org.openide.util.HelpCtx;
|
||||
import org.openide.util.Lookup;
|
||||
import org.sleuthkit.autopsy.casemodule.ContentTypePanel.ContentType;
|
||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.FileSystem;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.SleuthkitJNI.CaseDbHandle.AddImageProcess;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskDataException;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
import org.sleuthkit.datamodel.Volume;
|
||||
import org.sleuthkit.datamodel.VolumeSystem;
|
||||
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
/**
|
||||
* second panel of add image wizard, allows user to configure ingest modules.
|
||||
*
|
||||
@@ -68,28 +52,27 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
|
||||
* component from this class, just use getComponent().
|
||||
*/
|
||||
private Component component = null;
|
||||
|
||||
private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>());
|
||||
private boolean ingested = false;
|
||||
private boolean readyToIngest = false;
|
||||
// the paths of the image files to be added
|
||||
private String dataSourcePath;
|
||||
private ContentType dataSourceType;
|
||||
// the time zone where the image is added
|
||||
private String timeZone;
|
||||
//whether to not process FAT filesystem orphans
|
||||
private boolean noFatOrphans;
|
||||
|
||||
// task that will clean up the created database file if the wizard is cancelled before it finishes
|
||||
private AddImageAction.CleanupTask cleanupImage; // initialized to null in readSettings()
|
||||
private CurrentDirectoryFetcher fetcher;
|
||||
private AddImageProcess process;
|
||||
private AddImageAction action;
|
||||
private AddImageTask addImageTask;
|
||||
private AddLocalFilesTask addLocalFilesTask;
|
||||
private AddImageAction.CleanupTask cleanupTask;
|
||||
|
||||
private AddImageAction addImageAction;
|
||||
|
||||
private AddImageWizardAddingProgressPanel progressPanel;
|
||||
private AddImageWizardChooseDataSourcePanel dataSourcePanel;
|
||||
|
||||
private DataSourceProcessor dsProcessor;
|
||||
|
||||
|
||||
AddImageWizardIngestConfigPanel(AddImageAction action, AddImageWizardAddingProgressPanel proPanel) {
|
||||
this.action = action;
|
||||
AddImageWizardIngestConfigPanel(AddImageWizardChooseDataSourcePanel dsPanel, AddImageAction action, AddImageWizardAddingProgressPanel proPanel) {
|
||||
this.addImageAction = action;
|
||||
this.progressPanel = proPanel;
|
||||
this.dataSourcePanel = dsPanel;
|
||||
|
||||
ingestConfig = Lookup.getDefault().lookup(IngestConfigurator.class);
|
||||
List<String> messages = ingestConfig.setContext(AddImageWizardIngestConfigPanel.class.getCanonicalName());
|
||||
if (messages.isEmpty() == false) {
|
||||
@@ -183,24 +166,14 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
|
||||
JButton cancel = new JButton("Cancel");
|
||||
cancel.setEnabled(false);
|
||||
settings.setOptions(new Object[]{WizardDescriptor.PREVIOUS_OPTION, WizardDescriptor.NEXT_OPTION, WizardDescriptor.FINISH_OPTION, cancel});
|
||||
cleanupImage = null;
|
||||
cleanupTask = null;
|
||||
readyToIngest = false;
|
||||
|
||||
newContents.clear();
|
||||
dataSourcePath = (String) settings.getProperty(AddImageAction.DATASOURCEPATH_PROP);
|
||||
dataSourceType = (ContentType) settings.getProperty(AddImageAction.DATASOURCETYPE_PROP);
|
||||
timeZone = settings.getProperty(AddImageAction.TIMEZONE_PROP).toString();
|
||||
noFatOrphans = ((Boolean) settings.getProperty(AddImageAction.NOFATORPHANS_PROP)).booleanValue();
|
||||
|
||||
//start the process of adding the content
|
||||
if (dataSourceType.equals(ContentType.LOCAL)) {
|
||||
addLocalFilesTask = new AddLocalFilesTask(settings);
|
||||
addLocalFilesTask.execute();
|
||||
} else {
|
||||
//disk or image
|
||||
addImageTask = new AddImageTask(settings);
|
||||
addImageTask.execute();
|
||||
}
|
||||
|
||||
// Start processing the data source by handing it off to the selected DSP,
|
||||
// so it gets going in the background while the user is still picking the Ingest modules
|
||||
startDataSourceProcessing(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,470 +207,102 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel<WizardDe
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for getting the currently processing directory.
|
||||
*
|
||||
|
||||
/**
|
||||
* Starts the Data source processing by kicking off the selected DataSourceProcessor
|
||||
*/
|
||||
private static class CurrentDirectoryFetcher extends SwingWorker<Integer, Integer> {
|
||||
|
||||
AddImageTask task;
|
||||
JProgressBar prog;
|
||||
AddImageWizardAddingProgressVisual wiz;
|
||||
AddImageProcess proc;
|
||||
|
||||
CurrentDirectoryFetcher(JProgressBar prog, AddImageWizardAddingProgressVisual wiz, AddImageProcess proc) {
|
||||
this.wiz = wiz;
|
||||
this.proc = proc;
|
||||
this.prog = prog;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently processing directory
|
||||
*/
|
||||
@Override
|
||||
protected Integer doInBackground() {
|
||||
try {
|
||||
while (prog.getValue() < 100 || prog.isIndeterminate()) { //TODO Rely on state variable in AddImgTask class
|
||||
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
wiz.setCurrentDirText(proc.currentDirectory());
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(2 * 1000);
|
||||
}
|
||||
return 1;
|
||||
} catch (InterruptedException ie) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread that will add logical files to database, and then kick-off ingest
|
||||
* modules. Note: the add logical files task cannot currently be reverted as
|
||||
* the add image task can. This is a separate task from AddImgTask because
|
||||
* it is much simpler and does not require locks, since the underlying file
|
||||
* manager methods acquire the locks for each transaction when adding
|
||||
* logical files.
|
||||
*/
|
||||
private class AddLocalFilesTask extends SwingWorker<Integer, Integer> {
|
||||
|
||||
private JProgressBar progressBar;
|
||||
private Case currentCase;
|
||||
// true if the process was requested to stop
|
||||
private boolean interrupted = false;
|
||||
private boolean hasCritError = false;
|
||||
private String errorString = null;
|
||||
private WizardDescriptor settings;
|
||||
private Logger logger = Logger.getLogger(AddLocalFilesTask.class.getName());
|
||||
|
||||
protected AddLocalFilesTask(WizardDescriptor settings) {
|
||||
this.progressBar = progressPanel.getComponent().getProgressBar();
|
||||
currentCase = Case.getCurrentCase();
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the addImage process, but does not commit the results.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected Integer doInBackground() {
|
||||
this.setProgress(0);
|
||||
// Add a cleanup task to interupt the backgroud process if the
|
||||
// wizard exits while the background process is running.
|
||||
AddImageAction.CleanupTask cancelledWhileRunning = action.new CleanupTask() {
|
||||
@Override
|
||||
void cleanup() throws Exception {
|
||||
logger.log(Level.INFO, "Add logical files process interrupted.");
|
||||
//nothing to be cleanedup
|
||||
}
|
||||
};
|
||||
|
||||
cancelledWhileRunning.enable();
|
||||
final LocalFilesAddProgressUpdater progUpdater = new LocalFilesAddProgressUpdater(this.progressBar, progressPanel.getComponent());
|
||||
try {
|
||||
final FileManager fileManager = currentCase.getServices().getFileManager();
|
||||
progressPanel.setStateStarted();
|
||||
String[] paths = dataSourcePath.split(LocalFilesPanel.FILES_SEP);
|
||||
List<String> absLocalPaths = new ArrayList<String>();
|
||||
for (String path : paths) {
|
||||
absLocalPaths.add(path);
|
||||
}
|
||||
newContents.add(fileManager.addLocalFilesDirs(absLocalPaths, progUpdater));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Errors occurred while running add logical files. ", ex);
|
||||
hasCritError = true;
|
||||
errorString = ex.getMessage();
|
||||
} finally {
|
||||
// process is over, doesn't need to be dealt with if cancel happens
|
||||
cancelledWhileRunning.disable();
|
||||
//enqueue what would be in done() to EDT thread
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
postProcess();
|
||||
}
|
||||
});
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* (called by EventDispatch Thread after doInBackground finishes)
|
||||
*/
|
||||
protected void postProcess() {
|
||||
progressBar.setIndeterminate(false);
|
||||
setProgress(100);
|
||||
|
||||
//clear updates
|
||||
// progressPanel.getComponent().setProcessInvis();
|
||||
|
||||
if (interrupted || hasCritError) {
|
||||
logger.log(Level.INFO, "Handling errors or interruption that occured in logical files process");
|
||||
if (hasCritError) {
|
||||
//core error
|
||||
progressPanel.getComponent().showErrors(errorString, true);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (errorString != null) {
|
||||
//data error (non-critical)
|
||||
logger.log(Level.INFO, "Handling non-critical errors that occured in logical files process");
|
||||
progressPanel.getComponent().showErrors(errorString, false);
|
||||
}
|
||||
}
|
||||
try {
|
||||
// When everything happens without an error:
|
||||
if (errorString == null) { // complete progress bar
|
||||
progressPanel.getComponent().setProgressBarTextAndColor("*Logical Files added.", 100, Color.black);
|
||||
}
|
||||
|
||||
// Get attention for the process finish
|
||||
java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP!
|
||||
AddImageWizardAddingProgressVisual panel = progressPanel.getComponent();
|
||||
if (panel != null) {
|
||||
Window w = SwingUtilities.getWindowAncestor(panel);
|
||||
if (w != null) {
|
||||
w.toFront();
|
||||
}
|
||||
}
|
||||
|
||||
progressPanel.setStateFinished();
|
||||
|
||||
//notify the case
|
||||
if (!newContents.isEmpty()) {
|
||||
Case.getCurrentCase().addLocalDataSource(newContents.get(0));
|
||||
}
|
||||
|
||||
// Start ingest if we can
|
||||
startIngest();
|
||||
|
||||
} catch (Exception ex) {
|
||||
//handle unchecked exceptions
|
||||
logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex);
|
||||
progressPanel.getComponent().setProgressBarTextAndColor("*Failed to add image.", 0, Color.black); // set error message
|
||||
logger.log(Level.SEVERE, "Error adding image to case", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the wizard status with logical file/folder
|
||||
*/
|
||||
private class LocalFilesAddProgressUpdater implements FileManager.FileAddProgressUpdater {
|
||||
|
||||
private int count = 0;
|
||||
private JProgressBar prog;
|
||||
private AddImageWizardAddingProgressVisual wiz;
|
||||
|
||||
LocalFilesAddProgressUpdater(JProgressBar prog, AddImageWizardAddingProgressVisual wiz) {
|
||||
this.wiz = wiz;
|
||||
this.prog = prog;
|
||||
}
|
||||
|
||||
private void startDataSourceProcessing(WizardDescriptor settings) {
|
||||
|
||||
|
||||
|
||||
// Add a cleanup task to interrupt the background process if the
|
||||
// wizard exits while the background process is running.
|
||||
cleanupTask = addImageAction.new CleanupTask() {
|
||||
@Override
|
||||
public void fileAdded(final AbstractFile newFile) {
|
||||
if (count++ % 10 == 0 && (prog.getValue() < 100 || prog.isIndeterminate())) {
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
wiz.setCurrentDirText(newFile.getParentPath() + "/" + newFile.getName());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
void cleanup() throws Exception {
|
||||
cancelDataSourceProcessing();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cleanupTask.enable();
|
||||
|
||||
// get the selected DSProcessor
|
||||
dsProcessor = dataSourcePanel.getComponent().getCurrentDSProcessor();
|
||||
|
||||
DSPCallback cbObj = new DSPCallback () {
|
||||
@Override
|
||||
public void doneEDT(DSPCallback.DSP_Result result, List<String> errList, List<Content> contents) {
|
||||
dataSourceProcessorDone(result, errList, contents );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
progressPanel.setStateStarted();
|
||||
|
||||
// Kick off the DSProcessor
|
||||
dsProcessor.run(progressPanel.getDSPProgressMonitorImpl(), cbObj);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread that will make the JNI call to add image to database, and then
|
||||
* kick-off ingest modules.
|
||||
/*
|
||||
* Cancels the data source processing - in case the users presses 'Cancel'
|
||||
*/
|
||||
private class AddImageTask extends SwingWorker<Integer, Integer> {
|
||||
|
||||
private JProgressBar progressBar;
|
||||
private Case currentCase;
|
||||
// true if the process was requested to stop
|
||||
private boolean interrupted = false;
|
||||
private boolean hasCritError = false;
|
||||
private String errorString = null;
|
||||
private WizardDescriptor wizDescriptor;
|
||||
private Logger logger = Logger.getLogger(AddImageTask.class.getName());
|
||||
|
||||
protected AddImageTask(WizardDescriptor settings) {
|
||||
this.progressBar = progressPanel.getComponent().getProgressBar();
|
||||
currentCase = Case.getCurrentCase();
|
||||
this.wizDescriptor = settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the addImage process, but does not commit the results.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected Integer doInBackground() {
|
||||
|
||||
this.setProgress(0);
|
||||
|
||||
|
||||
// Add a cleanup task to interupt the backgroud process if the
|
||||
// wizard exits while the background process is running.
|
||||
AddImageAction.CleanupTask cancelledWhileRunning = action.new CleanupTask() {
|
||||
@Override
|
||||
void cleanup() throws Exception {
|
||||
logger.log(Level.INFO, "Add image process interrupted.");
|
||||
addImageTask.interrupt(); //it might take time to truly interrupt
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
try {
|
||||
//lock DB for writes in EWT thread
|
||||
//wait until lock acquired in EWT
|
||||
EventQueue.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SleuthkitCase.dbWriteLock();
|
||||
}
|
||||
});
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex);
|
||||
return 0;
|
||||
|
||||
} catch (InvocationTargetException ex) {
|
||||
logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
process = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans);
|
||||
fetcher = new CurrentDirectoryFetcher(this.progressBar, progressPanel.getComponent(), process);
|
||||
cancelledWhileRunning.enable();
|
||||
try {
|
||||
progressPanel.setStateStarted();
|
||||
fetcher.execute();
|
||||
process.run(new String[]{dataSourcePath});
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Core errors occurred while running add image. ", ex);
|
||||
//critical core/system error and process needs to be interrupted
|
||||
hasCritError = true;
|
||||
errorString = ex.getMessage();
|
||||
} catch (TskDataException ex) {
|
||||
logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex);
|
||||
errorString = ex.getMessage();
|
||||
} finally {
|
||||
// process is over, doesn't need to be dealt with if cancel happens
|
||||
cancelledWhileRunning.disable();
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the finished AddImageProcess, and cancel the CleanupTask that
|
||||
* would have reverted it.
|
||||
*
|
||||
* @param settings property set to get AddImageProcess and CleanupTask
|
||||
* from
|
||||
*
|
||||
* @throws Exception if commit or adding the image to the case failed
|
||||
*/
|
||||
private void commitImage(WizardDescriptor settings) throws Exception {
|
||||
|
||||
String contentPath = (String) settings.getProperty(AddImageAction.DATASOURCEPATH_PROP);
|
||||
|
||||
String timezone = settings.getProperty(AddImageAction.TIMEZONE_PROP).toString();
|
||||
settings.putProperty(AddImageAction.IMAGEID_PROP, "");
|
||||
|
||||
long imageId = 0;
|
||||
try {
|
||||
imageId = process.commit();
|
||||
} catch (TskException e) {
|
||||
logger.log(Level.WARNING, "Errors occured while committing the image", e);
|
||||
} finally {
|
||||
//commit done, unlock db write in EWT thread
|
||||
//before doing anything else
|
||||
SleuthkitCase.dbWriteUnlock();
|
||||
|
||||
if (imageId != 0) {
|
||||
Image newImage = Case.getCurrentCase().addImage(contentPath, imageId, timezone);
|
||||
|
||||
//while we have the image, verify the size of its contents
|
||||
String verificationErrors = newImage.verifyImageSize();
|
||||
if (verificationErrors.equals("") == false) {
|
||||
//data error (non-critical)
|
||||
progressPanel.addErrors(verificationErrors, false);
|
||||
}
|
||||
|
||||
|
||||
newContents.add(newImage);
|
||||
settings.putProperty(AddImageAction.IMAGEID_PROP, imageId);
|
||||
}
|
||||
|
||||
// Can't bail and revert image add after commit, so disable image cleanup
|
||||
// task
|
||||
cleanupImage.disable();
|
||||
settings.putProperty(AddImageAction.IMAGECLEANUPTASK_PROP, null);
|
||||
|
||||
logger.log(Level.INFO, "Image committed, imageId: " + imageId);
|
||||
logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo());
|
||||
|
||||
private void cancelDataSourceProcessing() {
|
||||
dsProcessor.cancel();
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for the data source processor.
|
||||
* Invoked by the DSP on the EDT thread, when it finishes processing the data source.
|
||||
*/
|
||||
private void dataSourceProcessorDone(DSPCallback.DSP_Result result, List<String> errList, List<Content> contents) {
|
||||
|
||||
// disable the cleanup task
|
||||
cleanupTask.disable();
|
||||
|
||||
// Get attention for the process finish
|
||||
java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP!
|
||||
AddImageWizardAddingProgressVisual panel = progressPanel.getComponent();
|
||||
if (panel != null) {
|
||||
Window w = SwingUtilities.getWindowAncestor(panel);
|
||||
if (w != null) {
|
||||
w.toFront();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* (called by EventDispatch Thread after doInBackground finishes)
|
||||
*/
|
||||
@Override
|
||||
protected void done() {
|
||||
//these are required to stop the CurrentDirectoryFetcher
|
||||
progressBar.setIndeterminate(false);
|
||||
setProgress(100);
|
||||
|
||||
// attempt actions that might fail and force the process to stop
|
||||
|
||||
if (interrupted || hasCritError) {
|
||||
logger.log(Level.INFO, "Handling errors or interruption that occured in add image process");
|
||||
revert();
|
||||
if (hasCritError) {
|
||||
//core error
|
||||
progressPanel.addErrors(errorString, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (errorString != null) {
|
||||
//data error (non-critical)
|
||||
logger.log(Level.INFO, "Handling non-critical errors that occured in add image process");
|
||||
progressPanel.addErrors(errorString, false);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
// When everything happens without an error:
|
||||
|
||||
// the add-image process needs to be reverted if the wizard doesn't finish
|
||||
cleanupImage = action.new CleanupTask() {
|
||||
//note, CleanupTask runs inside EWT thread
|
||||
@Override
|
||||
void cleanup() throws Exception {
|
||||
logger.log(Level.INFO, "Running cleanup task after add image process");
|
||||
revert();
|
||||
}
|
||||
};
|
||||
cleanupImage.enable();
|
||||
|
||||
if (errorString == null) { // complete progress bar
|
||||
progressPanel.getComponent().setProgressBarTextAndColor("*Data Source added.", 100, Color.black);
|
||||
}
|
||||
|
||||
// Get attention for the process finish
|
||||
java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP!
|
||||
AddImageWizardAddingProgressVisual panel = progressPanel.getComponent();
|
||||
if (panel != null) {
|
||||
Window w = SwingUtilities.getWindowAncestor(panel);
|
||||
if (w != null) {
|
||||
w.toFront();
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the panel we're done
|
||||
progressPanel.setStateFinished();
|
||||
|
||||
// Commit the image
|
||||
if (!newContents.isEmpty()) //already commited
|
||||
{
|
||||
logger.log(Level.INFO, "Assuming image already committed, will not commit.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (process != null) { // and if we're done configuring ingest
|
||||
// commit anything
|
||||
try {
|
||||
commitImage(wizDescriptor);
|
||||
} catch (Exception ex) {
|
||||
// Log error/display warning
|
||||
logger.log(Level.SEVERE, "Error adding image to case.", ex);
|
||||
}
|
||||
} else {
|
||||
logger.log(Level.SEVERE, "Missing image process object");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Start ingest if we can
|
||||
startIngest();
|
||||
|
||||
} catch (Exception ex) {
|
||||
//handle unchecked exceptions post image add
|
||||
|
||||
logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex);
|
||||
|
||||
progressPanel.getComponent().setProgressBarTextAndColor("*Failed to add image.", 0, Color.black); // set error message
|
||||
|
||||
// Log error/display warning
|
||||
|
||||
logger.log(Level.SEVERE, "Error adding image to case", ex);
|
||||
} finally {
|
||||
}
|
||||
// Tell the panel we're done
|
||||
progressPanel.setStateFinished();
|
||||
|
||||
|
||||
//check the result and display to user
|
||||
if (result == DSPCallback.DSP_Result.NO_ERRORS)
|
||||
progressPanel.getComponent().setProgressBarTextAndColor("*Data Source added.", 100, Color.black);
|
||||
else
|
||||
progressPanel.getComponent().setProgressBarTextAndColor("*Errors encountered in adding Data Source.", 100, Color.red);
|
||||
|
||||
|
||||
//if errors, display them on the progress panel
|
||||
boolean critErr = false;
|
||||
if (result == DSPCallback.DSP_Result.CRITICAL_ERRORS) {
|
||||
critErr = true;
|
||||
}
|
||||
for ( String err: errList ) {
|
||||
// TBD: there probably should be an error level for each error
|
||||
progressPanel.addErrors(err, critErr);
|
||||
}
|
||||
|
||||
newContents.clear();
|
||||
newContents.addAll(contents);
|
||||
|
||||
//notify the UI of the new content added to the case
|
||||
if (!newContents.isEmpty()) {
|
||||
|
||||
Case.getCurrentCase().notifyNewDataSource(newContents.get(0));
|
||||
}
|
||||
|
||||
void interrupt() throws Exception {
|
||||
interrupted = true;
|
||||
try {
|
||||
logger.log(Level.INFO, "interrupt() add image process");
|
||||
process.stop(); //it might take time to truly stop processing and writing to db
|
||||
} catch (TskException ex) {
|
||||
throw new Exception("Error stopping add-image process.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
//runs in EWT
|
||||
void revert() {
|
||||
try {
|
||||
logger.log(Level.INFO, "Revert after add image process");
|
||||
try {
|
||||
process.revert();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Error reverting add image process", ex);
|
||||
}
|
||||
} finally {
|
||||
//unlock db write within EWT thread
|
||||
SleuthkitCase.dbWriteUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
// Start ingest if we can
|
||||
progressPanel.setStateStarted();
|
||||
startIngest();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,11 +47,16 @@ class AddImageWizardIterator implements WizardDescriptor.Iterator<WizardDescript
|
||||
*/
|
||||
private List<WizardDescriptor.Panel<WizardDescriptor>> getPanels() {
|
||||
if (panels == null) {
|
||||
AddImageWizardAddingProgressPanel wizPanel = new AddImageWizardAddingProgressPanel();
|
||||
panels = new ArrayList<WizardDescriptor.Panel<WizardDescriptor>>();
|
||||
panels.add(new AddImageWizardChooseDataSourcePanel());
|
||||
panels.add(new AddImageWizardIngestConfigPanel(action, wizPanel));
|
||||
panels.add(wizPanel);
|
||||
|
||||
AddImageWizardAddingProgressPanel progressPanel = new AddImageWizardAddingProgressPanel();
|
||||
|
||||
AddImageWizardChooseDataSourcePanel dsPanel = new AddImageWizardChooseDataSourcePanel(progressPanel);
|
||||
AddImageWizardIngestConfigPanel ingestConfigPanel = new AddImageWizardIngestConfigPanel(dsPanel, action, progressPanel);
|
||||
|
||||
panels.add(dsPanel);
|
||||
panels.add(ingestConfigPanel);
|
||||
panels.add(progressPanel);
|
||||
|
||||
String[] steps = new String[panels.size()];
|
||||
for (int i = 0; i < panels.size(); i++) {
|
||||
|
||||
185
Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java
Normal file
185
Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
|
||||
/**
|
||||
* Thread that will add logical files to database, and then kick-off ingest
|
||||
* modules. Note: the add logical files task cannot currently be reverted as
|
||||
* the add image task can. This is a separate task from AddImgTask because
|
||||
* it is much simpler and does not require locks, since the underlying file
|
||||
* manager methods acquire the locks for each transaction when adding
|
||||
* logical files.
|
||||
*/
|
||||
public class AddLocalFilesTask implements Runnable {
|
||||
|
||||
private Logger logger = Logger.getLogger(AddLocalFilesTask.class.getName());
|
||||
|
||||
private String dataSourcePath;
|
||||
private DSPProgressMonitor progressMonitor;
|
||||
private DSPCallback callbackObj;
|
||||
|
||||
private Case currentCase;
|
||||
// true if the process was requested to stop
|
||||
private volatile boolean cancelled = false;
|
||||
private boolean hasCritError = false;
|
||||
|
||||
private List<String> errorList = new ArrayList<String>();
|
||||
private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>());
|
||||
|
||||
|
||||
protected AddLocalFilesTask(String dataSourcePath, DSPProgressMonitor aProgressMonitor, DSPCallback cbObj) {
|
||||
|
||||
currentCase = Case.getCurrentCase();
|
||||
|
||||
this.dataSourcePath = dataSourcePath;
|
||||
this.callbackObj = cbObj;
|
||||
this.progressMonitor = aProgressMonitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the addImage process, but does not commit the results.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
errorList.clear();
|
||||
|
||||
final LocalFilesAddProgressUpdater progUpdater = new LocalFilesAddProgressUpdater(progressMonitor);
|
||||
try {
|
||||
|
||||
progressMonitor.setIndeterminate(true);
|
||||
progressMonitor.setProgress(0);
|
||||
|
||||
final FileManager fileManager = currentCase.getServices().getFileManager();
|
||||
String[] paths = dataSourcePath.split(LocalFilesPanel.FILES_SEP);
|
||||
List<String> absLocalPaths = new ArrayList<String>();
|
||||
for (String path : paths) {
|
||||
absLocalPaths.add(path);
|
||||
}
|
||||
newContents.add(fileManager.addLocalFilesDirs(absLocalPaths, progUpdater));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Errors occurred while running add logical files. ", ex);
|
||||
hasCritError = true;
|
||||
errorList.add(ex.getMessage());
|
||||
} finally {
|
||||
|
||||
}
|
||||
|
||||
// handle done
|
||||
postProcess();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* (called by EventDispatch Thread after doInBackground finishes)
|
||||
*/
|
||||
protected void postProcess() {
|
||||
|
||||
if (cancelled || hasCritError) {
|
||||
logger.log(Level.WARNING, "Handling errors or interruption that occured in logical files process");
|
||||
|
||||
}
|
||||
if (!errorList.isEmpty()) {
|
||||
//data error (non-critical)
|
||||
logger.log(Level.WARNING, "Handling non-critical errors that occured in logical files process");
|
||||
}
|
||||
|
||||
if (!(cancelled || hasCritError)) {
|
||||
progressMonitor.setProgress(100);
|
||||
progressMonitor.setIndeterminate(false);
|
||||
}
|
||||
|
||||
// invoke the callBack, unless the caller cancelled
|
||||
if (!cancelled) {
|
||||
doCallBack();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the callback with results, new content, and errors, if any
|
||||
*/
|
||||
private void doCallBack()
|
||||
{
|
||||
DSPCallback.DSP_Result result;
|
||||
|
||||
if (hasCritError) {
|
||||
result = DSPCallback.DSP_Result.CRITICAL_ERRORS;
|
||||
}
|
||||
else if (!errorList.isEmpty()) {
|
||||
result = DSPCallback.DSP_Result.NONCRITICAL_ERRORS;
|
||||
}
|
||||
else {
|
||||
result = DSPCallback.DSP_Result.NO_ERRORS;
|
||||
}
|
||||
|
||||
// invoke the callback, passing it the result, list of new contents, and list of errors
|
||||
callbackObj.done(result, errorList, newContents);
|
||||
}
|
||||
|
||||
/*
|
||||
* cancel the files addition, if possible
|
||||
*/
|
||||
public void cancelTask() {
|
||||
cancelled = true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the wizard status with logical file/folder
|
||||
*/
|
||||
private class LocalFilesAddProgressUpdater implements FileManager.FileAddProgressUpdater {
|
||||
|
||||
private int count = 0;
|
||||
private DSPProgressMonitor progressMonitor;
|
||||
|
||||
|
||||
LocalFilesAddProgressUpdater(DSPProgressMonitor progressMonitor) {
|
||||
|
||||
this.progressMonitor = progressMonitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fileAdded(final AbstractFile newFile) {
|
||||
if (count++ % 10 == 0) {
|
||||
progressMonitor.setProgressText("Adding: " + newFile.getParentPath() + "/" + newFile.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,6 @@ ImageFilePanel.browseButton.text=Browse
|
||||
ImageFilePanel.pathTextField.text=
|
||||
LocalDiskPanel.diskLabel.text=Select a local disk:
|
||||
MissingImageDialog.selectButton.text=Select Image
|
||||
MissingImageDialog.typeTabel.text=Select input type to add:
|
||||
MissingImageDialog.titleLabel.text=Search for missing image
|
||||
MissingImageDialog.cancelButton.text=Cancel
|
||||
LocalDiskPanel.errorLabel.text=Error Label
|
||||
@@ -133,18 +132,23 @@ LocalFilesPanel.localFileChooser.approveButtonToolTipText=
|
||||
LocalFilesPanel.selectButton.actionCommand=Add
|
||||
AddImageWizardIngestConfigVisual.subtitleLabel.text=Configure the ingest modules you would like to run on this data source.
|
||||
AddImageWizardIngestConfigVisual.titleLabel.text=Configure Ingest Modules
|
||||
AddImageWizardAddingProgressVisual.statusLabel.text=File system has been added to the local database. Files are being analyzed.
|
||||
AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.toolTipText=
|
||||
AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems
|
||||
AddImageWizardChooseDataSourceVisual.descLabel.text=(faster results, although some data will not be searched)
|
||||
AddImageWizardAddingProgressVisual.statusLabel.text=Data source has been added to the local database. Files are being analyzed.
|
||||
AddImageWizardChooseDataSourceVisual.typeTabel.text=Select source type to add:
|
||||
AddImageWizardChooseDataSourceVisual.jLabel2.text=jLabel2
|
||||
AddImageWizardChooseDataSourceVisual.timeZoneLabel.text=Please select the input timezone:
|
||||
AddImageWizardChooseDataSourceVisual.nextLabel.text=<html> Press 'Next' to analyze the input data, extract volume and file system data, and populate a local database.</html>
|
||||
AddImageWizardChooseDataSourceVisual.imgInfoLabel.text=Enter Data Source Information:
|
||||
AddImageWizardAddingProgressVisual.progressLabel.text=<progress>
|
||||
AddImageWizardAddingProgressVisual.TextArea_CurrentDirectory.border.title=Currently Adding:
|
||||
AddImageWizardAddingProgressVisual.viewLogButton.text=View Log
|
||||
AddImageWizardAddingProgressVisual.titleLabel.text=Adding Data Source
|
||||
AddImageWizardAddingProgressVisual.subTitle1Label.text=File system information is being added to a local database. File analysis will start when this finishes.
|
||||
AddImageWizardAddingProgressVisual.subTitle2Label.text=Processing Data Source and Adding to Database
|
||||
AddImageWizardAddingProgressVisual.subTitle1Label.text=Processing data source and adding it to a local database. File analysis will start when this finishes.
|
||||
ImageFilePanel.timeZoneLabel.text=Please select the input timezone:
|
||||
ImageFilePanel.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems
|
||||
ImageFilePanel.noFatOrphansCheckbox.toolTipText=
|
||||
ImageFilePanel.descLabel.text=(faster results, although some data will not be searched)
|
||||
LocalDiskPanel.timeZoneLabel.text=Please select the input timezone:
|
||||
LocalDiskPanel.noFatOrphansCheckbox.toolTipText=
|
||||
LocalDiskPanel.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems
|
||||
LocalDiskPanel.descLabel.text=(faster results, although some data will not be searched)
|
||||
MissingImageDialog.browseButton.text=Browse
|
||||
MissingImageDialog.pathNameTextField.text=
|
||||
AddImageWizardAddingProgressVisual.progressTextArea.border.title=Status
|
||||
|
||||
@@ -384,7 +384,9 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
+ "\nPlease note that you will still be able to browse directories and generate reports\n"
|
||||
+ "if you choose No, but you will not be able to view file content or run the ingest process.", "Missing Image", JOptionPane.YES_NO_OPTION);
|
||||
if (ret == JOptionPane.YES_OPTION) {
|
||||
|
||||
MissingImageDialog.makeDialog(obj_id, db);
|
||||
|
||||
} else {
|
||||
logger.log(Level.WARNING, "Selected image files don't match old files!");
|
||||
}
|
||||
@@ -401,6 +403,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
* @param imgId the ID of the image that being added
|
||||
* @param timeZone the timeZone of the image where it's added
|
||||
*/
|
||||
@Deprecated
|
||||
public Image addImage(String imgPath, long imgId, String timeZone) throws CaseActionException {
|
||||
logger.log(Level.INFO, "Adding image to Case. imgPath: {0} ID: {1} TimeZone: {2}", new Object[]{imgPath, imgId, timeZone});
|
||||
|
||||
@@ -420,11 +423,23 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
*
|
||||
* @param newDataSource new data source added
|
||||
*/
|
||||
@Deprecated
|
||||
void addLocalDataSource(Content newDataSource) {
|
||||
pcs.firePropertyChange(CASE_ADD_DATA_SOURCE, null, newDataSource);
|
||||
CoreComponentControl.openCoreWindows();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the UI that a new data source has been added.
|
||||
*
|
||||
*
|
||||
* @param newDataSource new data source added
|
||||
*/
|
||||
void notifyNewDataSource(Content newDataSource) {
|
||||
pcs.firePropertyChange(CASE_ADD_DATA_SOURCE, null, newDataSource);
|
||||
CoreComponentControl.openCoreWindows();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The Services object for this case.
|
||||
*/
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012 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.beans.PropertyChangeListener;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
abstract class ContentTypePanel extends JPanel {
|
||||
|
||||
public enum ContentType{IMAGE, DISK, LOCAL};
|
||||
|
||||
/**
|
||||
* Returns a list off all the panels extending ImageTypePanel.
|
||||
* @return list of all ImageTypePanels
|
||||
*/
|
||||
public static ContentTypePanel[] getPanels() {
|
||||
return new ContentTypePanel[] {ImageFilePanel.getDefault(), LocalDiskPanel.getDefault(), LocalFilesPanel.getDefault() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path of the selected content in this panel.
|
||||
* @return paths to selected content (one or more if multiselect supported)
|
||||
*/
|
||||
abstract public String getContentPaths();
|
||||
|
||||
/**
|
||||
* Set the selected content in this panel to the provided path.
|
||||
* This function is optional.
|
||||
* @param s path to selected content
|
||||
*/
|
||||
abstract public void setContentPath(String s);
|
||||
|
||||
/**
|
||||
* Get content type (image, disk, local file) of the source this wizard panel is for
|
||||
* @return ContentType of the source panel
|
||||
*/
|
||||
abstract public ContentType getContentType();
|
||||
|
||||
/**
|
||||
* Returns if the next button should be enabled in the current wizard.
|
||||
* @return true if the next button should be enabled, false otherwise
|
||||
*/
|
||||
abstract public boolean enableNext();
|
||||
|
||||
/**
|
||||
* Tells this panel to reset itself
|
||||
*/
|
||||
abstract public void reset();
|
||||
|
||||
/**
|
||||
* Tells this panel it has been selected.
|
||||
*/
|
||||
abstract public void select();
|
||||
|
||||
|
||||
}
|
||||
@@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
|
||||
/**
|
||||
@@ -28,6 +29,16 @@ import javax.swing.filechooser.FileFilter;
|
||||
*/
|
||||
public class GeneralFilter extends FileFilter{
|
||||
|
||||
|
||||
// Extensions & Descriptions for commonly used filters
|
||||
public static final List<String> RAW_IMAGE_EXTS = Arrays.asList(new String[]{".img", ".dd", ".001", ".aa", ".raw", ".bin"});
|
||||
public static final String RAW_IMAGE_DESC = "Raw Images (*.img, *.dd, *.001, *.aa, *.raw, *.bin)";
|
||||
|
||||
public static final List<String> ENCASE_IMAGE_EXTS = Arrays.asList(new String[]{".e01"});
|
||||
public static final String ENCASE_IMAGE_DESC = "Encase Images (*.e01)";
|
||||
|
||||
|
||||
|
||||
private List<String> extensions;
|
||||
private String desc;
|
||||
|
||||
|
||||
218
Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java
Normal file
218
Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.util.logging.Level;
|
||||
import javax.swing.JPanel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
|
||||
/**
|
||||
* Image data source processor.
|
||||
* Handles the addition of "disk images" to Autopsy.
|
||||
*
|
||||
* An instance of this class is created via the Netbeans Lookup() method.
|
||||
*
|
||||
*/
|
||||
@ServiceProvider(service = DataSourceProcessor.class)
|
||||
public class ImageDSProcessor implements DataSourceProcessor {
|
||||
|
||||
|
||||
|
||||
static final Logger logger = Logger.getLogger(ImageDSProcessor.class.getName());
|
||||
|
||||
// Data source type handled by this processor
|
||||
protected final static String dsType = "Image File";
|
||||
|
||||
// The Config UI panel that plugins into the Choose Data Source Wizard
|
||||
private ImageFilePanel imageFilePanel;
|
||||
|
||||
// The Background task that does the actual work of adding the image
|
||||
private AddImageTask addImageTask;
|
||||
|
||||
// true of cancelled by the caller
|
||||
private boolean cancelled = false;
|
||||
|
||||
DSPCallback callbackObj = null;
|
||||
|
||||
// set to TRUE if the image options have been set via API and config Jpanel should be ignored
|
||||
private boolean imageOptionsSet = false;
|
||||
|
||||
// image options
|
||||
private String imagePath;
|
||||
private String timeZone;
|
||||
private boolean noFatOrphans;
|
||||
|
||||
|
||||
|
||||
|
||||
static final GeneralFilter rawFilter = new GeneralFilter(GeneralFilter.RAW_IMAGE_EXTS, GeneralFilter.RAW_IMAGE_DESC);
|
||||
static final GeneralFilter encaseFilter = new GeneralFilter(GeneralFilter.ENCASE_IMAGE_EXTS, GeneralFilter.ENCASE_IMAGE_DESC);
|
||||
|
||||
static final List<String> allExt = new ArrayList<String>();
|
||||
static {
|
||||
allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS);
|
||||
allExt.addAll(GeneralFilter.ENCASE_IMAGE_EXTS);
|
||||
}
|
||||
static final String allDesc = "All Supported Types";
|
||||
static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc);
|
||||
|
||||
static final List<FileFilter> filtersList = new ArrayList<FileFilter>();
|
||||
|
||||
static {
|
||||
filtersList.add(allFilter);
|
||||
filtersList.add(rawFilter);
|
||||
filtersList.add(encaseFilter);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A no argument constructor is required for the NM lookup() method to create an object
|
||||
*/
|
||||
public ImageDSProcessor() {
|
||||
|
||||
// Create the config panel
|
||||
imageFilePanel = ImageFilePanel.createInstance(ImageDSProcessor.class.getName(), filtersList);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Data source type (string) handled by this DSP
|
||||
*
|
||||
* @return String the data source type
|
||||
**/
|
||||
@Override
|
||||
public String getType() {
|
||||
return dsType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JPanel for collecting the Data source information
|
||||
*
|
||||
* @return JPanel the config panel
|
||||
**/
|
||||
@Override
|
||||
public JPanel getPanel() {
|
||||
|
||||
|
||||
imageFilePanel.readSettings();
|
||||
imageFilePanel.select();
|
||||
|
||||
return imageFilePanel;
|
||||
}
|
||||
/**
|
||||
* Validates the data collected by the JPanel
|
||||
*
|
||||
* @return String returns NULL if success, error string if there is any errors
|
||||
**/
|
||||
@Override
|
||||
public boolean validatePanel() {
|
||||
|
||||
return imageFilePanel.validatePanel();
|
||||
}
|
||||
/**
|
||||
* Runs the data source processor.
|
||||
* This must kick off processing the data source in background
|
||||
*
|
||||
* @param progressMonitor Progress monitor to report progress during processing
|
||||
* @param cbObj callback to call when processing is done.
|
||||
**/
|
||||
@Override
|
||||
public void run(DSPProgressMonitor progressMonitor, DSPCallback cbObj) {
|
||||
|
||||
callbackObj = cbObj;
|
||||
cancelled = false;
|
||||
|
||||
if (!imageOptionsSet)
|
||||
{
|
||||
//tell the panel to save the current settings
|
||||
imageFilePanel.storeSettings();
|
||||
|
||||
// get the image options from the panel
|
||||
imagePath = imageFilePanel.getContentPaths();
|
||||
timeZone = imageFilePanel.getTimeZone();
|
||||
noFatOrphans = imageFilePanel.getNoFatOrphans();
|
||||
}
|
||||
|
||||
addImageTask = new AddImageTask(imagePath, timeZone, noFatOrphans, progressMonitor, cbObj);
|
||||
new Thread(addImageTask).start();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the data source processing
|
||||
**/
|
||||
@Override
|
||||
public void cancel() {
|
||||
|
||||
cancelled = true;
|
||||
|
||||
addImageTask.cancelTask();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the data source processor
|
||||
**/
|
||||
@Override
|
||||
public void reset() {
|
||||
|
||||
// reset the config panel
|
||||
imageFilePanel.reset();
|
||||
|
||||
// reset state
|
||||
imageOptionsSet = false;
|
||||
imagePath = null;
|
||||
timeZone = null;
|
||||
noFatOrphans = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data source options externally.
|
||||
* To be used by a client that does not have a UI and does not use the JPanel to
|
||||
* collect this information from a user.
|
||||
*
|
||||
* @param imgPath path to thew image or first image
|
||||
* @param String timeZone
|
||||
* @param noFat whether to parse FAT orphans
|
||||
**/
|
||||
public void setDataSourceOptions(String imgPath, String tz, boolean noFat) {
|
||||
|
||||
this.imagePath = imgPath;
|
||||
this.timeZone = tz;
|
||||
this.noFatOrphans = noFat;
|
||||
|
||||
imageOptionsSet = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -31,8 +31,20 @@
|
||||
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="pathLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="284" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="timeZoneLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="timeZoneComboBox" min="-2" pref="215" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="pathLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="noFatOrphansCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
|
||||
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="20" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@@ -45,6 +57,16 @@
|
||||
<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"/>
|
||||
<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"/>
|
||||
</Group>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@@ -74,5 +96,40 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="timeZoneLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.timeZoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="timeZoneComboBox">
|
||||
<Properties>
|
||||
<Property name="maximumRowCount" type="int" value="30"/>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="0"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="noFatOrphansCheckbox">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.noFatOrphansCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.noFatOrphansCheckbox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="descLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="ImageFilePanel.descLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
||||
@@ -22,41 +22,71 @@ import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.SimpleTimeZone;
|
||||
import java.util.TimeZone;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
|
||||
|
||||
/**
|
||||
* ImageTypePanel for adding an image file such as .img, .E0x, .00x, etc.
|
||||
*/
|
||||
public class ImageFilePanel extends ContentTypePanel implements DocumentListener {
|
||||
private static ImageFilePanel instance = null;
|
||||
public class ImageFilePanel extends JPanel implements DocumentListener {
|
||||
|
||||
private final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH";
|
||||
|
||||
private PropertyChangeSupport pcs = null;
|
||||
private JFileChooser fc = new JFileChooser();
|
||||
|
||||
// Externally supplied name is used to store settings
|
||||
private String contextName;
|
||||
|
||||
/**
|
||||
* Creates new form ImageFilePanel
|
||||
* @param context a string context name used to read/store last used settings
|
||||
* @param fileChooserFilters a list of filters to be used with the FileChooser
|
||||
*/
|
||||
public ImageFilePanel() {
|
||||
private ImageFilePanel(String context, List<FileFilter> fileChooserFilters) {
|
||||
initComponents();
|
||||
fc.setDragEnabled(false);
|
||||
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
fc.setMultiSelectionEnabled(false);
|
||||
fc.addChoosableFileFilter(AddImageWizardChooseDataSourceVisual.rawFilter);
|
||||
fc.addChoosableFileFilter(AddImageWizardChooseDataSourceVisual.encaseFilter);
|
||||
fc.setFileFilter(AddImageWizardChooseDataSourceVisual.allFilter);
|
||||
|
||||
boolean firstFilter = true;
|
||||
for (FileFilter filter: fileChooserFilters ) {
|
||||
if (firstFilter) { // set the first on the list as the default selection
|
||||
fc.setFileFilter(filter);
|
||||
firstFilter = false;
|
||||
}
|
||||
else {
|
||||
fc.addChoosableFileFilter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
this.contextName = context;
|
||||
pcs = new PropertyChangeSupport(this);
|
||||
|
||||
createTimeZoneList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default instance of a ImageFilePanel.
|
||||
* Creates and returns an instance of a ImageFilePanel.
|
||||
*/
|
||||
public static synchronized ImageFilePanel getDefault() {
|
||||
if (instance == null) {
|
||||
instance = new ImageFilePanel();
|
||||
instance.postInit();
|
||||
}
|
||||
return instance;
|
||||
public static synchronized ImageFilePanel createInstance(String context, List<FileFilter> fileChooserFilters) {
|
||||
|
||||
ImageFilePanel instance = new ImageFilePanel(context, fileChooserFilters );
|
||||
|
||||
instance.postInit();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
//post-constructor initialization to properly initialize listener support
|
||||
@@ -79,6 +109,10 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
|
||||
pathLabel = new javax.swing.JLabel();
|
||||
browseButton = new javax.swing.JButton();
|
||||
pathTextField = new javax.swing.JTextField();
|
||||
timeZoneLabel = new javax.swing.JLabel();
|
||||
timeZoneComboBox = new javax.swing.JComboBox<String>();
|
||||
noFatOrphansCheckbox = new javax.swing.JCheckBox();
|
||||
descLabel = new javax.swing.JLabel();
|
||||
|
||||
setMinimumSize(new java.awt.Dimension(0, 65));
|
||||
setPreferredSize(new java.awt.Dimension(403, 65));
|
||||
@@ -94,6 +128,15 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
|
||||
|
||||
pathTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.pathTextField.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.timeZoneLabel.text")); // NOI18N
|
||||
|
||||
timeZoneComboBox.setMaximumRowCount(30);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.noFatOrphansCheckbox.text")); // NOI18N
|
||||
noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.noFatOrphansCheckbox.toolTipText")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.descLabel.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
@@ -104,8 +147,17 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
|
||||
.addComponent(browseButton)
|
||||
.addGap(2, 2, 2))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(pathLabel)
|
||||
.addGap(0, 284, Short.MAX_VALUE))
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(timeZoneLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addComponent(pathLabel)
|
||||
.addComponent(noFatOrphansCheckbox)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(21, 21, 21)
|
||||
.addComponent(descLabel)))
|
||||
.addGap(0, 20, Short.MAX_VALUE))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
@@ -114,7 +166,16 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.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)))
|
||||
.addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGap(18, 18, 18)
|
||||
.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))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(noFatOrphansCheckbox)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(descLabel)
|
||||
.addContainerGap(33, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
@@ -131,20 +192,23 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
|
||||
String path = fc.getSelectedFile().getPath();
|
||||
pathTextField.setText(path);
|
||||
}
|
||||
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.FOCUS_NEXT.toString(), false, true);
|
||||
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString(), false, true);
|
||||
}//GEN-LAST:event_browseButtonActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton browseButton;
|
||||
private javax.swing.JLabel descLabel;
|
||||
private javax.swing.JCheckBox noFatOrphansCheckbox;
|
||||
private javax.swing.JLabel pathLabel;
|
||||
private javax.swing.JTextField pathTextField;
|
||||
private javax.swing.JComboBox<String> timeZoneComboBox;
|
||||
private javax.swing.JLabel timeZoneLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
/**
|
||||
* Get the path of the user selected image.
|
||||
* @return the image path
|
||||
*/
|
||||
@Override
|
||||
public String getContentPaths() {
|
||||
return pathTextField.getText();
|
||||
}
|
||||
@@ -152,33 +216,37 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
|
||||
/**
|
||||
* Set the path of the image file.
|
||||
*/
|
||||
@Override
|
||||
public void setContentPath(String s) {
|
||||
pathTextField.setText(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getContentType() {
|
||||
return ContentType.IMAGE;
|
||||
public String getTimeZone() {
|
||||
String tz = timeZoneComboBox.getSelectedItem().toString();
|
||||
return tz.substring(tz.indexOf(")") + 2).trim();
|
||||
|
||||
}
|
||||
|
||||
public boolean getNoFatOrphans() {
|
||||
return noFatOrphansCheckbox.isSelected();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
//nothing to reset
|
||||
//reset the UI elements to default
|
||||
pathTextField.setText(null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Should we enable the next button of the wizard?
|
||||
* @return true if a proper image has been selected, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean enableNext() {
|
||||
public boolean validatePanel() {
|
||||
String path = getContentPaths();
|
||||
if (path == null || path.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isExist = Case.pathExists(path);
|
||||
boolean isPhysicalDrive = Case.isPhysicalDrive(path);
|
||||
boolean isPartition = Case.isPartition(path);
|
||||
@@ -186,6 +254,57 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
|
||||
return (isExist || isPhysicalDrive || isPartition);
|
||||
}
|
||||
|
||||
|
||||
public void storeSettings() {
|
||||
String imagePathName = getContentPaths();
|
||||
if (null != imagePathName ) {
|
||||
String imagePath = imagePathName.substring(0, imagePathName.lastIndexOf(File.separator) + 1);
|
||||
ModuleSettings.setConfigSetting(contextName, PROP_LASTIMAGE_PATH, imagePath);
|
||||
}
|
||||
}
|
||||
|
||||
public void readSettings() {
|
||||
String lastImagePath = ModuleSettings.getConfigSetting(contextName, PROP_LASTIMAGE_PATH);
|
||||
if (null != lastImagePath) {
|
||||
if (!lastImagePath.isEmpty())
|
||||
pathTextField.setText(lastImagePath);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates the drop down list for the time zones and then makes the local
|
||||
* machine time zone to be selected.
|
||||
*/
|
||||
public void createTimeZoneList() {
|
||||
// load and add all timezone
|
||||
String[] ids = SimpleTimeZone.getAvailableIDs();
|
||||
for (String id : ids) {
|
||||
TimeZone zone = TimeZone.getTimeZone(id);
|
||||
int offset = zone.getRawOffset() / 1000;
|
||||
int hour = offset / 3600;
|
||||
int minutes = (offset % 3600) / 60;
|
||||
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
|
||||
|
||||
/*
|
||||
* DateFormat dfm = new SimpleDateFormat("z");
|
||||
* dfm.setTimeZone(zone); boolean hasDaylight =
|
||||
* zone.useDaylightTime(); String first = dfm.format(new Date(2010,
|
||||
* 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid
|
||||
* = hour * -1; String result = first + Integer.toString(mid);
|
||||
* if(hasDaylight){ result = result + second; }
|
||||
* timeZoneComboBox.addItem(item + " (" + result + ")");
|
||||
*/
|
||||
timeZoneComboBox.addItem(item);
|
||||
}
|
||||
// get the current timezone
|
||||
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
|
||||
int thisOffset = thisTimeZone.getRawOffset() / 1000;
|
||||
int thisHour = thisOffset / 3600;
|
||||
int thisMinutes = (thisOffset % 3600) / 60;
|
||||
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
|
||||
|
||||
// set the selected timezone
|
||||
timeZoneComboBox.setSelectedItem(formatted);
|
||||
}
|
||||
/**
|
||||
* Update functions are called by the pathTextField which has this set
|
||||
* as it's DocumentEventListener. Each update function fires a property change
|
||||
@@ -194,34 +313,26 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener
|
||||
*/
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
|
||||
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
|
||||
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
|
||||
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the focus to the pathTextField.
|
||||
*/
|
||||
@Override
|
||||
public void select() {
|
||||
pathTextField.requestFocusInWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the string form of this panel
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Image File";
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addPropertyChangeListener(PropertyChangeListener pcl) {
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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 javax.swing.JPanel;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
|
||||
@ServiceProvider(service = DataSourceProcessor.class)
|
||||
public class LocalDiskDSProcessor implements DataSourceProcessor {
|
||||
|
||||
static final Logger logger = Logger.getLogger(ImageDSProcessor.class.getName());
|
||||
|
||||
// Data source type handled by this processor
|
||||
static protected final String dsType = "Local Disk";
|
||||
|
||||
// The Config UI panel that plugins into the Choose Data Source Wizard
|
||||
private LocalDiskPanel localDiskPanel;
|
||||
|
||||
// The Background task that does the actual work of adding the local Disk
|
||||
// Adding a local disk is exactly same as adding an Image.
|
||||
private AddImageTask addDiskTask;
|
||||
|
||||
// true if cancelled by the caller
|
||||
private boolean cancelled = false;
|
||||
|
||||
DSPCallback callbackObj = null;
|
||||
|
||||
// set to TRUE if the image options have been set via API and config Jpanel should be ignored
|
||||
private boolean localDiskOptionsSet = false;
|
||||
|
||||
// data source options
|
||||
private String localDiskPath;
|
||||
private String timeZone;
|
||||
private boolean noFatOrphans;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* A no argument constructor is required for the NM lookup() method to create an object
|
||||
*/
|
||||
public LocalDiskDSProcessor() {
|
||||
|
||||
// Create the config panel
|
||||
localDiskPanel = LocalDiskPanel.getDefault();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Data source type (string) handled by this DSP
|
||||
*
|
||||
* @return String the data source type
|
||||
**/
|
||||
@Override
|
||||
public String getType() {
|
||||
return dsType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JPanel for collecting the Data source information
|
||||
*
|
||||
* @return JPanel the config panel
|
||||
**/
|
||||
@Override
|
||||
public JPanel getPanel() {
|
||||
|
||||
localDiskPanel.select();
|
||||
return localDiskPanel;
|
||||
}
|
||||
/**
|
||||
* Validates the data collected by the JPanel
|
||||
*
|
||||
* @return String returns NULL if success, error string if there is any errors
|
||||
**/
|
||||
@Override
|
||||
public boolean validatePanel() {
|
||||
return localDiskPanel.validatePanel();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Runs the data source processor.
|
||||
* This must kick off processing the data source in background
|
||||
*
|
||||
* @param progressMonitor Progress monitor to report progress during processing
|
||||
* @param cbObj callback to call when processing is done.
|
||||
**/
|
||||
@Override
|
||||
public void run(DSPProgressMonitor progressMonitor, DSPCallback cbObj) {
|
||||
|
||||
callbackObj = cbObj;
|
||||
cancelled = false;
|
||||
|
||||
if (!localDiskOptionsSet) {
|
||||
// get the image options from the panel
|
||||
localDiskPath = localDiskPanel.getContentPaths();
|
||||
timeZone = localDiskPanel.getTimeZone();
|
||||
noFatOrphans = localDiskPanel.getNoFatOrphans();
|
||||
}
|
||||
|
||||
addDiskTask = new AddImageTask(localDiskPath, timeZone, noFatOrphans, progressMonitor, cbObj);
|
||||
new Thread(addDiskTask).start();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Cancel the data source processing
|
||||
**/
|
||||
@Override
|
||||
public void cancel() {
|
||||
|
||||
cancelled = true;
|
||||
|
||||
addDiskTask.cancelTask();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the data source processor
|
||||
**/
|
||||
@Override
|
||||
public void reset() {
|
||||
|
||||
// reset the config panel
|
||||
localDiskPanel.reset();
|
||||
|
||||
// reset state
|
||||
localDiskOptionsSet = false;
|
||||
localDiskPath = null;
|
||||
timeZone = null;
|
||||
noFatOrphans = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data source options externally.
|
||||
* To be used by a client that does not have a UI and does not use the JPanel to
|
||||
* collect this information from a user.
|
||||
*
|
||||
* @param diskPath path to the local disk
|
||||
* @param String timeZone
|
||||
* @param noFat whether to parse FAT orphans
|
||||
**/
|
||||
public void setDataSourceOptions(String diskPath, String tz, boolean noFat) {
|
||||
|
||||
this.localDiskPath = diskPath;
|
||||
this.timeZone = tz;
|
||||
this.noFatOrphans = noFat;
|
||||
|
||||
localDiskOptionsSet = true;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -29,8 +29,18 @@
|
||||
<Component id="diskLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="diskComboBox" min="-2" pref="345" max="-2" attributes="0"/>
|
||||
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="timeZoneLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="timeZoneComboBox" min="-2" pref="215" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
|
||||
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="140" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="102" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@@ -40,8 +50,18 @@
|
||||
<Component id="diskLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="diskComboBox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="13" max="-2" attributes="0"/>
|
||||
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" 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"/>
|
||||
</Group>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="noFatOrphansCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="descLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@@ -71,5 +91,40 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="timeZoneLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.timeZoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="timeZoneComboBox">
|
||||
<Properties>
|
||||
<Property name="maximumRowCount" type="int" value="30"/>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="0"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="noFatOrphansCheckbox">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.noFatOrphansCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.noFatOrphansCheckbox.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="descLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="LocalDiskPanel.descLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
||||
@@ -25,7 +25,10 @@ import java.awt.Font;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.SimpleTimeZone;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.ComboBoxModel;
|
||||
@@ -37,13 +40,16 @@ import javax.swing.ListCellRenderer;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.ListDataListener;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
|
||||
/**
|
||||
* ImageTypePanel for adding a local disk or partition such as PhysicalDrive0 or C:.
|
||||
*/
|
||||
public class LocalDiskPanel extends ContentTypePanel {
|
||||
public class LocalDiskPanel extends JPanel {
|
||||
private static final Logger logger = Logger.getLogger(LocalDiskPanel.class.getName());
|
||||
|
||||
private static LocalDiskPanel instance;
|
||||
private PropertyChangeSupport pcs = null;
|
||||
private List<LocalDisk> disks = new ArrayList<LocalDisk>();
|
||||
@@ -56,6 +62,9 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
public LocalDiskPanel() {
|
||||
initComponents();
|
||||
customInit();
|
||||
|
||||
createTimeZoneList();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,8 +82,10 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
model = new LocalDiskModel();
|
||||
diskComboBox.setModel(model);
|
||||
diskComboBox.setRenderer(model);
|
||||
|
||||
errorLabel.setText("");
|
||||
diskComboBox.setEnabled(false);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,6 +100,10 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
diskLabel = new javax.swing.JLabel();
|
||||
diskComboBox = new javax.swing.JComboBox();
|
||||
errorLabel = new javax.swing.JLabel();
|
||||
timeZoneLabel = new javax.swing.JLabel();
|
||||
timeZoneComboBox = new javax.swing.JComboBox<String>();
|
||||
noFatOrphansCheckbox = new javax.swing.JCheckBox();
|
||||
descLabel = new javax.swing.JLabel();
|
||||
|
||||
setMinimumSize(new java.awt.Dimension(0, 65));
|
||||
setPreferredSize(new java.awt.Dimension(485, 65));
|
||||
@@ -98,6 +113,15 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
errorLabel.setForeground(new java.awt.Color(255, 0, 0));
|
||||
org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.errorLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.timeZoneLabel.text")); // NOI18N
|
||||
|
||||
timeZoneComboBox.setMaximumRowCount(30);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.noFatOrphansCheckbox.text")); // NOI18N
|
||||
noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.noFatOrphansCheckbox.toolTipText")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.descLabel.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
@@ -106,8 +130,16 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(diskLabel)
|
||||
.addComponent(diskComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 345, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(errorLabel))
|
||||
.addGap(0, 140, Short.MAX_VALUE))
|
||||
.addComponent(errorLabel)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(timeZoneLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addComponent(noFatOrphansCheckbox)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(21, 21, 21)
|
||||
.addComponent(descLabel)))
|
||||
.addGap(0, 102, Short.MAX_VALUE))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
@@ -115,21 +147,34 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
.addComponent(diskLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(diskComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(13, 13, 13)
|
||||
.addComponent(errorLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.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))
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(noFatOrphansCheckbox)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(errorLabel))
|
||||
.addComponent(descLabel)
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JLabel descLabel;
|
||||
private javax.swing.JComboBox diskComboBox;
|
||||
private javax.swing.JLabel diskLabel;
|
||||
private javax.swing.JLabel errorLabel;
|
||||
private javax.swing.JCheckBox noFatOrphansCheckbox;
|
||||
private javax.swing.JComboBox<String> timeZoneComboBox;
|
||||
private javax.swing.JLabel timeZoneLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
/**
|
||||
* Return the currently selected disk path.
|
||||
* @return String selected disk path
|
||||
*/
|
||||
@Override
|
||||
//@Override
|
||||
public String getContentPaths() {
|
||||
if(disks.size() > 0) {
|
||||
LocalDisk selected = (LocalDisk) diskComboBox.getSelectedItem();
|
||||
@@ -143,7 +188,7 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
/**
|
||||
* Set the selected disk.
|
||||
*/
|
||||
@Override
|
||||
// @Override
|
||||
public void setContentPath(String s) {
|
||||
for(int i=0; i<disks.size(); i++) {
|
||||
if(disks.get(i).getPath().equals(s)) {
|
||||
@@ -152,9 +197,14 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getContentType() {
|
||||
return ContentType.DISK;
|
||||
public String getTimeZone() {
|
||||
String tz = timeZoneComboBox.getSelectedItem().toString();
|
||||
return tz.substring(tz.indexOf(")") + 2).trim();
|
||||
|
||||
}
|
||||
|
||||
boolean getNoFatOrphans() {
|
||||
return noFatOrphansCheckbox.isSelected();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,31 +212,27 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
* Always return true because we control the possible selections.
|
||||
* @return true
|
||||
*/
|
||||
@Override
|
||||
public boolean enableNext() {
|
||||
//@Override
|
||||
public boolean validatePanel() {
|
||||
return enableNext;
|
||||
}
|
||||
|
||||
@Override
|
||||
//@Override
|
||||
public void reset() {
|
||||
//nothing to reset
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the representation of this panel as a String.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Local Disk";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the focus to the diskComboBox and refreshes the list of disks.
|
||||
*/
|
||||
@Override
|
||||
// @Override
|
||||
public void select() {
|
||||
diskComboBox.requestFocusInWindow();
|
||||
model.loadDisks();
|
||||
model.loadDisks();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -207,16 +253,61 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
pcs.removePropertyChangeListener(pcl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the drop down list for the time zones and then makes the local
|
||||
* machine time zone to be selected.
|
||||
*/
|
||||
public void createTimeZoneList() {
|
||||
// load and add all timezone
|
||||
String[] ids = SimpleTimeZone.getAvailableIDs();
|
||||
for (String id : ids) {
|
||||
TimeZone zone = TimeZone.getTimeZone(id);
|
||||
int offset = zone.getRawOffset() / 1000;
|
||||
int hour = offset / 3600;
|
||||
int minutes = (offset % 3600) / 60;
|
||||
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
|
||||
|
||||
/*
|
||||
* DateFormat dfm = new SimpleDateFormat("z");
|
||||
* dfm.setTimeZone(zone); boolean hasDaylight =
|
||||
* zone.useDaylightTime(); String first = dfm.format(new Date(2010,
|
||||
* 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid
|
||||
* = hour * -1; String result = first + Integer.toString(mid);
|
||||
* if(hasDaylight){ result = result + second; }
|
||||
* timeZoneComboBox.addItem(item + " (" + result + ")");
|
||||
*/
|
||||
timeZoneComboBox.addItem(item);
|
||||
}
|
||||
// get the current timezone
|
||||
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
|
||||
int thisOffset = thisTimeZone.getRawOffset() / 1000;
|
||||
int thisHour = thisOffset / 3600;
|
||||
int thisMinutes = (thisOffset % 3600) / 60;
|
||||
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
|
||||
|
||||
// set the selected timezone
|
||||
timeZoneComboBox.setSelectedItem(formatted);
|
||||
}
|
||||
|
||||
private class LocalDiskModel implements ComboBoxModel, ListCellRenderer {
|
||||
private Object selected;
|
||||
private boolean ready = false;
|
||||
private volatile boolean loadingDisks = false;
|
||||
List<LocalDisk> physical = new ArrayList<LocalDisk>();
|
||||
List<LocalDisk> partitions = new ArrayList<LocalDisk>();
|
||||
|
||||
//private String SELECT = "Select a local disk:";
|
||||
private String LOADING = "Loading local disks...";
|
||||
LocalDiskThread worker = null;
|
||||
|
||||
|
||||
private void loadDisks() {
|
||||
|
||||
// if there is a worker already building the lists, then cancel it first.
|
||||
if (loadingDisks && worker != null) {
|
||||
worker.cancel(false);
|
||||
}
|
||||
|
||||
// Clear the lists
|
||||
errorLabel.setText("");
|
||||
disks = new ArrayList<LocalDisk>();
|
||||
@@ -224,9 +315,13 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
partitions = new ArrayList<LocalDisk>();
|
||||
diskComboBox.setEnabled(false);
|
||||
ready = false;
|
||||
|
||||
LocalDiskThread worker = new LocalDiskThread();
|
||||
enableNext = false;
|
||||
loadingDisks = true;
|
||||
|
||||
worker = new LocalDiskThread();
|
||||
worker.execute();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -234,7 +329,7 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
if(ready) {
|
||||
selected = anItem;
|
||||
enableNext = true;
|
||||
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
|
||||
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,7 +355,7 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
@Override
|
||||
public void removeListDataListener(ListDataListener l) {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
@@ -300,8 +395,6 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
// Populate the lists
|
||||
physical = PlatformUtil.getPhysicalDrives();
|
||||
partitions = PlatformUtil.getPartitions();
|
||||
disks.addAll(physical);
|
||||
disks.addAll(partitions);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -337,6 +430,11 @@ public class LocalDiskPanel extends ContentTypePanel {
|
||||
enableNext = false;
|
||||
displayErrors();
|
||||
ready = true;
|
||||
worker = null;
|
||||
loadingDisks = false;
|
||||
|
||||
disks.addAll(physical);
|
||||
disks.addAll(partitions);
|
||||
|
||||
if(disks.size() > 0) {
|
||||
diskComboBox.setEnabled(true);
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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 javax.swing.JPanel;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
@ServiceProvider(service = DataSourceProcessor.class)
|
||||
public class LocalFilesDSProcessor implements DataSourceProcessor {
|
||||
|
||||
static final Logger logger = Logger.getLogger(LocalFilesDSProcessor.class.getName());
|
||||
|
||||
// Data source type handled by this processor
|
||||
protected static final String dsType = "Logical Files";
|
||||
|
||||
// The Config UI panel that plugins into the Choose Data Source Wizard
|
||||
private LocalFilesPanel localFilesPanel;
|
||||
|
||||
// The Background task that does the actual work of adding the files
|
||||
private AddLocalFilesTask addFilesTask;
|
||||
|
||||
// true if cancelled by the caller
|
||||
private boolean cancelled = false;
|
||||
|
||||
DSPCallback callbackObj = null;
|
||||
|
||||
// set to TRUE if the image options have been set via API and config Jpanel should be ignored
|
||||
private boolean localFilesOptionsSet = false;
|
||||
|
||||
// data source options
|
||||
private String localFilesPath;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* A no argument constructor is required for the NM lookup() method to create an object
|
||||
*/
|
||||
public LocalFilesDSProcessor() {
|
||||
|
||||
// Create the config panel
|
||||
localFilesPanel = LocalFilesPanel.getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Data source type (string) handled by this DSP
|
||||
*
|
||||
* @return String the data source type
|
||||
**/
|
||||
@Override
|
||||
public String getType() {
|
||||
return dsType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JPanel for collecting the Data source information
|
||||
*
|
||||
* @return JPanel the config panel
|
||||
**/
|
||||
@Override
|
||||
public JPanel getPanel() {
|
||||
localFilesPanel.select();
|
||||
return localFilesPanel;
|
||||
}
|
||||
/**
|
||||
* Validates the data collected by the JPanel
|
||||
*
|
||||
* @return String returns NULL if success, error string if there is any errors
|
||||
**/
|
||||
@Override
|
||||
public boolean validatePanel() {
|
||||
return localFilesPanel.validatePanel();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Runs the data source processor.
|
||||
* This must kick off processing the data source in background
|
||||
*
|
||||
* @param progressMonitor Progress monitor to report progress during processing
|
||||
* @param cbObj callback to call when processing is done.
|
||||
**/
|
||||
@Override
|
||||
public void run(DSPProgressMonitor progressMonitor, DSPCallback cbObj) {
|
||||
|
||||
callbackObj = cbObj;
|
||||
cancelled = false;
|
||||
|
||||
if (!localFilesOptionsSet) {
|
||||
// get the selected file paths from the panel
|
||||
localFilesPath = localFilesPanel.getContentPaths();
|
||||
}
|
||||
|
||||
addFilesTask = new AddLocalFilesTask(localFilesPath, progressMonitor, cbObj);
|
||||
new Thread(addFilesTask).start();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the data source processing
|
||||
**/
|
||||
@Override
|
||||
public void cancel() {
|
||||
|
||||
cancelled = true;
|
||||
addFilesTask.cancelTask();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the data source processor
|
||||
**/
|
||||
@Override
|
||||
public void reset() {
|
||||
|
||||
// reset the config panel
|
||||
localFilesPanel.reset();
|
||||
|
||||
// reset state
|
||||
localFilesOptionsSet = false;
|
||||
localFilesPath = null;
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data source options externally.
|
||||
* To be used by a client that does not have a UI and does not use the JPanel to
|
||||
* collect this information from a user.
|
||||
*
|
||||
* @param filesPath PATH_SEP list of paths to local files
|
||||
*
|
||||
**/
|
||||
public void setDataSourceOptions(String filesPath) {
|
||||
|
||||
this.localFilesPath = filesPath;
|
||||
|
||||
localFilesOptionsSet = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -24,11 +24,13 @@ import java.io.File;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JPanel;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
|
||||
/**
|
||||
* Add input wizard subpanel for adding local files / dirs to the case
|
||||
*/
|
||||
public class LocalFilesPanel extends ContentTypePanel {
|
||||
public class LocalFilesPanel extends JPanel {
|
||||
|
||||
private PropertyChangeSupport pcs = null;
|
||||
private Set<File> currentFiles = new TreeSet<File>(); //keep currents in a set to disallow duplicates per add
|
||||
@@ -57,7 +59,7 @@ public class LocalFilesPanel extends ContentTypePanel {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
//@Override
|
||||
public String getContentPaths() {
|
||||
//TODO consider interface change to return list of paths instead
|
||||
|
||||
@@ -72,36 +74,37 @@ public class LocalFilesPanel extends ContentTypePanel {
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
//@Override
|
||||
public void setContentPath(String s) {
|
||||
//for the local file panel we don't need to restore the last paths used
|
||||
//when the wizard restarts
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getContentType() {
|
||||
return ContentType.LOCAL;
|
||||
//@Override
|
||||
public String getContentType() {
|
||||
return "LOCAL";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enableNext() {
|
||||
//@Override
|
||||
public boolean validatePanel() {
|
||||
return enableNext;
|
||||
}
|
||||
|
||||
@Override
|
||||
//@Override
|
||||
public void select() {
|
||||
reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
//@Override
|
||||
public void reset() {
|
||||
currentFiles.clear();
|
||||
selectedPaths.setText("");
|
||||
enableNext = false;
|
||||
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
|
||||
|
||||
//pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public synchronized void addPropertyChangeListener(PropertyChangeListener pcl) {
|
||||
super.addPropertyChangeListener(pcl);
|
||||
|
||||
@@ -231,7 +234,7 @@ public class LocalFilesPanel extends ContentTypePanel {
|
||||
else {
|
||||
enableNext = false;
|
||||
}
|
||||
pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true);
|
||||
pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
|
||||
}//GEN-LAST:event_selectButtonActionPerformed
|
||||
|
||||
private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed
|
||||
|
||||
@@ -110,65 +110,49 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="typePanel" max="32767" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="typeTabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="typeComboBox" pref="298" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<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>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="typeTabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="typeComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="pathNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="typePanel" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<EmptySpace pref="62" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JComboBox" name="typeComboBox">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="0"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="typeTabel">
|
||||
<Component class="javax.swing.JTextField" name="pathNameTextField">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MissingImageDialog.typeTabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MissingImageDialog.pathNameTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pathNameTextFieldActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="browseButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MissingImageDialog.browseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="typePanel">
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="57" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="javax.swing.JLabel" name="titleLabel">
|
||||
|
||||
@@ -18,49 +18,71 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.ComboBoxModel;
|
||||
import javax.swing.JDialog;
|
||||
import java.io.File;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.event.ListDataListener;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
|
||||
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
|
||||
|
||||
public class MissingImageDialog extends javax.swing.JDialog {
|
||||
private static final Logger logger = Logger.getLogger(MissingImageDialog.class.getName());
|
||||
long obj_id;
|
||||
SleuthkitCase db;
|
||||
ContentTypePanel currentPanel;
|
||||
ImageTypeModel model;
|
||||
|
||||
|
||||
|
||||
static final GeneralFilter rawFilter = new GeneralFilter(GeneralFilter.RAW_IMAGE_EXTS, GeneralFilter.RAW_IMAGE_DESC);
|
||||
static final GeneralFilter encaseFilter = new GeneralFilter(GeneralFilter.ENCASE_IMAGE_EXTS, GeneralFilter.ENCASE_IMAGE_DESC);
|
||||
|
||||
static final List<String> allExt = new ArrayList<String>();
|
||||
static {
|
||||
allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS);
|
||||
allExt.addAll(GeneralFilter.ENCASE_IMAGE_EXTS);
|
||||
}
|
||||
static final String allDesc = "All Supported Types";
|
||||
static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc);
|
||||
|
||||
private JFileChooser fc = new JFileChooser();
|
||||
|
||||
private MissingImageDialog(long obj_id, SleuthkitCase db) {
|
||||
super(new JFrame(), true);
|
||||
this.obj_id = obj_id;
|
||||
this.db = db;
|
||||
initComponents();
|
||||
|
||||
fc.setDragEnabled(false);
|
||||
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
fc.setMultiSelectionEnabled(false);
|
||||
|
||||
fc.addChoosableFileFilter(rawFilter);
|
||||
fc.addChoosableFileFilter(encaseFilter);
|
||||
fc.setFileFilter(allFilter);
|
||||
|
||||
|
||||
customInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Client call to create a MissingImageDialog.
|
||||
*
|
||||
* @param obj_id obj_id of the missing image
|
||||
* @param db the current SleuthkitCase connected to a db
|
||||
*/
|
||||
//
|
||||
// * Client call to create a MissingImageDialog.
|
||||
// *
|
||||
// * @param obj_id obj_id of the missing image
|
||||
// * @param db the current SleuthkitCase connected to a db
|
||||
//
|
||||
static void makeDialog(long obj_id, SleuthkitCase db) {
|
||||
final MissingImageDialog dialog = new MissingImageDialog(obj_id, db);
|
||||
dialog.addWindowListener(new WindowAdapter() {
|
||||
@@ -73,11 +95,8 @@ public class MissingImageDialog extends javax.swing.JDialog {
|
||||
}
|
||||
|
||||
private void customInit() {
|
||||
model = new ImageTypeModel();
|
||||
typeComboBox.setModel(model);
|
||||
typeComboBox.setSelectedIndex(0);
|
||||
typePanel.setLayout(new BorderLayout());
|
||||
updateCurrentPanel(ImageFilePanel.getDefault());
|
||||
|
||||
selectButton.setEnabled(false);
|
||||
}
|
||||
|
||||
private void display() {
|
||||
@@ -92,54 +111,31 @@ public class MissingImageDialog extends javax.swing.JDialog {
|
||||
this.setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh this panel.
|
||||
* @param panel current typepanel
|
||||
*/
|
||||
private void updateCurrentPanel(ContentTypePanel panel) {
|
||||
currentPanel = panel;
|
||||
typePanel.removeAll();
|
||||
typePanel.add((JPanel) currentPanel, BorderLayout.CENTER);
|
||||
typePanel.validate();
|
||||
typePanel.repaint();
|
||||
this.validate();
|
||||
this.repaint();
|
||||
currentPanel.addPropertyChangeListener(new PropertyChangeListener() {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if(evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString())) {
|
||||
updateSelectButton();
|
||||
}
|
||||
if(evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.FOCUS_NEXT.toString())) {
|
||||
moveFocusToSelect();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
currentPanel.select();
|
||||
updateSelectButton();
|
||||
}
|
||||
|
||||
/**
|
||||
* Focuses the select button for easy enter-pressing access.
|
||||
*/
|
||||
//
|
||||
// * Focuses the select button for easy enter-pressing access.
|
||||
//
|
||||
private void moveFocusToSelect() {
|
||||
this.selectButton.requestFocusInWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables/disables the select button based off the current panel.
|
||||
*/
|
||||
//
|
||||
// * Enables/disables the select button based off the current panel.
|
||||
//
|
||||
private void updateSelectButton() {
|
||||
this.selectButton.setEnabled(currentPanel.enableNext());
|
||||
|
||||
// Enable this based on whether there is a valid path
|
||||
if (!pathNameTextField.getText().isEmpty()) {
|
||||
String filePath = pathNameTextField.getText();
|
||||
boolean isExist = Case.pathExists(filePath) || Case.driveExists(filePath);
|
||||
selectButton.setEnabled(isExist);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
//
|
||||
// * 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() {
|
||||
@@ -148,9 +144,8 @@ public class MissingImageDialog extends javax.swing.JDialog {
|
||||
selectButton = new javax.swing.JButton();
|
||||
cancelButton = new javax.swing.JButton();
|
||||
containerPanel = new javax.swing.JPanel();
|
||||
typeComboBox = new javax.swing.JComboBox();
|
||||
typeTabel = new javax.swing.JLabel();
|
||||
typePanel = new javax.swing.JPanel();
|
||||
pathNameTextField = new javax.swing.JTextField();
|
||||
browseButton = new javax.swing.JButton();
|
||||
titleLabel = new javax.swing.JLabel();
|
||||
titleSeparator = new javax.swing.JSeparator();
|
||||
|
||||
@@ -191,43 +186,39 @@ public class MissingImageDialog extends javax.swing.JDialog {
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(typeTabel, org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.typeTabel.text")); // NOI18N
|
||||
pathNameTextField.setText(org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.pathNameTextField.text")); // NOI18N
|
||||
pathNameTextField.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
pathNameTextFieldActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout typePanelLayout = new javax.swing.GroupLayout(typePanel);
|
||||
typePanel.setLayout(typePanelLayout);
|
||||
typePanelLayout.setHorizontalGroup(
|
||||
typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 0, Short.MAX_VALUE)
|
||||
);
|
||||
typePanelLayout.setVerticalGroup(
|
||||
typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 57, Short.MAX_VALUE)
|
||||
);
|
||||
org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.browseButton.text")); // NOI18N
|
||||
browseButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
browseButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout containerPanelLayout = new javax.swing.GroupLayout(containerPanel);
|
||||
containerPanel.setLayout(containerPanelLayout);
|
||||
containerPanelLayout.setHorizontalGroup(
|
||||
containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(containerPanelLayout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGroup(containerPanelLayout.createSequentialGroup()
|
||||
.addComponent(typeTabel)
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(typeComboBox, 0, 298, Short.MAX_VALUE)))
|
||||
.addContainerGap())
|
||||
.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))
|
||||
);
|
||||
containerPanelLayout.setVerticalGroup(
|
||||
containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(containerPanelLayout.createSequentialGroup()
|
||||
.addGap(0, 0, 0)
|
||||
.addGap(18, 18, 18)
|
||||
.addGroup(containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(typeTabel)
|
||||
.addComponent(typeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addContainerGap())
|
||||
.addComponent(pathNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(browseButton))
|
||||
.addContainerGap(62, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
titleLabel.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
|
||||
@@ -268,7 +259,7 @@ public class MissingImageDialog extends javax.swing.JDialog {
|
||||
|
||||
private void selectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectButtonActionPerformed
|
||||
try {
|
||||
String newPath = currentPanel.getContentPaths();
|
||||
String newPath = pathNameTextField.getText();
|
||||
//TODO handle local files
|
||||
db.setImagePaths(obj_id, Arrays.asList(new String[]{newPath}));
|
||||
} catch (TskCoreException ex) {
|
||||
@@ -281,21 +272,48 @@ public class MissingImageDialog extends javax.swing.JDialog {
|
||||
cancel();
|
||||
}//GEN-LAST:event_cancelButtonActionPerformed
|
||||
|
||||
private void pathNameTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pathNameTextFieldActionPerformed
|
||||
// TODO add your handling code here:
|
||||
|
||||
updateSelectButton();
|
||||
}//GEN-LAST:event_pathNameTextFieldActionPerformed
|
||||
|
||||
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
|
||||
|
||||
|
||||
|
||||
String oldText = pathNameTextField.getText();
|
||||
|
||||
// set the current directory of the FileChooser if the ImagePath Field is valid
|
||||
File currentDir = new File(oldText);
|
||||
if (currentDir.exists()) {
|
||||
fc.setCurrentDirectory(currentDir);
|
||||
}
|
||||
|
||||
int retval = fc.showOpenDialog(this);
|
||||
if (retval == JFileChooser.APPROVE_OPTION) {
|
||||
String path = fc.getSelectedFile().getPath();
|
||||
pathNameTextField.setText(path);
|
||||
}
|
||||
//pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString(), false, true);
|
||||
|
||||
updateSelectButton();
|
||||
}//GEN-LAST:event_browseButtonActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton browseButton;
|
||||
private javax.swing.JPanel buttonPanel;
|
||||
private javax.swing.JButton cancelButton;
|
||||
private javax.swing.JPanel containerPanel;
|
||||
private javax.swing.JTextField pathNameTextField;
|
||||
private javax.swing.JButton selectButton;
|
||||
private javax.swing.JLabel titleLabel;
|
||||
private javax.swing.JSeparator titleSeparator;
|
||||
private javax.swing.JComboBox typeComboBox;
|
||||
private javax.swing.JPanel typePanel;
|
||||
private javax.swing.JLabel typeTabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
/**
|
||||
* Verify the user wants to cancel searching for the image.
|
||||
*/
|
||||
//
|
||||
// * Verify the user wants to cancel searching for the image.
|
||||
//
|
||||
void cancel() {
|
||||
int ret = JOptionPane.showConfirmDialog(null,
|
||||
"No image file has been selected, are you sure you\n" +
|
||||
@@ -306,40 +324,5 @@ public class MissingImageDialog extends javax.swing.JDialog {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ComboBoxModel to control typeComboBox and supply ImageTypePanels.
|
||||
*/
|
||||
private class ImageTypeModel implements ComboBoxModel {
|
||||
ContentTypePanel selected;
|
||||
ContentTypePanel[] types = ContentTypePanel.getPanels();
|
||||
|
||||
@Override
|
||||
public void setSelectedItem(Object anItem) {
|
||||
selected = (ContentTypePanel) anItem;
|
||||
updateCurrentPanel(selected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSelectedItem() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return types.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElementAt(int index) {
|
||||
return types[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListDataListener(ListDataListener l) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListDataListener(ListDataListener l) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java
Normal file → Executable file
12
Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java
Normal file → Executable file
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012 Basis Technology Corp.
|
||||
* Copyright 2012-2013 Basis Technology Corp.
|
||||
*
|
||||
* Copyright 2012 42six Solutions.
|
||||
* Contact: aebadirad <at> 42six <dot> com
|
||||
@@ -37,21 +37,29 @@ public class Services implements Closeable {
|
||||
|
||||
// NOTE: all new services added to Services class must be added to this list
|
||||
// of services.
|
||||
private List<Closeable> services = new ArrayList<Closeable>();
|
||||
private List<Closeable> services = new ArrayList<>();
|
||||
|
||||
// services
|
||||
private FileManager fileManager;
|
||||
private TagsManager tagsManager;
|
||||
|
||||
public Services(SleuthkitCase tskCase) {
|
||||
this.tskCase = tskCase;
|
||||
//create and initialize FileManager as early as possibly in the new/opened Case
|
||||
fileManager = new FileManager(tskCase);
|
||||
services.add(fileManager);
|
||||
|
||||
tagsManager = new TagsManager(tskCase);
|
||||
services.add(tagsManager);
|
||||
}
|
||||
|
||||
public FileManager getFileManager() {
|
||||
return fileManager;
|
||||
}
|
||||
|
||||
public TagsManager getTagsManager() {
|
||||
return tagsManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
||||
464
Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java
Executable file
464
Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java
Executable file
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.services;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* A per case instance of this class functions as an Autopsy service that
|
||||
* manages the creation, updating, and deletion of tags applied to content and
|
||||
* blackboard artifacts by users.
|
||||
*/
|
||||
public class TagsManager implements Closeable {
|
||||
private static final String TAGS_SETTINGS_NAME = "Tags";
|
||||
private static final String TAG_NAMES_SETTING_KEY = "TagNames";
|
||||
private final SleuthkitCase tskCase;
|
||||
private final HashMap<String, TagName> uniqueTagNames = new HashMap<>();
|
||||
private boolean tagNamesInitialized = false; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
|
||||
// Use this exception and the member hash map to manage uniqueness of hash
|
||||
// names. This is deemed more proactive and informative than leaving this to
|
||||
// the UNIQUE constraint on the display_name field of the tag_names table in
|
||||
// the case database.
|
||||
public class TagNameAlreadyExistsException extends Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Package-scope constructor for use of the Services class. An instance of
|
||||
* TagsManager should be created for each case that is opened.
|
||||
* @param [in] tskCase The SleuthkitCase object for the current case.
|
||||
*/
|
||||
TagsManager(SleuthkitCase tskCase) {
|
||||
this.tskCase = tskCase;
|
||||
// @@@ The removal of this call is a work around until database access on the EDT is correctly synchronized.
|
||||
// getExistingTagNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all tag names currently available for tagging content or
|
||||
* blackboard artifacts.
|
||||
* @return A list, possibly empty, of TagName data transfer objects (DTOs).
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public synchronized List<TagName> getAllTagNames() throws TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
return tskCase.getAllTagNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all tag names currently used for tagging content or
|
||||
* blackboard artifacts.
|
||||
* @return A list, possibly empty, of TagName data transfer objects (DTOs).
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public synchronized List<TagName> getTagNamesInUse() throws TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
return tskCase.getTagNamesInUse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a tag name with a given display name exists.
|
||||
* @param [in] tagDisplayName The display name for which to check.
|
||||
* @return True if the tag name exists, false otherwise.
|
||||
*/
|
||||
public synchronized boolean tagNameExists(String tagDisplayName) {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
return uniqueTagNames.containsKey(tagDisplayName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new tag name to the current case and to the tags settings.
|
||||
* @param [in] displayName The display name for the new tag name.
|
||||
* @return A TagName data transfer object (DTO) representing the new tag name.
|
||||
* @throws TagNameAlreadyExistsException, TskCoreException
|
||||
*/
|
||||
public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException {
|
||||
return addTagName(displayName, "", TagName.HTML_COLOR.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new tag name to the current case and to the tags settings.
|
||||
* @param [in] displayName The display name for the new tag name.
|
||||
* @param [in] description The description for the new tag name.
|
||||
* @return A TagName data transfer object (DTO) representing the new tag name.
|
||||
* @throws TagNameAlreadyExistsException, TskCoreException
|
||||
*/
|
||||
public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException {
|
||||
return addTagName(displayName, description, TagName.HTML_COLOR.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new tag name to the current case and to the tags settings.
|
||||
* @param [in] displayName The display name for the new tag name.
|
||||
* @param [in] description The description for the new tag name.
|
||||
* @param [in] color The HTML color to associate with the new tag name.
|
||||
* @return A TagName data transfer object (DTO) representing the new tag name.
|
||||
* @throws TagNameAlreadyExistsException, TskCoreException
|
||||
*/
|
||||
public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
if (uniqueTagNames.containsKey(displayName)) {
|
||||
throw new TagNameAlreadyExistsException();
|
||||
}
|
||||
|
||||
// Add the tag name to the case.
|
||||
TagName newTagName = tskCase.addTagName(displayName, description, color);
|
||||
|
||||
// Add the tag name to the tags settings.
|
||||
uniqueTagNames.put(newTagName.getDisplayName(), newTagName);
|
||||
saveTagNamesToTagsSettings();
|
||||
|
||||
return newTagName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags a content object.
|
||||
* @param [in] content The content to tag.
|
||||
* @param [in] tagName The name to use for the tag.
|
||||
* @return A ContentTag data transfer object (DTO) representing the new tag.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public ContentTag addContentTag(Content content, TagName tagName) throws TskCoreException {
|
||||
return addContentTag(content, tagName, "", -1, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags a content object.
|
||||
* @param [in] content The content to tag.
|
||||
* @param [in] tagName The name to use for the tag.
|
||||
* @param [in] comment A comment to store with the tag.
|
||||
* @return A ContentTag data transfer object (DTO) representing the new tag.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public ContentTag addContentTag(Content content, TagName tagName, String comment) throws TskCoreException {
|
||||
return addContentTag(content, tagName, comment, -1, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags a content object or a section of a content object.
|
||||
* @param [in] content The content to tag.
|
||||
* @param [in] tagName The name to use for the tag.
|
||||
* @param [in] comment A comment to store with the tag.
|
||||
* @param [in] beginByteOffset Designates the beginning of a tagged section.
|
||||
* @param [in] endByteOffset Designates the end of a tagged section.
|
||||
* @return A ContentTag data transfer object (DTO) representing the new tag.
|
||||
* @throws IllegalArgumentException, TskCoreException
|
||||
*/
|
||||
public synchronized ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
if (beginByteOffset >= 0 && endByteOffset >= 1) {
|
||||
if (beginByteOffset > content.getSize() - 1) {
|
||||
throw new IllegalArgumentException("beginByteOffset = " + beginByteOffset + " out of content size range (0 - " + (content.getSize() - 1) + ")");
|
||||
}
|
||||
|
||||
if (endByteOffset > content.getSize() - 1) {
|
||||
throw new IllegalArgumentException("endByteOffset = " + endByteOffset + " out of content size range (0 - " + (content.getSize() - 1) + ")");
|
||||
}
|
||||
|
||||
if (endByteOffset < beginByteOffset) {
|
||||
throw new IllegalArgumentException("endByteOffset < beginByteOffset");
|
||||
}
|
||||
}
|
||||
|
||||
return tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a content tag.
|
||||
* @param [in] tag The tag to delete.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public synchronized void deleteContentTag(ContentTag tag) throws TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
tskCase.deleteContentTag(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all content tags for the current case.
|
||||
* @return A list, possibly empty, of content tags.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public List<ContentTag> getAllContentTags() throws TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
return tskCase.getAllContentTags();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets content tags count by tag name.
|
||||
* @param [in] tagName The tag name of interest.
|
||||
* @return A count of the content tags with the specified tag name.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public synchronized long getContentTagsCountByTagName(TagName tagName) throws TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
return tskCase.getContentTagsCountByTagName(tagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets content tags by tag name.
|
||||
* @param [in] tagName The tag name of interest.
|
||||
* @return A list, possibly empty, of the content tags with the specified tag name.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public synchronized List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
return tskCase.getContentTagsByTagName(tagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets content tags count by content.
|
||||
* @param [in] content The content of interest.
|
||||
* @return A list, possibly empty, of the tags that have been applied to the artifact.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public synchronized List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
return tskCase.getContentTagsByContent(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags a blackboard artifact object.
|
||||
* @param [in] artifact The blackboard artifact to tag.
|
||||
* @param [in] tagName The name to use for the tag.
|
||||
* @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException {
|
||||
return addBlackboardArtifactTag(artifact, tagName, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags a blackboard artifact object.
|
||||
* @param [in] artifact The blackboard artifact to tag.
|
||||
* @param [in] tagName The name to use for the tag.
|
||||
* @param [in] comment A comment to store with the tag.
|
||||
* @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public synchronized BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
return tskCase.addBlackboardArtifactTag(artifact, tagName, comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a blackboard artifact tag.
|
||||
* @param [in] tag The tag to delete.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public synchronized void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
tskCase.deleteBlackboardArtifactTag(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all blackboard artifact tags for the current case.
|
||||
* @return A list, possibly empty, of blackboard artifact tags.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
return tskCase.getAllBlackboardArtifactTags();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets blackboard artifact tags count by tag name.
|
||||
* @param [in] tagName The tag name of interest.
|
||||
* @return A count of the blackboard artifact tags with the specified tag name.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public synchronized long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
return tskCase.getBlackboardArtifactTagsCountByTagName(tagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets blackboard artifact tags by tag name.
|
||||
* @param [in] tagName The tag name of interest.
|
||||
* @return A list, possibly empty, of the blackboard artifact tags with the specified tag name.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public synchronized List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
return tskCase.getBlackboardArtifactTagsByTagName(tagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets blackboard artifact tags for a particular blackboard artifact.
|
||||
* @param [in] artifact The blackboard artifact of interest.
|
||||
* @return A list, possibly empty, of the tags that have been applied to the artifact.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public synchronized List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
|
||||
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
if (!tagNamesInitialized) {
|
||||
getExistingTagNames();
|
||||
}
|
||||
|
||||
return tskCase.getBlackboardArtifactTagsByArtifact(artifact);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
saveTagNamesToTagsSettings();
|
||||
}
|
||||
|
||||
private void getExistingTagNames() {
|
||||
getTagNamesFromCurrentCase();
|
||||
getTagNamesFromTagsSettings();
|
||||
getPredefinedTagNames();
|
||||
saveTagNamesToTagsSettings();
|
||||
tagNamesInitialized = true; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized.
|
||||
}
|
||||
|
||||
private void getTagNamesFromCurrentCase() {
|
||||
try {
|
||||
List<TagName> currentTagNames = tskCase.getAllTagNames();
|
||||
for (TagName tagName : currentTagNames) {
|
||||
uniqueTagNames.put(tagName.getDisplayName(), tagName);
|
||||
}
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void getTagNamesFromTagsSettings() {
|
||||
String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY);
|
||||
if (null != setting && !setting.isEmpty()) {
|
||||
// Read the tag name setting and break it into tag name tuples.
|
||||
List<String> tagNameTuples = Arrays.asList(setting.split(";"));
|
||||
|
||||
// Parse each tuple and add the tag names to the current case, one
|
||||
// at a time to gracefully discard any duplicates or corrupt tuples.
|
||||
for (String tagNameTuple : tagNameTuples) {
|
||||
String[] tagNameAttributes = tagNameTuple.split(",");
|
||||
if (!uniqueTagNames.containsKey(tagNameAttributes[0])) {
|
||||
try {
|
||||
TagName tagName = tskCase.addTagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2]));
|
||||
uniqueTagNames.put(tagName.getDisplayName(), tagName);
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add saved tag name " + tagNameAttributes[0], ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void getPredefinedTagNames() {
|
||||
if (!uniqueTagNames.containsKey("Bookmark")) {
|
||||
try {
|
||||
TagName tagName = tskCase.addTagName("Bookmark", "", TagName.HTML_COLOR.NONE);
|
||||
uniqueTagNames.put(tagName.getDisplayName(), tagName);
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add predefined 'Bookmark' tag name", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveTagNamesToTagsSettings() {
|
||||
if (!uniqueTagNames.isEmpty()) {
|
||||
StringBuilder setting = new StringBuilder();
|
||||
for (TagName tagName : uniqueTagNames.values()) {
|
||||
if (setting.length() != 0) {
|
||||
setting.append(";");
|
||||
}
|
||||
setting.append(tagName.getDisplayName()).append(",");
|
||||
setting.append(tagName.getDescription()).append(",");
|
||||
setting.append(tagName.getColor().name());
|
||||
}
|
||||
ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,7 +157,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer
|
||||
|
||||
@Override
|
||||
public String getToolTip() {
|
||||
return "";
|
||||
return "Displays metadata about the file.";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,8 +26,8 @@ import javafx.embed.swing.JFXPanel;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.openide.modules.ModuleInstall;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
|
||||
/**
|
||||
* Wrapper over Installers in packages in Core module This is the main
|
||||
@@ -39,6 +39,41 @@ public class Installer extends ModuleInstall {
|
||||
private static final Logger logger = Logger.getLogger(Installer.class.getName());
|
||||
private static volatile boolean javaFxInit = false;
|
||||
|
||||
static {
|
||||
loadDynLibraries();
|
||||
}
|
||||
|
||||
private static void loadDynLibraries() {
|
||||
if (PlatformUtil.isWindowsOS()) {
|
||||
try {
|
||||
//on windows force loading ms crt dependencies first
|
||||
//in case linker can't find them on some systems
|
||||
//Note: if shipping with a different CRT version, this will only print a warning
|
||||
//and try to use linker mechanism to find the correct versions of libs.
|
||||
//We should update this if we officially switch to a new version of CRT/compiler
|
||||
System.loadLibrary("msvcr100");
|
||||
System.loadLibrary("msvcp100");
|
||||
logger.log(Level.INFO, "MS CRT libraries loaded");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
logger.log(Level.SEVERE, "Error loading ms crt libraries, ", e);
|
||||
}
|
||||
|
||||
try {
|
||||
System.loadLibrary("zlib");
|
||||
logger.log(Level.INFO, "ZLIB library loaded loaded");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
logger.log(Level.SEVERE, "Error loading ZLIB library, ", e);
|
||||
}
|
||||
|
||||
try {
|
||||
System.loadLibrary("libewf");
|
||||
logger.log(Level.INFO, "EWF library loaded");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
logger.log(Level.SEVERE, "Error loading EWF library, ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Installer() {
|
||||
logger.log(Level.INFO, "core installer created");
|
||||
javaFxInit = false;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 - 2013 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.corecomponentinterfaces;
|
||||
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
|
||||
/**
|
||||
* Implementers of this interface provide Actions that will be added to context
|
||||
* menus in Autopsy.
|
||||
*/
|
||||
public interface ContextMenuActionsProvider {
|
||||
/**
|
||||
* Gets context menu Actions for the currently selected data model objects
|
||||
* exposed by the NetBeans Lookup of the active TopComponent. Implementers
|
||||
* should discover the selected objects by calling
|
||||
* org.openide.util.Utilities.actionsGlobalContext().lookupAll() for the
|
||||
* org.sleuthkit.datamodel classes of interest to the provider.
|
||||
* @return A list, possibly empty, of Action objects.
|
||||
*/
|
||||
public List<Action> getActions();
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.corecomponentinterfaces;
|
||||
|
||||
import java.awt.EventQueue;
|
||||
import java.util.List;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
|
||||
/**
|
||||
* Abstract class for a callback for a DataSourceProcessor.
|
||||
*
|
||||
* Ensures that DSP invokes the caller overridden method, doneEDT(),
|
||||
* in the EDT thread.
|
||||
*
|
||||
*/
|
||||
public abstract class DSPCallback {
|
||||
|
||||
public enum DSP_Result
|
||||
{
|
||||
NO_ERRORS,
|
||||
CRITICAL_ERRORS,
|
||||
NONCRITICAL_ERRORS,
|
||||
};
|
||||
|
||||
/*
|
||||
* Invoke the caller supplied callback function on the EDT thread
|
||||
*/
|
||||
public void done(DSP_Result result, List<String> errList, List<Content> newContents)
|
||||
{
|
||||
|
||||
final DSP_Result resultf = result;
|
||||
final List<String> errListf = errList;
|
||||
final List<Content> newContentsf = newContents;
|
||||
|
||||
// Invoke doneEDT() that runs on the EDT .
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doneEDT(resultf, errListf, newContentsf );
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* calling code overrides to provide its own calllback
|
||||
*/
|
||||
public abstract void doneEDT(DSP_Result result, List<String> errList, List<Content> newContents);
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.corecomponentinterfaces;
|
||||
|
||||
/*
|
||||
* An GUI agnostic DSPProgressMonitor interface for DataSourceProcesssors to
|
||||
* indicate progress.
|
||||
* It models after a JProgressbar though it could use any underlying implementation
|
||||
*/
|
||||
public interface DSPProgressMonitor {
|
||||
|
||||
void setIndeterminate(boolean indeterminate);
|
||||
|
||||
void setProgress(int progress);
|
||||
|
||||
void setProgressText(String text);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2013 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.corecomponentinterfaces;
|
||||
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/*
|
||||
* Defines an interface used by the Add DataSource wizard to discover different
|
||||
* Data SourceProcessors.
|
||||
*
|
||||
* Each data source may have its unique attributes and may need to be processed
|
||||
* differently.
|
||||
*
|
||||
* The DataSourceProcessor interface defines a uniform mechanism for the Autopsy UI
|
||||
* to:
|
||||
* - collect details for the data source to be processed.
|
||||
* - Process the data source in the background
|
||||
* - Be notified when the processing is complete
|
||||
*/
|
||||
public interface DataSourceProcessor {
|
||||
|
||||
/*
|
||||
* The DSP Panel may fire Property change events
|
||||
* The caller must enure to add itself as a listener and
|
||||
* then react appropriately to the events
|
||||
*/
|
||||
enum DSP_PANEL_EVENT {
|
||||
|
||||
UPDATE_UI, // the content of JPanel has changed that MAY warrant updates to the caller UI
|
||||
FOCUS_NEXT // the caller UI may move focus the the next UI element, floowing the panel.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the type of Data Source it handles.
|
||||
* This name gets displayed in the drop-down listbox
|
||||
**/
|
||||
String getType();
|
||||
|
||||
/**
|
||||
* Returns the picker panel to be displayed along with any other
|
||||
* runtime options supported by the data source handler.
|
||||
**/
|
||||
JPanel getPanel();
|
||||
|
||||
/**
|
||||
* Called to validate the input data in the panel.
|
||||
* Returns true if no errors, or
|
||||
* Returns false if there is an error.
|
||||
**/
|
||||
boolean validatePanel();
|
||||
|
||||
/**
|
||||
* Called to invoke the handling of Data source in the background.
|
||||
* Returns after starting the background thread
|
||||
* @param settings wizard settings to read/store properties
|
||||
* @param progressPanel progress panel to be updated while processing
|
||||
*
|
||||
**/
|
||||
void run(DSPProgressMonitor progressPanel, DSPCallback dspCallback);
|
||||
|
||||
|
||||
/**
|
||||
* Called to cancel the background processing.
|
||||
**/
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* Called to reset/reinitialize the DSP.
|
||||
*
|
||||
**/
|
||||
void reset();
|
||||
|
||||
|
||||
}
|
||||
@@ -299,7 +299,6 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
|
||||
currentPage = page;
|
||||
long offset = (currentPage - 1) * pageLength;
|
||||
|
||||
|
||||
// change the cursor to "waiting cursor" for this operation
|
||||
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
|
||||
@@ -344,13 +343,13 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
|
||||
// set the output view
|
||||
if (errorText == null) {
|
||||
int showLength = bytesRead < pageLength ? bytesRead : (int) pageLength;
|
||||
outputViewPane.setText(DataConversion.byteArrayToHex(data, showLength, offset, outputViewPane.getFont()));
|
||||
outputViewPane.setText(DataConversion.byteArrayToHex(data, showLength, offset));
|
||||
}
|
||||
else {
|
||||
outputViewPane.setText(errorText);
|
||||
}
|
||||
|
||||
outputViewPane.moveCaretPosition(0);
|
||||
outputViewPane.setCaretPosition(0);
|
||||
this.setCursor(null);
|
||||
}
|
||||
|
||||
|
||||
@@ -362,6 +362,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
this.rootNode.addNodeListener(dummyNodeListener);
|
||||
}
|
||||
|
||||
resetTabs(selectedNode);
|
||||
setupTabs(selectedNode);
|
||||
|
||||
if (selectedNode != null) {
|
||||
@@ -369,58 +370,42 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
this.numberMatchLabel.setText(Integer.toString(childrenCount));
|
||||
}
|
||||
this.numberMatchLabel.setVisible(true);
|
||||
|
||||
|
||||
resetTabs(selectedNode);
|
||||
|
||||
// set the display on the current active tab
|
||||
int currentActiveTab = this.dataResultTabbedPanel.getSelectedIndex();
|
||||
if (currentActiveTab != -1) {
|
||||
UpdateWrapper drv = viewers.get(currentActiveTab);
|
||||
drv.setNode(selectedNode);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupTabs(final Node selectedNode) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//update/disable tabs based on if supported for this node
|
||||
int drvC = 0;
|
||||
for (UpdateWrapper drv : viewers) {
|
||||
private void setupTabs(Node selectedNode) {
|
||||
//update/disable tabs based on if supported for this node
|
||||
int drvC = 0;
|
||||
for (UpdateWrapper drv : viewers) {
|
||||
|
||||
if (drv.isSupported(selectedNode)) {
|
||||
dataResultTabbedPanel.setEnabledAt(drvC, true);
|
||||
} else {
|
||||
dataResultTabbedPanel.setEnabledAt(drvC, false);
|
||||
}
|
||||
++drvC;
|
||||
}
|
||||
if (drv.isSupported(selectedNode)) {
|
||||
dataResultTabbedPanel.setEnabledAt(drvC, true);
|
||||
} else {
|
||||
dataResultTabbedPanel.setEnabledAt(drvC, false);
|
||||
}
|
||||
++drvC;
|
||||
}
|
||||
|
||||
// if the current tab is no longer enabled, then find one that is
|
||||
boolean hasViewerEnabled = true;
|
||||
int currentActiveTab = dataResultTabbedPanel.getSelectedIndex();
|
||||
if ((currentActiveTab == -1) || (dataResultTabbedPanel.isEnabledAt(currentActiveTab) == false)) {
|
||||
hasViewerEnabled = false;
|
||||
for (int i = 0; i < dataResultTabbedPanel.getTabCount(); i++) {
|
||||
if (dataResultTabbedPanel.isEnabledAt(i)) {
|
||||
currentActiveTab = i;
|
||||
hasViewerEnabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasViewerEnabled) {
|
||||
dataResultTabbedPanel.setSelectedIndex(currentActiveTab);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasViewerEnabled) {
|
||||
viewers.get(currentActiveTab).setNode(selectedNode);
|
||||
// if the current tab is no longer enabled, then find one that is
|
||||
boolean hasViewerEnabled = true;
|
||||
int currentActiveTab = dataResultTabbedPanel.getSelectedIndex();
|
||||
if ((currentActiveTab == -1) || (dataResultTabbedPanel.isEnabledAt(currentActiveTab) == false)) {
|
||||
hasViewerEnabled = false;
|
||||
for (int i = 0; i < dataResultTabbedPanel.getTabCount(); i++) {
|
||||
if (dataResultTabbedPanel.isEnabledAt(i)) {
|
||||
currentActiveTab = i;
|
||||
hasViewerEnabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (hasViewerEnabled) {
|
||||
dataResultTabbedPanel.setSelectedIndex(currentActiveTab);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasViewerEnabled) {
|
||||
viewers.get(currentActiveTab).setNode(selectedNode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -622,12 +607,22 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childrenAdded(NodeMemberEvent nme) {
|
||||
public void childrenAdded(final NodeMemberEvent nme) {
|
||||
Node[] delta = nme.getDelta();
|
||||
if (load && containsReal(delta)) {
|
||||
load = false;
|
||||
setupTabs(nme.getNode());
|
||||
updateMatches();
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
setupTabs(nme.getNode());
|
||||
updateMatches();
|
||||
} else {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setupTabs(nme.getNode());
|
||||
updateMatches();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,14 +640,9 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
*
|
||||
*/
|
||||
private void updateMatches() {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (rootNode != null && rootNode.getChildren() != null) {
|
||||
setNumMatches(rootNode.getChildren().getNodesCount());
|
||||
}
|
||||
}
|
||||
});
|
||||
if (rootNode != null && rootNode.getChildren() != null) {
|
||||
setNumMatches(rootNode.getChildren().getNodesCount());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -215,18 +215,17 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
*/
|
||||
private void getAllChildPropertyHeadersRec(Node parent, int rows) {
|
||||
Children children = parent.getChildren();
|
||||
int total = Math.min(rows, children.getNodesCount());
|
||||
for (int i = 0; i < total; i++) {
|
||||
Node child = children.getNodeAt(i);
|
||||
int childCount = 0;
|
||||
for (Node child : children.getNodes()) {
|
||||
if (++childCount > rows) {
|
||||
break;
|
||||
}
|
||||
for (PropertySet ps : child.getPropertySets()) {
|
||||
//if (ps.getName().equals(Sheet.PROPERTIES)) {
|
||||
//return ps.getProperties();
|
||||
final Property[] props = ps.getProperties();
|
||||
final int propsNum = props.length;
|
||||
for (int j = 0; j < propsNum; ++j) {
|
||||
propertiesAcc.add(props[j]);
|
||||
}
|
||||
//}
|
||||
}
|
||||
getAllChildPropertyHeadersRec(child, rows);
|
||||
}
|
||||
@@ -278,137 +277,131 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
* @param root The parent Node of the ContentNodes
|
||||
*/
|
||||
private void setupTable(final Node root) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//wrap to filter out children
|
||||
//note: this breaks the tree view mode in this generic viewer,
|
||||
//so wrap nodes earlier if want 1 level view
|
||||
//if (!(root instanceof TableFilterNode)) {
|
||||
/// root = new TableFilterNode(root, true);
|
||||
//}
|
||||
//wrap to filter out children
|
||||
//note: this breaks the tree view mode in this generic viewer,
|
||||
//so wrap nodes earlier if want 1 level view
|
||||
//if (!(root instanceof TableFilterNode)) {
|
||||
/// root = new TableFilterNode(root, true);
|
||||
//}
|
||||
|
||||
em.setRootContext(root);
|
||||
em.setRootContext(root);
|
||||
|
||||
|
||||
final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel);
|
||||
final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel);
|
||||
|
||||
if (ov == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
propertiesAcc.clear();
|
||||
|
||||
DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100);
|
||||
List<Node.Property> props = new ArrayList<Node.Property>(propertiesAcc);
|
||||
if (props.size() > 0) {
|
||||
Node.Property prop = props.remove(0);
|
||||
((DefaultOutlineModel) ov.getOutline().getOutlineModel()).setNodesColumnLabel(prop.getDisplayName());
|
||||
}
|
||||
|
||||
|
||||
// *********** Make the TreeTableView to be sortable ***************
|
||||
|
||||
//First property column is sortable, but also sorted initially, so
|
||||
//initially this one will have the arrow icon:
|
||||
if (props.size() > 0) {
|
||||
props.get(0).setValue("TreeColumnTTV", Boolean.TRUE); // Identifies special property representing first (tree) column.
|
||||
props.get(0).setValue("SortingColumnTTV", Boolean.TRUE); // TreeTableView should be initially sorted by this property column.
|
||||
}
|
||||
|
||||
// The rest of the columns are sortable, but not initially sorted,
|
||||
// so initially will have no arrow icon:
|
||||
String[] propStrings = new String[props.size() * 2];
|
||||
for (int i = 0; i < props.size(); i++) {
|
||||
props.get(i).setValue("ComparableColumnTTV", Boolean.TRUE);
|
||||
propStrings[2 * i] = props.get(i).getName();
|
||||
propStrings[2 * i + 1] = props.get(i).getDisplayName();
|
||||
}
|
||||
|
||||
ov.setPropertyColumns(propStrings);
|
||||
// *****************************************************************
|
||||
|
||||
// // set the first entry
|
||||
// Children test = root.getChildren();
|
||||
// Node firstEntryNode = test.getNodeAt(0);
|
||||
// try {
|
||||
// this.getExplorerManager().setSelectedNodes(new Node[]{firstEntryNode});
|
||||
// } catch (PropertyVetoException ex) {}
|
||||
|
||||
|
||||
// show the horizontal scroll panel and show all the content & header
|
||||
|
||||
int totalColumns = props.size();
|
||||
|
||||
//int scrollWidth = ttv.getWidth();
|
||||
int margin = 4;
|
||||
int startColumn = 1;
|
||||
|
||||
if (ov == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
propertiesAcc.clear();
|
||||
|
||||
DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100);
|
||||
List<Node.Property> props = new ArrayList<Node.Property>(propertiesAcc);
|
||||
if (props.size() > 0) {
|
||||
Node.Property prop = props.remove(0);
|
||||
((DefaultOutlineModel) ov.getOutline().getOutlineModel()).setNodesColumnLabel(prop.getDisplayName());
|
||||
}
|
||||
|
||||
|
||||
// *********** Make the TreeTableView to be sortable ***************
|
||||
|
||||
//First property column is sortable, but also sorted initially, so
|
||||
//initially this one will have the arrow icon:
|
||||
if (props.size() > 0) {
|
||||
props.get(0).setValue("TreeColumnTTV", Boolean.TRUE); // Identifies special property representing first (tree) column.
|
||||
props.get(0).setValue("SortingColumnTTV", Boolean.TRUE); // TreeTableView should be initially sorted by this property column.
|
||||
}
|
||||
|
||||
// The rest of the columns are sortable, but not initially sorted,
|
||||
// so initially will have no arrow icon:
|
||||
String[] propStrings = new String[props.size() * 2];
|
||||
for (int i = 0; i < props.size(); i++) {
|
||||
props.get(i).setValue("ComparableColumnTTV", Boolean.TRUE);
|
||||
propStrings[2 * i] = props.get(i).getName();
|
||||
propStrings[2 * i + 1] = props.get(i).getDisplayName();
|
||||
}
|
||||
|
||||
ov.setPropertyColumns(propStrings);
|
||||
// *****************************************************************
|
||||
|
||||
// // set the first entry
|
||||
// Children test = root.getChildren();
|
||||
// Node firstEntryNode = test.getNodeAt(0);
|
||||
// try {
|
||||
// this.getExplorerManager().setSelectedNodes(new Node[]{firstEntryNode});
|
||||
// } catch (PropertyVetoException ex) {}
|
||||
|
||||
|
||||
// show the horizontal scroll panel and show all the content & header
|
||||
|
||||
int totalColumns = props.size();
|
||||
|
||||
//int scrollWidth = ttv.getWidth();
|
||||
int margin = 4;
|
||||
int startColumn = 1;
|
||||
|
||||
// If there is only one column (which was removed from props above)
|
||||
// Just let the table resize itself.
|
||||
ov.getOutline().setAutoResizeMode((props.size() > 0) ? JTable.AUTO_RESIZE_OFF : JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||
// If there is only one column (which was removed from props above)
|
||||
// Just let the table resize itself.
|
||||
ov.getOutline().setAutoResizeMode((props.size() > 0) ? JTable.AUTO_RESIZE_OFF : JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||
|
||||
|
||||
|
||||
// get first 100 rows values for the table
|
||||
Object[][] content = null;
|
||||
content = getRowValues(root, 100);
|
||||
// get first 100 rows values for the table
|
||||
Object[][] content = null;
|
||||
content = getRowValues(root, 100);
|
||||
|
||||
|
||||
if (content != null) {
|
||||
// get the fontmetrics
|
||||
final Graphics graphics = ov.getGraphics();
|
||||
if (graphics != null) {
|
||||
final FontMetrics metrics = graphics.getFontMetrics();
|
||||
if (content != null) {
|
||||
// get the fontmetrics
|
||||
final Graphics graphics = ov.getGraphics();
|
||||
if (graphics != null) {
|
||||
final FontMetrics metrics = graphics.getFontMetrics();
|
||||
|
||||
// for the "Name" column
|
||||
int nodeColWidth = Math.min(getMaxColumnWidth(0, metrics, margin, 40, firstColumnLabel, content), 250); // Note: 40 is the width of the icon + node lines. Change this value if those values change!
|
||||
ov.getOutline().getColumnModel().getColumn(0).setPreferredWidth(nodeColWidth);
|
||||
// for the "Name" column
|
||||
int nodeColWidth = Math.min(getMaxColumnWidth(0, metrics, margin, 40, firstColumnLabel, content), 250); // Note: 40 is the width of the icon + node lines. Change this value if those values change!
|
||||
ov.getOutline().getColumnModel().getColumn(0).setPreferredWidth(nodeColWidth);
|
||||
|
||||
// get the max for each other column
|
||||
for (int colIndex = startColumn; colIndex <= totalColumns; colIndex++) {
|
||||
int colWidth = Math.min(getMaxColumnWidth(colIndex, metrics, margin, 8, props, content), 350);
|
||||
ov.getOutline().getColumnModel().getColumn(colIndex).setPreferredWidth(colWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there's no content just auto resize all columns
|
||||
if (!(content.length > 0)) {
|
||||
// turn on the auto resize
|
||||
ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Object[][] getRowValues(Node node, int rows) {
|
||||
// how many rows are we returning
|
||||
int maxRows = Math.min(rows, node.getChildren().getNodesCount());
|
||||
|
||||
Object[][] objs = new Object[maxRows][];
|
||||
|
||||
for (int i = 0; i < maxRows; i++) {
|
||||
PropertySet[] props = node.getChildren().getNodeAt(i).getPropertySets();
|
||||
if (props.length == 0) //rare special case
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Property[] property = props[0].getProperties();
|
||||
objs[i] = new Object[property.length];
|
||||
|
||||
|
||||
for (int j = 0; j < property.length; j++) {
|
||||
try {
|
||||
objs[i][j] = property[j].getValue();
|
||||
} catch (IllegalAccessException ignore) {
|
||||
objs[i][j] = "n/a";
|
||||
} catch (InvocationTargetException ignore) {
|
||||
objs[i][j] = "n/a";
|
||||
// get the max for each other column
|
||||
for (int colIndex = startColumn; colIndex <= totalColumns; colIndex++) {
|
||||
int colWidth = Math.min(getMaxColumnWidth(colIndex, metrics, margin, 8, props, content), 350);
|
||||
ov.getOutline().getColumnModel().getColumn(colIndex).setPreferredWidth(colWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
return objs;
|
||||
|
||||
// if there's no content just auto resize all columns
|
||||
if (!(content.length > 0)) {
|
||||
// turn on the auto resize
|
||||
ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||
}
|
||||
}
|
||||
|
||||
// Populate a two-dimensional array with rows of property values for up
|
||||
// to maxRows children of the node passed in.
|
||||
private static Object[][] getRowValues(Node node, int maxRows) {
|
||||
Object[][] rowValues = new Object[Math.min(maxRows, node.getChildren().getNodesCount())][];
|
||||
int rowCount = 0;
|
||||
for (Node child : node.getChildren().getNodes()) {
|
||||
if (rowCount >= maxRows) {
|
||||
break;
|
||||
}
|
||||
PropertySet[] propertySets = child.getPropertySets();
|
||||
if (propertySets.length > 0)
|
||||
{
|
||||
Property[] properties = propertySets[0].getProperties();
|
||||
rowValues[rowCount] = new Object[properties.length];
|
||||
for (int j = 0; j < properties.length; ++j) {
|
||||
try {
|
||||
rowValues[rowCount][j] = properties[j].getValue();
|
||||
}
|
||||
catch (IllegalAccessException | InvocationTargetException ignore) {
|
||||
rowValues[rowCount][j] = "n/a";
|
||||
}
|
||||
}
|
||||
}
|
||||
++rowCount;
|
||||
}
|
||||
return rowValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -492,11 +485,20 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childrenAdded(NodeMemberEvent nme) {
|
||||
public void childrenAdded(final NodeMemberEvent nme) {
|
||||
Node[] delta = nme.getDelta();
|
||||
if (load && containsReal(delta)) {
|
||||
load = false;
|
||||
setupTable(nme.getNode());
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
setupTable(nme.getNode());
|
||||
} else {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setupTable(nme.getNode());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
50
Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java
Executable file
50
Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java
Executable file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 - 2013 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 org.openide.util.Lookup;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider;
|
||||
|
||||
/**
|
||||
* This class implements the ContextMenuActionsProvider extension point.
|
||||
*/
|
||||
public class ContextMenuExtensionPoint {
|
||||
/**
|
||||
* Gets all of the Actions provided by registered implementers of the
|
||||
* ContextMenuActionsProvider interface.
|
||||
* @return A list, possibly empty, of Action objects.
|
||||
*/
|
||||
static public List<Action> getActions() {
|
||||
ArrayList<Action> actions = new ArrayList<>();
|
||||
Collection<? extends ContextMenuActionsProvider> actionProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class);
|
||||
for (ContextMenuActionsProvider provider : actionProviders) {
|
||||
List<Action> providerActions = provider.getActions();
|
||||
if (!providerActions.isEmpty()) {
|
||||
actions.add(null); // Separator to set off this provider's actions.
|
||||
actions.addAll(provider.getActions());
|
||||
actions.add(null); // Separator to set off this provider's actions.
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
@@ -146,6 +146,12 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
||||
return "Known";
|
||||
}
|
||||
},
|
||||
HASHSETS {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "In Hashsets";
|
||||
}
|
||||
},
|
||||
MD5HASH {
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -188,6 +194,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
||||
map.put(AbstractFilePropertyType.TYPE_DIR.toString(), content.getDirType().getLabel());
|
||||
map.put(AbstractFilePropertyType.TYPE_META.toString(), content.getMetaType().toString());
|
||||
map.put(AbstractFilePropertyType.KNOWN.toString(), content.getKnown().getName());
|
||||
map.put(AbstractFilePropertyType.HASHSETS.toString(), HashsetHits.getList(content.getSleuthkitCase(), content.getId()));
|
||||
map.put(AbstractFilePropertyType.MD5HASH.toString(), content.getMd5Hash() == null ? "" : content.getMd5Hash());
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children.Keys;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
|
||||
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
|
||||
import org.sleuthkit.datamodel.DerivedFile;
|
||||
import org.sleuthkit.datamodel.Directory;
|
||||
@@ -157,8 +156,8 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(Tags t) {
|
||||
return t.new TagsRootNode();
|
||||
public AbstractNode visit(TagsNodeKey tagsNodeKey) {
|
||||
return new TagsNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -128,11 +128,6 @@ public class ArtifactTypeNode extends DisplayableItemNode {
|
||||
return "artifact-icon.png";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
||||
@@ -52,14 +52,14 @@ public interface AutopsyItemVisitor<T> {
|
||||
|
||||
T visit(EmailExtracted ee);
|
||||
|
||||
T visit(Tags t);
|
||||
|
||||
T visit(TagsNodeKey tagsNodeKey);
|
||||
|
||||
T visit(DataSources i);
|
||||
|
||||
T visit(Views v);
|
||||
|
||||
T visit(Results r);
|
||||
|
||||
|
||||
static abstract public class Default<T> implements AutopsyItemVisitor<T> {
|
||||
|
||||
protected abstract T defaultVisit(AutopsyVisitableItem ec);
|
||||
@@ -135,8 +135,8 @@ public interface AutopsyItemVisitor<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(Tags t) {
|
||||
return defaultVisit(t);
|
||||
public T visit(TagsNodeKey tagsNodeKey) {
|
||||
return defaultVisit(tagsNodeKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
|
||||
@@ -140,7 +141,12 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
} else {
|
||||
String dataSource = "";
|
||||
try {
|
||||
dataSource = associated.getImage().getName();
|
||||
Image image = associated.getImage();
|
||||
if (image != null) {
|
||||
dataSource = image.getName();
|
||||
} else {
|
||||
dataSource = getRootParentName();
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Failed to get image name from " + associated.getName());
|
||||
}
|
||||
@@ -153,6 +159,20 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private String getRootParentName() {
|
||||
String parentName = associated.getName();
|
||||
Content parent = associated;
|
||||
try {
|
||||
while ((parent = parent.getParent()) != null) {
|
||||
parentName = parent.getName();
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Failed to get parent name from " + associated.getName());
|
||||
return "";
|
||||
}
|
||||
return parentName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an additional custom node property to that node before it is
|
||||
@@ -334,11 +354,6 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
return "artifact-icon.png";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
||||
94
Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java
Executable file
94
Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java
Executable file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.datamodel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.actions.DeleteBlackboardArtifactTagAction;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Instances of this class wrap BlackboardArtifactTag objects. In the Autopsy
|
||||
* presentation of the SleuthKit data model, they are leaf nodes of a sub-tree
|
||||
* organized as follows: there is a tags root node with tag name child nodes;
|
||||
* tag name nodes have tag type child nodes; tag type nodes are the parents of
|
||||
* either content or blackboard artifact tag nodes.
|
||||
*/
|
||||
public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/green-tag-icon-16.png";
|
||||
private final BlackboardArtifactTag tag;
|
||||
|
||||
public BlackboardArtifactTagNode(BlackboardArtifactTag tag) {
|
||||
super(Children.LEAF, Lookups.fixed(tag, tag.getArtifact(), tag.getContent()));
|
||||
super.setName(tag.getContent().getName());
|
||||
super.setDisplayName(tag.getContent().getName());
|
||||
this.setIconBaseWithExtension(ICON_PATH);
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet propertySheet = super.createSheet();
|
||||
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
|
||||
if (properties == null) {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
propertySheet.put(properties);
|
||||
}
|
||||
|
||||
properties.put(new NodeProperty("Source File", "Source File", "", tag.getContent().getName()));
|
||||
String contentPath;
|
||||
try {
|
||||
contentPath = tag.getContent().getUniquePath();
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex);
|
||||
contentPath = "Unavailable";
|
||||
}
|
||||
properties.put(new NodeProperty("Source File Path", "Source File Path", "", contentPath));
|
||||
properties.put(new NodeProperty("Result Type", "Result Type", "", tag.getArtifact().getDisplayName()));
|
||||
properties.put(new NodeProperty("Comment", "Comment", "", tag.getComment()));
|
||||
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action[] getActions(boolean context) {
|
||||
List<Action> actions = DataModelActionsFactory.getActions(tag.getContent(), true);
|
||||
actions.add(null); // Adds a menu item separator.
|
||||
actions.add(DeleteBlackboardArtifactTagAction.getInstance());
|
||||
return actions.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,303 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012 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.datamodel;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Action;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Support for bookmark (file and result/artifact) nodes and displaying
|
||||
* bookmarks in the directory tree Bookmarks are divided into file and result
|
||||
* children bookmarks.
|
||||
*
|
||||
* Bookmarks are specialized tags - TSK_TAG_NAME starts with File Bookmark or
|
||||
* Result Bookmark
|
||||
*
|
||||
* @deprecated cosolidated under Tags
|
||||
*
|
||||
* TODO bookmark hierarchy support (TSK_TAG_NAME with slashes)
|
||||
*/
|
||||
@Deprecated
|
||||
public class Bookmarks implements AutopsyVisitableItem {
|
||||
|
||||
public static final String NAME = "Bookmarks";
|
||||
private static final String FILE_BOOKMARKS_LABEL_NAME = "File Bookmarks";
|
||||
private static final String RESULT_BOOKMARKS_LABEL_NAME = "Result Bookmarks";
|
||||
//bookmarks are specializations of tags
|
||||
public static final String BOOKMARK_TAG_NAME = "Bookmark";
|
||||
private static final String BOOKMARK_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png";
|
||||
private static final Logger logger = Logger.getLogger(Bookmarks.class.getName());
|
||||
private SleuthkitCase skCase;
|
||||
private final Map<BlackboardArtifact.ARTIFACT_TYPE, List<BlackboardArtifact>> data =
|
||||
new EnumMap<BlackboardArtifact.ARTIFACT_TYPE, List<BlackboardArtifact>>(BlackboardArtifact.ARTIFACT_TYPE.class);
|
||||
|
||||
public Bookmarks(SleuthkitCase skCase) {
|
||||
this.skCase = skCase;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return null; //v.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* bookmarks root node with file/result bookmarks
|
||||
*/
|
||||
public class BookmarksRootNode extends DisplayableItemNode {
|
||||
|
||||
public BookmarksRootNode() {
|
||||
super(Children.create(new BookmarksRootChildren(), true), Lookups.singleton(NAME));
|
||||
super.setName(NAME);
|
||||
super.setDisplayName(NAME);
|
||||
this.setIconBaseWithExtension(BOOKMARK_ICON_PATH);
|
||||
initData();
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, null);
|
||||
data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, null);
|
||||
|
||||
try {
|
||||
|
||||
//filter out tags that are not bookmarks
|
||||
//we get bookmarks that have tag names that start with predefined names, preserving the bookmark hierarchy
|
||||
List<BlackboardArtifact> tagFiles = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE,
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME,
|
||||
BOOKMARK_TAG_NAME);
|
||||
List<BlackboardArtifact> tagArtifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT,
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME,
|
||||
BOOKMARK_TAG_NAME);
|
||||
|
||||
data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, tagFiles);
|
||||
data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, tagArtifacts);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Count not initialize bookmark nodes, ", ex);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return null; // v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||
if (ss == null) {
|
||||
ss = Sheet.createPropertiesSet();
|
||||
s.put(ss);
|
||||
}
|
||||
|
||||
ss.put(new NodeProperty("Name",
|
||||
"Name",
|
||||
"no description",
|
||||
getName()));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* bookmarks root child node creating types of bookmarks nodes
|
||||
*/
|
||||
private class BookmarksRootChildren extends ChildFactory<BlackboardArtifact.ARTIFACT_TYPE> {
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<BlackboardArtifact.ARTIFACT_TYPE> list) {
|
||||
for (BlackboardArtifact.ARTIFACT_TYPE artType : data.keySet()) {
|
||||
list.add(artType);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(BlackboardArtifact.ARTIFACT_TYPE key) {
|
||||
return new BookmarksNodeRoot(key, data.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bookmarks node representation (file or result)
|
||||
*/
|
||||
public class BookmarksNodeRoot extends DisplayableItemNode {
|
||||
|
||||
public BookmarksNodeRoot(BlackboardArtifact.ARTIFACT_TYPE bookType, List<BlackboardArtifact> bookmarks) {
|
||||
super(Children.create(new BookmarksChildrenNode(bookmarks), true), Lookups.singleton(bookType.getDisplayName()));
|
||||
|
||||
String name = null;
|
||||
if (bookType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)) {
|
||||
name = FILE_BOOKMARKS_LABEL_NAME;
|
||||
} else if (bookType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) {
|
||||
name = RESULT_BOOKMARKS_LABEL_NAME;
|
||||
}
|
||||
|
||||
super.setName(name);
|
||||
super.setDisplayName(name + " (" + bookmarks.size() + ")");
|
||||
|
||||
this.setIconBaseWithExtension(BOOKMARK_ICON_PATH);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||
if (ss == null) {
|
||||
ss = Sheet.createPropertiesSet();
|
||||
s.put(ss);
|
||||
}
|
||||
|
||||
ss.put(new NodeProperty("Name",
|
||||
"Name",
|
||||
"no description",
|
||||
getName()));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return null; //v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Node representing mail folder content (mail messages)
|
||||
*/
|
||||
private class BookmarksChildrenNode extends ChildFactory<BlackboardArtifact> {
|
||||
|
||||
private List<BlackboardArtifact> bookmarks;
|
||||
|
||||
private BookmarksChildrenNode(List<BlackboardArtifact> bookmarks) {
|
||||
super();
|
||||
this.bookmarks = bookmarks;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||
list.addAll(bookmarks);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(BlackboardArtifact artifact) {
|
||||
BlackboardArtifactNode bookmarkNode = null;
|
||||
|
||||
int artifactTypeID = artifact.getArtifactTypeID();
|
||||
if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
final BlackboardArtifact sourceResult = Tags.getArtifactFromTag(artifact.getArtifactID());
|
||||
bookmarkNode = new BlackboardArtifactNode(artifact, BOOKMARK_ICON_PATH) {
|
||||
@Override
|
||||
public Action[] getActions(boolean bln) {
|
||||
//Action [] actions = super.getActions(bln); //To change body of generated methods, choose Tools | Templates.
|
||||
Action[] actions = new Action[1];
|
||||
actions[0] = new AbstractAction("View Source Result") {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
//open the source artifact in dir tree
|
||||
if (sourceResult != null) {
|
||||
BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class);
|
||||
v.viewArtifact(sourceResult);
|
||||
}
|
||||
}
|
||||
};
|
||||
return actions;
|
||||
}
|
||||
};
|
||||
|
||||
//add custom property
|
||||
final String NO_DESCR = "no description";
|
||||
String resultType = sourceResult.getDisplayName();
|
||||
NodeProperty resultTypeProp = new NodeProperty("Source Result Type",
|
||||
"Result Type",
|
||||
NO_DESCR,
|
||||
resultType);
|
||||
bookmarkNode.addNodeProperty(resultTypeProp);
|
||||
|
||||
} else {
|
||||
//file bookmark, no additional action
|
||||
bookmarkNode = new BlackboardArtifactNode(artifact, BOOKMARK_ICON_PATH);
|
||||
|
||||
}
|
||||
return bookmarkNode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Links existing blackboard artifact (a tag) to this artifact. Linkage is
|
||||
* made using TSK_TAGGED_ARTIFACT attribute.
|
||||
*/
|
||||
void addArtifactTag(BlackboardArtifact art, BlackboardArtifact tag) throws TskCoreException {
|
||||
if (art.equals(tag)) {
|
||||
throw new TskCoreException("Cannot tag the same artifact: id" + art.getArtifactID());
|
||||
}
|
||||
BlackboardAttribute attrLink = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID(),
|
||||
"", art.getArtifactID());
|
||||
tag.addAttribute(attrLink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tag artifacts linked to the artifact
|
||||
*
|
||||
* @param art artifact to get tags for
|
||||
* @return list of children artifacts or an empty list
|
||||
* @throws TskCoreException exception thrown if a critical error occurs
|
||||
* within tsk core and child artifact could not be queried
|
||||
*/
|
||||
List<BlackboardArtifact> getTagArtifacts(BlackboardArtifact art) throws TskCoreException {
|
||||
return skCase.getBlackboardArtifacts(ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT, art.getArtifactID());
|
||||
}
|
||||
}
|
||||
92
Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java
Executable file
92
Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java
Executable file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.datamodel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.actions.DeleteContentTagAction;
|
||||
import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Instances of this class wrap ContentTag objects. In the Autopsy
|
||||
* presentation of the SleuthKit data model, they are leaf nodes of a tree
|
||||
* consisting of content and blackboard artifact tags, grouped first by tag
|
||||
* type, then by tag name.
|
||||
*/
|
||||
public class ContentTagNode extends DisplayableItemNode {
|
||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/blue-tag-icon-16.png";
|
||||
private final ContentTag tag;
|
||||
|
||||
public ContentTagNode(ContentTag tag) {
|
||||
super(Children.LEAF, Lookups.fixed(tag, tag.getContent()));
|
||||
super.setName(tag.getContent().getName());
|
||||
super.setDisplayName(tag.getContent().getName());
|
||||
this.setIconBaseWithExtension(ICON_PATH);
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet propertySheet = super.createSheet();
|
||||
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
|
||||
if (properties == null) {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
propertySheet.put(properties);
|
||||
}
|
||||
|
||||
properties.put(new NodeProperty("File", "File", "", tag.getContent().getName()));
|
||||
String contentPath;
|
||||
try {
|
||||
contentPath = tag.getContent().getUniquePath();
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex);
|
||||
contentPath = "Unavailable";
|
||||
}
|
||||
properties.put(new NodeProperty("File Path", "File Path", "", contentPath));
|
||||
properties.put(new NodeProperty("Comment", "Comment", "", tag.getComment()));
|
||||
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action[] getActions(boolean context) {
|
||||
List<Action> actions = DataModelActionsFactory.getActions(tag.getContent(), false);
|
||||
actions.add(null); // Adds a menu item separator.
|
||||
actions.add(DeleteContentTagAction.getInstance());
|
||||
return actions.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
108
Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java
Executable file
108
Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java
Executable file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.datamodel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Instances of this class are are elements of a directory tree sub-tree
|
||||
* consisting of content and blackboard artifact tags, grouped first by tag type,
|
||||
* then by tag name.
|
||||
*/
|
||||
public class ContentTagTypeNode extends DisplayableItemNode {
|
||||
private static final String DISPLAY_NAME = "File Tags";
|
||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
|
||||
|
||||
public ContentTagTypeNode(TagName tagName) {
|
||||
super(Children.create(new ContentTagNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " " + DISPLAY_NAME));
|
||||
|
||||
long tagsCount = 0;
|
||||
try {
|
||||
tagsCount = Case.getCurrentCase().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(ContentTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get content tags count for " + tagName.getDisplayName() + " tag name", ex);
|
||||
}
|
||||
|
||||
super.setName(DISPLAY_NAME);
|
||||
super.setDisplayName(DISPLAY_NAME + " (" + tagsCount + ")");
|
||||
this.setIconBaseWithExtension(ICON_PATH);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet propertySheet = super.createSheet();
|
||||
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
|
||||
if (properties == null) {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
propertySheet.put(properties);
|
||||
}
|
||||
|
||||
properties.put(new NodeProperty("Name", "Name", "", getName()));
|
||||
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class ContentTagNodeFactory extends ChildFactory<ContentTag> {
|
||||
private final TagName tagName;
|
||||
|
||||
ContentTagNodeFactory(TagName tagName) {
|
||||
this.tagName = tagName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<ContentTag> keys) {
|
||||
// Use the content tags bearing the specified tag name as the keys.
|
||||
try {
|
||||
keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName));
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(ContentTagTypeNode.ContentTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(ContentTag key) {
|
||||
// The content tags to be wrapped are used as the keys.
|
||||
return new ContentTagNode(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,79 +20,106 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.util.Arrays;
|
||||
import java.util.Formatter;
|
||||
|
||||
/**
|
||||
* Helper methods for converting data.
|
||||
*/
|
||||
public class DataConversion {
|
||||
|
||||
public static String byteArrayToHex(byte[] array, int length, long offset, Font font) {
|
||||
final private static char[] hexArray = "0123456789ABCDEF".toCharArray();
|
||||
|
||||
/**
|
||||
* Return the hex-dump layout of the passed in byte array.
|
||||
* Deprecated because we don't need font
|
||||
* @param array Data to display
|
||||
* @param length Amount of data in array to display
|
||||
* @param arrayOffset Offset of where data in array begins as part of a bigger file (used for arrayOffset column)
|
||||
* @param font Font that will be used to display the text
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public static String byteArrayToHex(byte[] array, int length, long arrayOffset, Font font) {
|
||||
return byteArrayToHex(array, length, arrayOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hex-dump layout of the passed in byte array.
|
||||
* @param array Data to display
|
||||
* @param length Amount of data in array to display
|
||||
* @param arrayOffset Offset of where data in array begins as part of a bigger file (used for arrayOffset column)
|
||||
* @return
|
||||
*/
|
||||
public static String byteArrayToHex(byte[] array, int length, long arrayOffset) {
|
||||
if (array == null) {
|
||||
return "";
|
||||
} else {
|
||||
String base = new String(array, 0, length);
|
||||
}
|
||||
else {
|
||||
StringBuilder outputStringBuilder = new StringBuilder();
|
||||
|
||||
// loop through the file in 16-byte increments
|
||||
for (int curOffset = 0; curOffset < length; curOffset += 16) {
|
||||
// how many bytes are we displaying on this line
|
||||
int lineLen = 16;
|
||||
if (length - curOffset < 16) {
|
||||
lineLen = length - curOffset;
|
||||
}
|
||||
|
||||
// print the offset column
|
||||
//outputStringBuilder.append("0x");
|
||||
outputStringBuilder.append(String.format("0x%08x: ", arrayOffset + curOffset));
|
||||
//outputStringBuilder.append(": ");
|
||||
|
||||
StringBuilder buff = new StringBuilder();
|
||||
int count = 0;
|
||||
int extra = base.length() % 16;
|
||||
String sub = "";
|
||||
char subchar;
|
||||
|
||||
//commented out code can be used as a base for generating hex length based on
|
||||
//offset/length/file size
|
||||
//String hex = Long.toHexString(length + offset);
|
||||
//double hexMax = Math.pow(16, hex.length());
|
||||
double hexMax = Math.pow(16, 6);
|
||||
while (count < base.length() - extra) {
|
||||
buff.append("0x");
|
||||
buff.append(Long.toHexString((long) (offset + count + hexMax)).substring(1));
|
||||
buff.append(": ");
|
||||
// print the hex columns
|
||||
for (int i = 0; i < 16; i++) {
|
||||
buff.append(Integer.toHexString((((int) base.charAt(count + i)) & 0xff) + 256).substring(1).toUpperCase());
|
||||
buff.append(" ");
|
||||
if (i == 7) {
|
||||
buff.append(" ");
|
||||
if (i < lineLen) {
|
||||
int v = array[curOffset + i] & 0xFF;
|
||||
outputStringBuilder.append(hexArray[v >>> 4]);
|
||||
outputStringBuilder.append(hexArray[v & 0x0F]);
|
||||
}
|
||||
else {
|
||||
outputStringBuilder.append(" ");
|
||||
}
|
||||
|
||||
// someday we'll offer the option of these two styles...
|
||||
if (true) {
|
||||
outputStringBuilder.append(" ");
|
||||
if (i % 4 == 3) {
|
||||
outputStringBuilder.append(" ");
|
||||
}
|
||||
if (i == 7) {
|
||||
outputStringBuilder.append(" ");
|
||||
}
|
||||
}
|
||||
// xxd style
|
||||
else {
|
||||
if (i % 2 == 1) {
|
||||
outputStringBuilder.append(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
sub = base.substring(count, count + 16);
|
||||
|
||||
outputStringBuilder.append(" ");
|
||||
|
||||
// print the ascii columns
|
||||
String ascii = new String(array, curOffset, lineLen);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
subchar = sub.charAt(i);
|
||||
if (!font.canDisplay(subchar)) {
|
||||
sub.replace(subchar, '.');
|
||||
}
|
||||
|
||||
// replace all unprintable characters with "."
|
||||
int dec = (int) subchar;
|
||||
if (dec < 32 || dec > 126) {
|
||||
sub = sub.replace(subchar, '.');
|
||||
char c = ' ';
|
||||
if (i < lineLen) {
|
||||
c = ascii.charAt(i);
|
||||
int dec = (int) c;
|
||||
|
||||
if (dec < 32 || dec > 126) {
|
||||
c = '.';
|
||||
}
|
||||
}
|
||||
outputStringBuilder.append(c);
|
||||
}
|
||||
buff.append(" " + sub + "\n");
|
||||
count += 16;
|
||||
|
||||
|
||||
outputStringBuilder.append("\n");
|
||||
}
|
||||
if (base.length() % 16 != 0) {
|
||||
buff.append("0x" + Long.toHexString((long) (offset + count + hexMax)).substring(1) + ": ");
|
||||
}
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i < extra) {
|
||||
buff.append(Integer.toHexString((((int) base.charAt(count + i)) & 0xff) + 256).substring(1) + " ");
|
||||
} else {
|
||||
buff.append(" ");
|
||||
}
|
||||
if (i == 7) {
|
||||
buff.append(" ");
|
||||
}
|
||||
}
|
||||
sub = base.substring(count, count + extra);
|
||||
for (int i = 0; i < extra; i++) {
|
||||
subchar = sub.charAt(i);
|
||||
if (!font.canDisplay(subchar)) {
|
||||
sub.replace(subchar, '.');
|
||||
}
|
||||
}
|
||||
buff.append(" " + sub);
|
||||
return buff.toString();
|
||||
|
||||
return outputStringBuilder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
182
Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java
Executable file
182
Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java
Executable file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.DerivedFile;
|
||||
import org.sleuthkit.datamodel.Directory;
|
||||
import org.sleuthkit.datamodel.File;
|
||||
import org.sleuthkit.datamodel.LayoutFile;
|
||||
import org.sleuthkit.datamodel.LocalFile;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
|
||||
/**
|
||||
* This class provides methods for creating sets of actions for data model objects.
|
||||
*/
|
||||
// TODO: All of the methods below that deal with classes derived from AbstractFile are the same except for the creation of wrapper nodes to pass to actions.
|
||||
// 1. Do the types of the wrapper nodes really need to vary? If not, it would mean a single
|
||||
// static List<Action> getActions(AbstrctFile file, boolean isArtifactSource)
|
||||
// method could be implemented. If the different nodes are necessary, is it merely because of some misuse of the Visitor pattern somewhere?
|
||||
// 2. All of this would be much improved by not constructing nodes with actions, but this might be necessary with pushing of nodes rather than use of lookups to
|
||||
// handle selections.
|
||||
class DataModelActionsFactory {
|
||||
static List<Action> getActions(File file, boolean isArtifactSource) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), file));
|
||||
final FileNode fileNode = new FileNode(file);
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(new NewWindowViewAction("View in New Window", fileNode));
|
||||
actions.add(new ExternalViewerAction("Open in External Viewer", fileNode));
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(new HashSearchAction("Search for files with the same MD5 hash", fileNode));
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
if (isArtifactSource) {
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
}
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
static List<Action> getActions(LayoutFile file, boolean isArtifactSource) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), file));
|
||||
LayoutFileNode layoutFileNode = new LayoutFileNode(file);
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(new NewWindowViewAction("View in New Window", layoutFileNode));
|
||||
actions.add(new ExternalViewerAction("Open in External Viewer", layoutFileNode));
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(ExtractAction.getInstance());//
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
if (isArtifactSource) {
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
}
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
static List<Action> getActions(Directory directory, boolean isArtifactSource) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), directory));
|
||||
DirectoryNode directoryNode = new DirectoryNode(directory);
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(new NewWindowViewAction("View in New Window", directoryNode));
|
||||
actions.add(new ExternalViewerAction("Open in External Viewer", directoryNode));
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
if (isArtifactSource) {
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
}
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
static List<Action> getActions(VirtualDirectory directory, boolean isArtifactSource) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), directory));
|
||||
VirtualDirectoryNode directoryNode = new VirtualDirectoryNode(directory);
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(new NewWindowViewAction("View in New Window", directoryNode));
|
||||
actions.add(new ExternalViewerAction("Open in External Viewer", directoryNode));
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
if (isArtifactSource) {
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
}
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
static List<Action> getActions(LocalFile file, boolean isArtifactSource) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), file));
|
||||
final LocalFileNode localFileNode = new LocalFileNode(file);
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(new NewWindowViewAction("View in New Window", localFileNode));
|
||||
actions.add(new ExternalViewerAction("Open in External Viewer", localFileNode));
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
if (isArtifactSource) {
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
}
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
static List<Action> getActions(DerivedFile file, boolean isArtifactSource) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), file));
|
||||
final LocalFileNode localFileNode = new LocalFileNode(file);
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(new NewWindowViewAction("View in New Window", localFileNode));
|
||||
actions.add(new ExternalViewerAction("Open in External Viewer", localFileNode));
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
if (isArtifactSource) {
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
}
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
static List<Action> getActions(Content content, boolean isArtifactSource) {
|
||||
if (content instanceof File) {
|
||||
return getActions((File)content, isArtifactSource);
|
||||
}
|
||||
else if (content instanceof LayoutFile) {
|
||||
return getActions((LayoutFile)content, isArtifactSource);
|
||||
}
|
||||
else if (content instanceof Directory) {
|
||||
return getActions((Directory)content, isArtifactSource);
|
||||
}
|
||||
else if (content instanceof VirtualDirectory) {
|
||||
return getActions((VirtualDirectory)content, isArtifactSource);
|
||||
}
|
||||
else if (content instanceof LocalFile) {
|
||||
return getActions((LocalFile)content, isArtifactSource);
|
||||
}
|
||||
else if (content instanceof DerivedFile) {
|
||||
return getActions((DerivedFile)content, isArtifactSource);
|
||||
}
|
||||
else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,10 +39,10 @@ public class DataSourcesNode extends DisplayableItemNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
|
||||
@@ -109,10 +109,10 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@@ -199,11 +199,6 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
||||
@@ -1,97 +1,99 @@
|
||||
/*
|
||||
* 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.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Directory;
|
||||
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
||||
|
||||
/**
|
||||
* This class is used to represent the "Node" for the directory. Its children
|
||||
* are more directories.
|
||||
*/
|
||||
public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
|
||||
|
||||
public static final String DOTDOTDIR = "[parent folder]";
|
||||
public static final String DOTDIR = "[current folder]";
|
||||
|
||||
public DirectoryNode(Directory dir) {
|
||||
this(dir, true);
|
||||
|
||||
setIcon(dir);
|
||||
}
|
||||
|
||||
public DirectoryNode(AbstractFile dir, boolean directoryBrowseMode) {
|
||||
super(dir, directoryBrowseMode);
|
||||
|
||||
setIcon(dir);
|
||||
}
|
||||
|
||||
private void setIcon(AbstractFile dir) {
|
||||
// set name, display name, and icon
|
||||
if (dir.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-deleted.png");
|
||||
} else {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/Folder-icon.png");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Right click action for this node
|
||||
*
|
||||
* @param popup
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Action[] getActions(boolean popup) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
if (!getDirectoryBrowseMode()) {
|
||||
actions.add(new ViewContextAction("View File in Directory", this));
|
||||
actions.add(null); // creates a menu separator
|
||||
}
|
||||
actions.add(new NewWindowViewAction("View in New Window", this));
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
return actions.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(ContentNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 - 2013 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.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Directory;
|
||||
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
||||
|
||||
/**
|
||||
* This class is used to represent the "Node" for the directory. Its children
|
||||
* are more directories.
|
||||
*/
|
||||
public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
|
||||
|
||||
public static final String DOTDOTDIR = "[parent folder]";
|
||||
public static final String DOTDIR = "[current folder]";
|
||||
|
||||
public DirectoryNode(Directory dir) {
|
||||
this(dir, true);
|
||||
|
||||
setIcon(dir);
|
||||
}
|
||||
|
||||
public DirectoryNode(AbstractFile dir, boolean directoryBrowseMode) {
|
||||
super(dir, directoryBrowseMode);
|
||||
|
||||
setIcon(dir);
|
||||
}
|
||||
|
||||
private void setIcon(AbstractFile dir) {
|
||||
// set name, display name, and icon
|
||||
if (dir.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-deleted.png");
|
||||
} else {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/Folder-icon.png");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Right click action for this node
|
||||
*
|
||||
* @param popup
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Action[] getActions(boolean popup) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
if (!getDirectoryBrowseMode()) {
|
||||
actions.add(new ViewContextAction("View File in Directory", this));
|
||||
actions.add(null); // creates a menu separator
|
||||
}
|
||||
actions.add(new NewWindowViewAction("View in New Window", this));
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(ContentNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011 - 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -18,12 +18,9 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.datatransfer.PasteType;
|
||||
|
||||
|
||||
/**
|
||||
* Interface for all displayable Nodes
|
||||
@@ -37,35 +34,7 @@ public abstract class DisplayableItemNode extends AbstractNode {
|
||||
public DisplayableItemNode(Children children, Lookup lookup) {
|
||||
super(children, lookup);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Possible sub-implementations
|
||||
*/
|
||||
public enum TYPE {
|
||||
CONTENT, ///< content node, such as file, image
|
||||
ARTIFACT, ///< artifact data node
|
||||
META, ///< top-level category node, such as view, filters, etc.
|
||||
};
|
||||
|
||||
/**
|
||||
* Get possible subtype of the displayable item node
|
||||
* @return
|
||||
*/
|
||||
public abstract TYPE getDisplayableItemNodeType();
|
||||
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visitor pattern support.
|
||||
*
|
||||
* @param v visitor
|
||||
* @return visitor's visit return value
|
||||
*/
|
||||
public abstract <T> T accept(DisplayableItemNodeVisitor<T> v);
|
||||
|
||||
|
||||
|
||||
|
||||
abstract public boolean isLeafTypeNode();
|
||||
public abstract <T> T accept(DisplayableItemNodeVisitor<T> v);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011 - 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -30,12 +30,10 @@ import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode;
|
||||
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsKeywordNode;
|
||||
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsListNode;
|
||||
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags.TagsRootNode;
|
||||
import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode;
|
||||
|
||||
/**
|
||||
* Visitor pattern for DisplayableItemNodes
|
||||
* Visitor pattern implementation for DisplayableItemNodes
|
||||
*/
|
||||
public interface DisplayableItemNodeVisitor<T> {
|
||||
|
||||
@@ -85,11 +83,17 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
|
||||
T visit(EmailExtractedFolderNode eefn);
|
||||
|
||||
T visit(TagsRootNode bksrn);
|
||||
T visit(TagsNode node);
|
||||
|
||||
T visit(TagsNodeRoot bksrn);
|
||||
T visit(TagNameNode node);
|
||||
|
||||
T visit(TagNodeRoot tnr);
|
||||
T visit(ContentTagTypeNode node);
|
||||
|
||||
T visit(ContentTagNode node);
|
||||
|
||||
T visit(BlackboardArtifactTagTypeNode node);
|
||||
|
||||
T visit(BlackboardArtifactTagNode node);
|
||||
|
||||
T visit(ViewsNode vn);
|
||||
|
||||
@@ -265,18 +269,33 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(TagsRootNode bksrn) {
|
||||
return defaultVisit(bksrn);
|
||||
public T visit(TagsNode node) {
|
||||
return defaultVisit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(TagsNodeRoot bksnr) {
|
||||
return defaultVisit(bksnr);
|
||||
public T visit(TagNameNode node) {
|
||||
return defaultVisit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(TagNodeRoot tnr) {
|
||||
return defaultVisit(tnr);
|
||||
public T visit(ContentTagTypeNode node) {
|
||||
return defaultVisit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(ContentTagNode node) {
|
||||
return defaultVisit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(BlackboardArtifactTagTypeNode node) {
|
||||
return defaultVisit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(BlackboardArtifactTagNode node) {
|
||||
return defaultVisit(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,10 +133,10 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
//return v.visit(this);
|
||||
@@ -215,10 +215,10 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@@ -272,11 +272,6 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account-icon-16.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
@@ -294,6 +289,11 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@@ -337,11 +337,6 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-16.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
||||
@@ -38,6 +38,11 @@ public class ExtractedContentNode extends DisplayableItemNode {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@@ -58,9 +63,4 @@ public class ExtractedContentNode extends DisplayableItemNode {
|
||||
NAME));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,180 +1,177 @@
|
||||
/*
|
||||
* 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.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
||||
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
||||
|
||||
/**
|
||||
* This class is used to represent the "Node" for the file. It may have derived
|
||||
* files children.
|
||||
*/
|
||||
public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
||||
|
||||
/**
|
||||
* @param file underlying Content
|
||||
*/
|
||||
public FileNode(AbstractFile file) {
|
||||
this(file, true);
|
||||
|
||||
setIcon(file);
|
||||
}
|
||||
|
||||
public FileNode(AbstractFile file, boolean directoryBrowseMode) {
|
||||
super(file, directoryBrowseMode);
|
||||
|
||||
setIcon(file);
|
||||
}
|
||||
|
||||
private void setIcon(AbstractFile file) {
|
||||
// set name, display name, and icon
|
||||
if (file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
|
||||
if (file.getType().equals(TSK_DB_FILES_TYPE_ENUM.CARVED)) {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/carved-file-icon-16.png");
|
||||
} else {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png");
|
||||
}
|
||||
} else {
|
||||
this.setIconBaseWithExtension(getIconForFileType(file));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Right click action for this node
|
||||
*
|
||||
* @param popup
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Action[] getActions(boolean popup) {
|
||||
List<Action> actionsList = new ArrayList<>();
|
||||
if (!this.getDirectoryBrowseMode()) {
|
||||
actionsList.add(new ViewContextAction("View File in Directory", this));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
}
|
||||
actionsList.add(new NewWindowViewAction("View in New Window", this));
|
||||
actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(ExtractAction.getInstance());
|
||||
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(TagAbstractFileAction.getInstance());
|
||||
return actionsList.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(ContentNodeVisitor< T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor< T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
// Given a file, returns the correct icon for said
|
||||
// file based off it's extension
|
||||
static String getIconForFileType(AbstractFile file) {
|
||||
// Get the name, extension
|
||||
String name = file.getName();
|
||||
int dotIndex = name.lastIndexOf(".");
|
||||
if (dotIndex == -1) {
|
||||
return "org/sleuthkit/autopsy/images/file-icon.png";
|
||||
}
|
||||
String ext = name.substring(dotIndex).toLowerCase();
|
||||
|
||||
// Images
|
||||
for (String s : FileTypeExtensions.getImageExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/image-file.png";
|
||||
}
|
||||
}
|
||||
// Videos
|
||||
for (String s : FileTypeExtensions.getVideoExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/video-file.png";
|
||||
}
|
||||
}
|
||||
// Audio Files
|
||||
for (String s : FileTypeExtensions.getAudioExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/audio-file.png";
|
||||
}
|
||||
}
|
||||
// Documents
|
||||
for (String s : FileTypeExtensions.getDocumentExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/doc-file.png";
|
||||
}
|
||||
}
|
||||
// Executables / System Files
|
||||
for (String s : FileTypeExtensions.getExecutableExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/exe-file.png";
|
||||
}
|
||||
}
|
||||
// Text Files
|
||||
for (String s : FileTypeExtensions.getTextExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/text-file.png";
|
||||
}
|
||||
}
|
||||
// Web Files
|
||||
for (String s : FileTypeExtensions.getWebExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/web-file.png";
|
||||
}
|
||||
}
|
||||
// PDFs
|
||||
for (String s : FileTypeExtensions.getPDFExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/pdf-file.png";
|
||||
}
|
||||
}
|
||||
// Archives
|
||||
for (String s : FileTypeExtensions.getArchiveExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/archive-file.png";
|
||||
}
|
||||
}
|
||||
// Else return the default
|
||||
return "org/sleuthkit/autopsy/images/file-icon.png";
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true; //false;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 - 2013 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.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
||||
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
||||
|
||||
/**
|
||||
* This class is used to represent the "Node" for the file. It may have derived
|
||||
* files children.
|
||||
*/
|
||||
public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
||||
|
||||
/**
|
||||
* @param file underlying Content
|
||||
*/
|
||||
public FileNode(AbstractFile file) {
|
||||
this(file, true);
|
||||
|
||||
setIcon(file);
|
||||
}
|
||||
|
||||
public FileNode(AbstractFile file, boolean directoryBrowseMode) {
|
||||
super(file, directoryBrowseMode);
|
||||
|
||||
setIcon(file);
|
||||
}
|
||||
|
||||
private void setIcon(AbstractFile file) {
|
||||
// set name, display name, and icon
|
||||
if (file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
|
||||
if (file.getType().equals(TSK_DB_FILES_TYPE_ENUM.CARVED)) {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/carved-file-icon-16.png");
|
||||
} else {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png");
|
||||
}
|
||||
} else {
|
||||
this.setIconBaseWithExtension(getIconForFileType(file));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Right click action for this node
|
||||
*
|
||||
* @param popup
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Action[] getActions(boolean popup) {
|
||||
List<Action> actionsList = new ArrayList<>();
|
||||
if (!this.getDirectoryBrowseMode()) {
|
||||
actionsList.add(new ViewContextAction("View File in Directory", this));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
}
|
||||
actionsList.add(new NewWindowViewAction("View in New Window", this));
|
||||
actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(ExtractAction.getInstance());
|
||||
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(AddContentTagAction.getInstance());
|
||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actionsList.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(ContentNodeVisitor< T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor< T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
// Given a file, returns the correct icon for said
|
||||
// file based off it's extension
|
||||
static String getIconForFileType(AbstractFile file) {
|
||||
// Get the name, extension
|
||||
String name = file.getName();
|
||||
int dotIndex = name.lastIndexOf(".");
|
||||
if (dotIndex == -1) {
|
||||
return "org/sleuthkit/autopsy/images/file-icon.png";
|
||||
}
|
||||
String ext = name.substring(dotIndex).toLowerCase();
|
||||
|
||||
// Images
|
||||
for (String s : FileTypeExtensions.getImageExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/image-file.png";
|
||||
}
|
||||
}
|
||||
// Videos
|
||||
for (String s : FileTypeExtensions.getVideoExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/video-file.png";
|
||||
}
|
||||
}
|
||||
// Audio Files
|
||||
for (String s : FileTypeExtensions.getAudioExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/audio-file.png";
|
||||
}
|
||||
}
|
||||
// Documents
|
||||
for (String s : FileTypeExtensions.getDocumentExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/doc-file.png";
|
||||
}
|
||||
}
|
||||
// Executables / System Files
|
||||
for (String s : FileTypeExtensions.getExecutableExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/exe-file.png";
|
||||
}
|
||||
}
|
||||
// Text Files
|
||||
for (String s : FileTypeExtensions.getTextExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/text-file.png";
|
||||
}
|
||||
}
|
||||
// Web Files
|
||||
for (String s : FileTypeExtensions.getWebExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/web-file.png";
|
||||
}
|
||||
}
|
||||
// PDFs
|
||||
for (String s : FileTypeExtensions.getPDFExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/pdf-file.png";
|
||||
}
|
||||
}
|
||||
// Archives
|
||||
for (String s : FileTypeExtensions.getArchiveExtensions()) {
|
||||
if (ext.equals(s)) {
|
||||
return "org/sleuthkit/autopsy/images/archive-file.png";
|
||||
}
|
||||
}
|
||||
// Else return the default
|
||||
return "org/sleuthkit/autopsy/images/file-icon.png";
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -111,10 +111,10 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
|
||||
return DisplayableItemNode.TYPE.META;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@@ -201,11 +201,6 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
|
||||
return DisplayableItemNode.TYPE.META;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
||||
@@ -78,11 +78,6 @@ public class FileTypeNode extends DisplayableItemNode {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
||||
@@ -52,6 +52,11 @@ public class FileTypesNode extends DisplayableItemNode {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@@ -72,9 +77,4 @@ public class FileTypesNode extends DisplayableItemNode {
|
||||
getName()));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,43 @@ public class HashsetHits implements AutopsyVisitableItem {
|
||||
}
|
||||
}
|
||||
|
||||
static public String getList(SleuthkitCase skCase, long objId) {
|
||||
ResultSet rs = null;
|
||||
String strList = "";
|
||||
|
||||
try {
|
||||
int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
|
||||
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID();
|
||||
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id "
|
||||
+ "FROM blackboard_attributes,blackboard_artifacts WHERE "
|
||||
+ "attribute_type_id=" + setNameId
|
||||
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id"
|
||||
+ " AND blackboard_artifacts.artifact_type_id=" + artId
|
||||
+ " AND blackboard_artifacts.obj_id=" + objId;
|
||||
rs = skCase.runQuery(query);
|
||||
int i = 0;
|
||||
while (rs.next()) {
|
||||
if (i++ > 0) {
|
||||
strList += ", ";
|
||||
}
|
||||
strList += rs.getString("value_text");
|
||||
}
|
||||
|
||||
} catch (SQLException ex) {
|
||||
logger.log(Level.WARNING, "SQL Exception occurred: ", ex);
|
||||
}
|
||||
finally {
|
||||
if (rs != null) {
|
||||
try {
|
||||
skCase.closeRunQuery(rs);
|
||||
} catch (SQLException ex) {
|
||||
logger.log(Level.WARNING, "Error closing result set after getting hashset hits", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return strList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@@ -113,10 +150,10 @@ public class HashsetHits implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@@ -163,11 +200,6 @@ public class HashsetHits implements AutopsyVisitableItem {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
||||
@@ -56,11 +56,6 @@ public class ImageNode extends AbstractContentNode<Image> {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hard-drive-icon.jpg");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Right click action for this node
|
||||
*
|
||||
@@ -98,6 +93,11 @@ public class ImageNode extends AbstractContentNode<Image> {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
|
||||
@@ -171,16 +171,16 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
//logger.info("Process took " + (finish-start) + " ms" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
@@ -231,11 +231,6 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
@@ -259,6 +254,11 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@@ -312,11 +312,6 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011 - 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -24,10 +24,11 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import org.sleuthkit.datamodel.LayoutFile;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
@@ -62,11 +63,6 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
@@ -95,6 +91,11 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@@ -102,13 +103,14 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
||||
|
||||
@Override
|
||||
public Action[] getActions(boolean context) {
|
||||
List<Action> actionsList = new ArrayList<Action>();
|
||||
List<Action> actionsList = new ArrayList<>();
|
||||
actionsList.add(new NewWindowViewAction("View in New Window", this));
|
||||
actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(ExtractAction.getInstance());
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(TagAbstractFileAction.getInstance());
|
||||
actionsList.add(AddContentTagAction.getInstance());
|
||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actionsList.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.TYPE;
|
||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
|
||||
/**
|
||||
@@ -55,11 +55,6 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
@@ -92,7 +87,8 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
||||
actionsList.add(ExtractAction.getInstance());
|
||||
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(TagAbstractFileAction.getInstance());
|
||||
actionsList.add(AddContentTagAction.getInstance());
|
||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actionsList.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,11 +79,6 @@ public class RecentFilesFilterNode extends DisplayableItemNode {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
||||
@@ -42,10 +42,10 @@ public class RecentFilesNode extends DisplayableItemNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
@@ -36,13 +35,18 @@ public class ResultsNode extends DisplayableItemNode {
|
||||
new KeywordHits(sleuthkitCase),
|
||||
new HashsetHits(sleuthkitCase),
|
||||
new EmailExtracted(sleuthkitCase),
|
||||
new Tags(sleuthkitCase) //TODO move to the top of the tree
|
||||
new TagsNodeKey()
|
||||
)), Lookups.singleton(NAME));
|
||||
setName(NAME);
|
||||
setDisplayName(NAME);
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@@ -63,9 +67,4 @@ public class ResultsNode extends DisplayableItemNode {
|
||||
NAME));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,19 +79,12 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
|
||||
case TSK_EMAIL_MSG:
|
||||
if (o instanceof EmailExtracted)
|
||||
this.refreshKey(o);
|
||||
break;
|
||||
|
||||
//TODO check
|
||||
break;
|
||||
case TSK_TAG_FILE:
|
||||
if (o instanceof Tags)
|
||||
case TSK_TAG_ARTIFACT:
|
||||
if (o instanceof TagsNodeKey)
|
||||
this.refreshKey(o);
|
||||
break;
|
||||
|
||||
//TODO check
|
||||
case TSK_TAG_ARTIFACT:
|
||||
if (o instanceof Tags)
|
||||
this.refreshKey(o);
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
if (o instanceof ExtractedContent)
|
||||
this.refreshKey(o);
|
||||
@@ -105,7 +98,7 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
|
||||
this.refreshKey(o);
|
||||
else if (o instanceof EmailExtracted)
|
||||
this.refreshKey(o);
|
||||
else if (o instanceof Tags)
|
||||
else if (o instanceof TagsNodeKey)
|
||||
this.refreshKey(o);
|
||||
else if (o instanceof ExtractedContent)
|
||||
this.refreshKey(o);
|
||||
|
||||
123
Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java
Executable file
123
Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java
Executable file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.datamodel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Instances of this class are elements of Node hierarchies consisting of
|
||||
* content and blackboard artifact tags, grouped first by tag type, then by
|
||||
* tag name.
|
||||
*/
|
||||
public class TagNameNode extends DisplayableItemNode {
|
||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
|
||||
private static final String BOOKMARK_TAG_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png";
|
||||
private final TagName tagName;
|
||||
|
||||
public TagNameNode(TagName tagName) {
|
||||
super(Children.create(new TagTypeNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " Tags"));
|
||||
this.tagName = tagName;
|
||||
|
||||
long tagsCount = 0;
|
||||
try {
|
||||
tagsCount = Case.getCurrentCase().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
|
||||
tagsCount += Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex);
|
||||
}
|
||||
|
||||
super.setName(tagName.getDisplayName());
|
||||
super.setDisplayName(tagName.getDisplayName() + " (" + tagsCount + ")");
|
||||
if (tagName.getDisplayName().equals("Bookmark")) {
|
||||
setIconBaseWithExtension(BOOKMARK_TAG_ICON_PATH);
|
||||
}
|
||||
else {
|
||||
setIconBaseWithExtension(ICON_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet propertySheet = super.createSheet();
|
||||
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
|
||||
if (properties == null) {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
propertySheet.put(properties);
|
||||
}
|
||||
|
||||
properties.put(new NodeProperty("Name", "Name", tagName.getDescription(), getName()));
|
||||
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
// See classes derived from DisplayableItemNodeVisitor<AbstractNode>
|
||||
// for behavior added using the Visitor pattern.
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class TagTypeNodeFactory extends ChildFactory<String> {
|
||||
private static final String CONTENT_TAG_TYPE_NODE_KEY = "Content Tags";
|
||||
private static final String BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY = "Result Tags";
|
||||
private final TagName tagName;
|
||||
|
||||
TagTypeNodeFactory(TagName tagName) {
|
||||
this.tagName = tagName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<String> keys) {
|
||||
keys.add(CONTENT_TAG_TYPE_NODE_KEY);
|
||||
keys.add(BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(String key) {
|
||||
switch (key) {
|
||||
case CONTENT_TAG_TYPE_NODE_KEY:
|
||||
return new ContentTagTypeNode(tagName);
|
||||
case BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY:
|
||||
return new BlackboardArtifactTagTypeNode(tagName);
|
||||
default:
|
||||
Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "{0} not a recognized key", key);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,711 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.datamodel;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Support for tags in the directory tree. Tag nodes representing file and
|
||||
* result tags, encapsulate TSK_TAG_FILE and TSK_TAG_ARTIFACT typed artifacts.
|
||||
*
|
||||
* The class implements querying of data model and populating node hierarchy
|
||||
* using child factories.
|
||||
*
|
||||
*/
|
||||
public class Tags implements AutopsyVisitableItem {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Tags.class.getName());
|
||||
private static final String FILE_TAG_LABEL_NAME = "File Tags";
|
||||
private static final String RESULT_TAG_LABEL_NAME = "Result Tags";
|
||||
private SleuthkitCase skCase;
|
||||
public static final String NAME = "Tags";
|
||||
private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
|
||||
//bookmarks are specializations of tags
|
||||
public static final String BOOKMARK_TAG_NAME = "Bookmark";
|
||||
private static final String BOOKMARK_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png";
|
||||
private Map<BlackboardArtifact.ARTIFACT_TYPE, Map<String, List<BlackboardArtifact>>> tags;
|
||||
private static final String EMPTY_COMMENT = "";
|
||||
private static final String APP_SETTINGS_FILE_NAME = "app"; // @@@ TODO: Need a general app settings or user preferences file, this will do for now.
|
||||
private static final String TAG_NAMES_SETTING_KEY = "tag_names";
|
||||
private static final HashSet<String> appSettingTagNames = new HashSet<>();
|
||||
private static final StringBuilder tagNamesAppSetting = new StringBuilder();
|
||||
|
||||
// When this class is loaded, either create an new app settings file or
|
||||
// get the tag names setting from the existing app settings file.
|
||||
static {
|
||||
String setting = ModuleSettings.getConfigSetting(APP_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY);
|
||||
if (null != setting && !setting.isEmpty()) {
|
||||
// Make a speedy lookup for the tag names in the setting to aid in the
|
||||
// detection of new tag names.
|
||||
List<String> tagNamesFromAppSettings = Arrays.asList(setting.split(","));
|
||||
for (String tagName : tagNamesFromAppSettings) {
|
||||
appSettingTagNames.add(tagName);
|
||||
}
|
||||
|
||||
// Load the raw comma separated values list from the setting into a
|
||||
// string builder to facilitate adding new tag names to the list and writing
|
||||
// it back to the app settings file.
|
||||
tagNamesAppSetting.append(setting);
|
||||
}
|
||||
}
|
||||
|
||||
Tags(SleuthkitCase skCase) {
|
||||
this.skCase = skCase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Root of all Tag nodes. This node is shown directly under Results in the
|
||||
* directory tree.
|
||||
*/
|
||||
public class TagsRootNode extends DisplayableItemNode {
|
||||
|
||||
public TagsRootNode() {
|
||||
super(Children.create(new Tags.TagsRootChildren(), true), Lookups.singleton(NAME));
|
||||
super.setName(NAME);
|
||||
super.setDisplayName(NAME);
|
||||
this.setIconBaseWithExtension(TAG_ICON_PATH);
|
||||
initData();
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
try {
|
||||
// Get all file and artifact tags
|
||||
|
||||
//init data
|
||||
tags = new EnumMap<>(BlackboardArtifact.ARTIFACT_TYPE.class);
|
||||
tags.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, new HashMap<String, List<BlackboardArtifact>>());
|
||||
tags.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, new HashMap<String, List<BlackboardArtifact>>());
|
||||
|
||||
//populate
|
||||
for (BlackboardArtifact.ARTIFACT_TYPE artType : tags.keySet()) {
|
||||
final Map<String, List<BlackboardArtifact>> artTags = tags.get(artType);
|
||||
for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(artType)) {
|
||||
for (BlackboardAttribute attribute : artifact.getAttributes()) {
|
||||
if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) {
|
||||
String tagName = attribute.getValueString();
|
||||
if (artTags.containsKey(tagName)) {
|
||||
List<BlackboardArtifact> artifacts = artTags.get(tagName);
|
||||
artifacts.add(artifact);
|
||||
} else {
|
||||
List<BlackboardArtifact> artifacts = new ArrayList<>();
|
||||
artifacts.add(artifact);
|
||||
artTags.put(tagName, artifacts);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Count not initialize tag nodes", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||
if (ss == null) {
|
||||
ss = Sheet.createPropertiesSet();
|
||||
s.put(ss);
|
||||
}
|
||||
|
||||
ss.put(new NodeProperty("Name",
|
||||
"Name",
|
||||
"no description",
|
||||
getName()));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
|
||||
return DisplayableItemNode.TYPE.ARTIFACT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* bookmarks root child node creating types of bookmarks nodes
|
||||
*/
|
||||
private class TagsRootChildren extends ChildFactory<BlackboardArtifact.ARTIFACT_TYPE> {
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<BlackboardArtifact.ARTIFACT_TYPE> list) {
|
||||
for (BlackboardArtifact.ARTIFACT_TYPE artType : tags.keySet()) {
|
||||
list.add(artType);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(BlackboardArtifact.ARTIFACT_TYPE key) {
|
||||
return new TagsNodeRoot(key, tags.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag node representation (file or result)
|
||||
*/
|
||||
public class TagsNodeRoot extends DisplayableItemNode {
|
||||
|
||||
TagsNodeRoot(BlackboardArtifact.ARTIFACT_TYPE tagType, Map<String, List<BlackboardArtifact>> subTags) {
|
||||
super(Children.create(new TagRootChildren(tagType, subTags), true), Lookups.singleton(tagType.getDisplayName()));
|
||||
|
||||
String name = null;
|
||||
if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)) {
|
||||
name = FILE_TAG_LABEL_NAME;
|
||||
} else if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) {
|
||||
name = RESULT_TAG_LABEL_NAME;
|
||||
}
|
||||
|
||||
super.setName(name);
|
||||
super.setDisplayName(name + " (" + subTags.values().size() + ")");
|
||||
|
||||
this.setIconBaseWithExtension(TAG_ICON_PATH);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||
if (ss == null) {
|
||||
ss = Sheet.createPropertiesSet();
|
||||
s.put(ss);
|
||||
}
|
||||
|
||||
ss.put(new NodeProperty("Name",
|
||||
"Name",
|
||||
"no description",
|
||||
getName()));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Child factory to add all the Tag artifacts to a TagsRootNode with the tag
|
||||
* name.
|
||||
*/
|
||||
private class TagRootChildren extends ChildFactory<String> {
|
||||
|
||||
private Map<String, List<BlackboardArtifact>> subTags;
|
||||
private BlackboardArtifact.ARTIFACT_TYPE tagType;
|
||||
|
||||
TagRootChildren(BlackboardArtifact.ARTIFACT_TYPE tagType, Map<String, List<BlackboardArtifact>> subTags) {
|
||||
super();
|
||||
this.tagType = tagType;
|
||||
this.subTags = subTags;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<String> list) {
|
||||
list.addAll(subTags.keySet());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(String key) {
|
||||
return new Tags.TagNodeRoot(tagType, key, subTags.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Node for each unique tag name. Shown directly under Results > Tags.
|
||||
*/
|
||||
public class TagNodeRoot extends DisplayableItemNode {
|
||||
|
||||
TagNodeRoot(BlackboardArtifact.ARTIFACT_TYPE tagType, String tagName, List<BlackboardArtifact> artifacts) {
|
||||
super(Children.create(new Tags.TagsChildrenNode(tagType, tagName, artifacts), true), Lookups.singleton(tagName));
|
||||
|
||||
super.setName(tagName);
|
||||
super.setDisplayName(tagName + " (" + artifacts.size() + ")");
|
||||
|
||||
if (tagName.equals(BOOKMARK_TAG_NAME)) {
|
||||
this.setIconBaseWithExtension(BOOKMARK_ICON_PATH);
|
||||
} else {
|
||||
this.setIconBaseWithExtension(TAG_ICON_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||
if (ss == null) {
|
||||
ss = Sheet.createPropertiesSet();
|
||||
s.put(ss);
|
||||
}
|
||||
|
||||
ss.put(new NodeProperty("Name",
|
||||
"Name",
|
||||
"no description",
|
||||
getName()));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
|
||||
return DisplayableItemNode.TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Node representing an individual Tag artifact. For each TagsNodeRoot under
|
||||
* Results > Tags, this is one of the nodes listed in the result viewer.
|
||||
*/
|
||||
private class TagsChildrenNode extends ChildFactory<BlackboardArtifact> {
|
||||
|
||||
private List<BlackboardArtifact> artifacts;
|
||||
private BlackboardArtifact.ARTIFACT_TYPE tagType;
|
||||
private String tagName;
|
||||
|
||||
private TagsChildrenNode(BlackboardArtifact.ARTIFACT_TYPE tagType, String tagName, List<BlackboardArtifact> artifacts) {
|
||||
super();
|
||||
this.tagType = tagType;
|
||||
this.tagName = tagName;
|
||||
this.artifacts = artifacts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||
list.addAll(artifacts);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(final BlackboardArtifact artifact) {
|
||||
//create node with action
|
||||
BlackboardArtifactNode tagNode = null;
|
||||
|
||||
String iconPath;
|
||||
if (tagName.equals(BOOKMARK_TAG_NAME)) {
|
||||
iconPath = BOOKMARK_ICON_PATH;
|
||||
} else {
|
||||
iconPath = TAG_ICON_PATH;
|
||||
}
|
||||
|
||||
//create actions here where Tag logic belongs
|
||||
//instead of DataResultFilterNode w/visitors, which is much less pluggable and cluttered
|
||||
if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) {
|
||||
//in case of result tag, add a action by sublcassing bb art node
|
||||
//this action will be merged with other actions set DataResultFIlterNode
|
||||
//otherwise in case of
|
||||
tagNode = new BlackboardArtifactNode(artifact, iconPath) {
|
||||
@Override
|
||||
public Action[] getActions(boolean bln) {
|
||||
//Action [] actions = super.getActions(bln); //To change body of generated methods, choose Tools | Templates.
|
||||
Action[] actions = new Action[1];
|
||||
actions[0] = new AbstractAction("View Source Result") {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
//open the source artifact in dir tree
|
||||
BlackboardArtifact sourceArt = Tags.getArtifactFromTag(artifact.getArtifactID());
|
||||
if (sourceArt != null) {
|
||||
BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class);
|
||||
v.viewArtifact(sourceArt);
|
||||
}
|
||||
}
|
||||
};
|
||||
return actions;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
//for file tag, don't subclass to add the additional actions
|
||||
tagNode = new BlackboardArtifactNode(artifact, iconPath);
|
||||
}
|
||||
|
||||
//add some additional node properties
|
||||
int artifactTypeID = artifact.getArtifactTypeID();
|
||||
final String NO_DESCR = "no description";
|
||||
if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
BlackboardArtifact sourceResult = Tags.getArtifactFromTag(artifact.getArtifactID());
|
||||
String resultType = sourceResult.getDisplayName();
|
||||
|
||||
NodeProperty resultTypeProp = new NodeProperty("Source Result Type",
|
||||
"Result Type",
|
||||
NO_DESCR,
|
||||
resultType);
|
||||
|
||||
|
||||
tagNode.addNodeProperty(resultTypeProp);
|
||||
|
||||
}
|
||||
|
||||
return tagNode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tag for a file with TSK_TAG_NAME as tagName.
|
||||
*
|
||||
* @param file to create tag for
|
||||
* @param tagName TSK_TAG_NAME
|
||||
* @param comment the tag comment, or null if not present
|
||||
*/
|
||||
public static void createTag(AbstractFile file, String tagName, String comment) {
|
||||
try {
|
||||
final BlackboardArtifact bookArt = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
|
||||
List<BlackboardAttribute> attrs = new ArrayList<>();
|
||||
|
||||
|
||||
BlackboardAttribute attr1 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID(),
|
||||
"", tagName);
|
||||
attrs.add(attr1);
|
||||
|
||||
if (comment != null && !comment.isEmpty()) {
|
||||
BlackboardAttribute attr2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(),
|
||||
"", comment);
|
||||
attrs.add(attr2);
|
||||
}
|
||||
bookArt.addAttributes(attrs);
|
||||
|
||||
updateTagNamesAppSetting(tagName);
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to create tag for " + file.getName(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tag for an artifact with TSK_TAG_NAME as tagName.
|
||||
*
|
||||
* @param artifact to create tag for
|
||||
* @param tagName TSK_TAG_NAME
|
||||
* @param comment the tag comment or null if not present
|
||||
*/
|
||||
public static void createTag(BlackboardArtifact artifact, String tagName, String comment) {
|
||||
try {
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
SleuthkitCase skCase = currentCase.getSleuthkitCase();
|
||||
|
||||
AbstractFile file = skCase.getAbstractFileById(artifact.getObjectID());
|
||||
final BlackboardArtifact bookArt = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
|
||||
List<BlackboardAttribute> attrs = new ArrayList<>();
|
||||
|
||||
|
||||
BlackboardAttribute attr1 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID(),
|
||||
"", tagName);
|
||||
|
||||
if (comment != null && !comment.isEmpty()) {
|
||||
BlackboardAttribute attr2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(),
|
||||
"", comment);
|
||||
attrs.add(attr2);
|
||||
}
|
||||
|
||||
BlackboardAttribute attr3 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID(),
|
||||
"", artifact.getArtifactID());
|
||||
attrs.add(attr1);
|
||||
|
||||
attrs.add(attr3);
|
||||
bookArt.addAttributes(attrs);
|
||||
|
||||
updateTagNamesAppSetting(tagName);
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to create tag for artifact " + artifact.getArtifactID(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateTagNamesAppSetting(String tagName) {
|
||||
// If this tag name is not in the current tag names app setting...
|
||||
if (!appSettingTagNames.contains(tagName)) {
|
||||
// Add it to the lookup.
|
||||
appSettingTagNames.add(tagName);
|
||||
|
||||
// Add it to the setting and write the setting back to the app settings file.
|
||||
if (tagNamesAppSetting.length() != 0) {
|
||||
tagNamesAppSetting.append(",");
|
||||
}
|
||||
tagNamesAppSetting.append(tagName);
|
||||
ModuleSettings.setConfigSetting(APP_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY, tagNamesAppSetting.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a bookmark tag for a file.
|
||||
*
|
||||
* @param file to create bookmark tag for
|
||||
* @param comment the bookmark comment
|
||||
*/
|
||||
public static void createBookmark(AbstractFile file, String comment) {
|
||||
createTag(file, Tags.BOOKMARK_TAG_NAME, comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a bookmark tag for an artifact.
|
||||
*
|
||||
* @param artifact to create bookmark tag for
|
||||
* @param comment the bookmark comment
|
||||
*/
|
||||
public static void createBookmark(BlackboardArtifact artifact, String comment) {
|
||||
createTag(artifact, Tags.BOOKMARK_TAG_NAME, comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all the bookmarks.
|
||||
*
|
||||
* @return a list of all bookmark artifacts
|
||||
*/
|
||||
static List<BlackboardArtifact> getBookmarks() {
|
||||
try {
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
SleuthkitCase skCase = currentCase.getSleuthkitCase();
|
||||
return skCase.getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME, Tags.BOOKMARK_TAG_NAME);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to get list of artifacts from the case", ex);
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all the unique tag names associated with the current case plus any
|
||||
* tag names stored in the application settings file.
|
||||
*
|
||||
* @return A collection of tag names.
|
||||
*/
|
||||
public static TreeSet<String> getAllTagNames() {
|
||||
// Use a TreeSet<> so the union of the tag names from the two sources will be sorted.
|
||||
TreeSet<String> tagNames = getTagNamesFromCurrentCase();
|
||||
tagNames.addAll(appSettingTagNames);
|
||||
|
||||
// Make sure the book mark tag is always included.
|
||||
tagNames.add(BOOKMARK_TAG_NAME);
|
||||
|
||||
return tagNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all the unique tag names associated with the current case.
|
||||
* Uses a custom query for speed when dealing with thousands of tags.
|
||||
*
|
||||
* @return A collection of tag names.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static TreeSet<String> getTagNamesFromCurrentCase() {
|
||||
TreeSet<String> tagNames = new TreeSet<>();
|
||||
|
||||
ResultSet rs = null;
|
||||
SleuthkitCase skCase = null;
|
||||
try {
|
||||
skCase = Case.getCurrentCase().getSleuthkitCase();
|
||||
rs = skCase.runQuery("SELECT value_text"
|
||||
+ " FROM blackboard_attributes"
|
||||
+ " WHERE attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
|
||||
+ " GROUP BY value_text"
|
||||
+ " ORDER BY value_text");
|
||||
while (rs.next()) {
|
||||
tagNames.add(rs.getString("value_text"));
|
||||
}
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
// Case.getCurrentCase() throws IllegalStateException if there is no current autopsy case.
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to query the blackboard for tag names", ex);
|
||||
}
|
||||
finally {
|
||||
if (null != skCase && null != rs) {
|
||||
try {
|
||||
skCase.closeRunQuery(rs);
|
||||
} catch (SQLException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to close the query for blackboard for tag names", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the book mark tag is always included.
|
||||
tagNames.add(BOOKMARK_TAG_NAME);
|
||||
|
||||
return tagNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tag comment for a specified tag.
|
||||
*
|
||||
* @param tagArtifactId artifact id of the tag
|
||||
* @return the tag comment
|
||||
*/
|
||||
static String getCommentFromTag(long tagArtifactId) {
|
||||
try {
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
SleuthkitCase skCase = currentCase.getSleuthkitCase();
|
||||
|
||||
BlackboardArtifact artifact = skCase.getBlackboardArtifact(tagArtifactId);
|
||||
if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
|| artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
List<BlackboardAttribute> attributes = artifact.getAttributes();
|
||||
for (BlackboardAttribute att : attributes) {
|
||||
if (att.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) {
|
||||
return att.getValueString();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to get artifact " + tagArtifactId + " from case", ex);
|
||||
}
|
||||
|
||||
return EMPTY_COMMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the artifact for a result tag.
|
||||
*
|
||||
* @param tagArtifactId artifact id of the tag
|
||||
* @return the tag's artifact
|
||||
*/
|
||||
static BlackboardArtifact getArtifactFromTag(long tagArtifactId) {
|
||||
try {
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
SleuthkitCase skCase = currentCase.getSleuthkitCase();
|
||||
|
||||
BlackboardArtifact artifact = skCase.getBlackboardArtifact(tagArtifactId);
|
||||
if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
|| artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
List<BlackboardAttribute> attributes = artifact.getAttributes();
|
||||
for (BlackboardAttribute att : attributes) {
|
||||
if (att.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()) {
|
||||
return skCase.getBlackboardArtifact(att.getValueLong());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to get artifact " + tagArtifactId + " from case.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the tag names associated with either a tagged artifact or a tag artifact.
|
||||
*
|
||||
* @param artifact The artifact
|
||||
* @return A set of unique tag names
|
||||
*/
|
||||
public static HashSet<String> getUniqueTagNamesForArtifact(BlackboardArtifact artifact) {
|
||||
return getUniqueTagNamesForArtifact(artifact.getArtifactID(), artifact.getArtifactTypeID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the tag names associated with either a tagged artifact or a tag artifact.
|
||||
*
|
||||
* @param artifactID The ID of the artifact
|
||||
* @param artifactTypeID The ID of the artifact type
|
||||
* @return A set of unique tag names
|
||||
*/
|
||||
public static HashSet<String> getUniqueTagNamesForArtifact(long artifactID, int artifactTypeID) {
|
||||
HashSet<String> tagNames = new HashSet<>();
|
||||
|
||||
try {
|
||||
ArrayList<Long> tagArtifactIDs = new ArrayList<>();
|
||||
if (artifactTypeID == ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() ||
|
||||
artifactTypeID == ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
tagArtifactIDs.add(artifactID);
|
||||
} else {
|
||||
List<BlackboardArtifact> tags = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifacts(ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT, artifactID);
|
||||
for (BlackboardArtifact tag : tags) {
|
||||
tagArtifactIDs.add(tag.getArtifactID());
|
||||
}
|
||||
}
|
||||
|
||||
for (Long tagArtifactID : tagArtifactIDs) {
|
||||
String whereClause = "WHERE artifact_id = " + tagArtifactID + " AND attribute_type_id = " + ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID();
|
||||
List<BlackboardAttribute> attributes = Case.getCurrentCase().getSleuthkitCase().getMatchingAttributes(whereClause);
|
||||
for (BlackboardAttribute attr : attributes) {
|
||||
tagNames.add(attr.getValueString());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to get tags for artifact " + artifactID, ex);
|
||||
}
|
||||
|
||||
return tagNames;
|
||||
}
|
||||
}
|
||||
91
Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java
Executable file
91
Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java
Executable file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.datamodel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Instances of this class are the root nodes of tree that is a sub-tree of the
|
||||
* Autopsy presentation of the SleuthKit data model. The sub-tree consists of
|
||||
* content and blackboard artifact tags, grouped first by tag type, then by
|
||||
* tag name.
|
||||
*/
|
||||
public class TagsNode extends DisplayableItemNode {
|
||||
private static final String DISPLAY_NAME = "Tags";
|
||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
|
||||
|
||||
public TagsNode() {
|
||||
super(Children.create(new TagNameNodeFactory(), true), Lookups.singleton(DISPLAY_NAME));
|
||||
super.setName(DISPLAY_NAME);
|
||||
super.setDisplayName(DISPLAY_NAME);
|
||||
this.setIconBaseWithExtension(ICON_PATH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet propertySheet = super.createSheet();
|
||||
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
|
||||
if (properties == null) {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
propertySheet.put(properties);
|
||||
}
|
||||
|
||||
properties.put(new NodeProperty("Name", "Name", "", getName()));
|
||||
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
private static class TagNameNodeFactory extends ChildFactory<TagName> {
|
||||
@Override
|
||||
protected boolean createKeys(List<TagName> keys) {
|
||||
try {
|
||||
keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse());
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(TagNameNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(TagName key) {
|
||||
return new TagNameNode(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java
Executable file
34
Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java
Executable file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.datamodel;
|
||||
|
||||
/**
|
||||
* Instances of this class act as keys for use by instances of the
|
||||
* RootContentChildren class. RootContentChildren is a NetBeans child node
|
||||
* factory built on top of the NetBeans Children.Keys class.
|
||||
*/
|
||||
public class TagsNodeKey implements AutopsyVisitableItem {
|
||||
// Creation of a TagsNode object corresponding to a TagsNodeKey object is done
|
||||
// by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren
|
||||
// override of Children.Keys<T>.createNodes().
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,11 @@ public class ViewsNode extends DisplayableItemNode {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/views.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@@ -65,9 +70,4 @@ public class ViewsNode extends DisplayableItemNode {
|
||||
NAME));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011 - 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -24,10 +24,10 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
@@ -81,7 +81,7 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
@@ -118,11 +118,6 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
||||
@@ -100,13 +100,13 @@ public class VolumeNode extends AbstractContentNode<Volume> {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
}
|
||||
}
|
||||
|
||||
113
Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java
Executable file
113
Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java
Executable file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.directorytree;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactTagNode;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentTagTypeNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Instances of this class are elements in a sub-tree of the Autopsy
|
||||
* presentation of the SleuthKit data model. The sub-tree consists of content
|
||||
* and blackboard artifact tags, grouped first by tag type, then by tag name.
|
||||
*/
|
||||
public class BlackboardArtifactTagTypeNode extends DisplayableItemNode {
|
||||
private static final String DISPLAY_NAME = "Result Tags";
|
||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
|
||||
|
||||
public BlackboardArtifactTagTypeNode(TagName tagName) {
|
||||
super(Children.create(new BlackboardArtifactTagNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " " + DISPLAY_NAME));
|
||||
|
||||
long tagsCount = 0;
|
||||
try {
|
||||
tagsCount = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(BlackboardArtifactTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags count for " + tagName.getDisplayName() + " tag name", ex);
|
||||
}
|
||||
|
||||
super.setName(DISPLAY_NAME);
|
||||
super.setDisplayName(DISPLAY_NAME + " (" + tagsCount + ")");
|
||||
this.setIconBaseWithExtension(ICON_PATH);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet propertySheet = super.createSheet();
|
||||
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
|
||||
if (properties == null) {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
propertySheet.put(properties);
|
||||
}
|
||||
|
||||
properties.put(new NodeProperty("Name", "Name", "", getName()));
|
||||
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class BlackboardArtifactTagNodeFactory extends ChildFactory<BlackboardArtifactTag> {
|
||||
private final TagName tagName;
|
||||
|
||||
BlackboardArtifactTagNodeFactory(TagName tagName) {
|
||||
this.tagName = tagName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<BlackboardArtifactTag> keys) {
|
||||
try {
|
||||
// Use the blackboard artifact tags bearing the specified tag name as the keys.
|
||||
keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName));
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(BlackboardArtifactTagTypeNode.BlackboardArtifactTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(BlackboardArtifactTag key) {
|
||||
// The blackboard artifact tags to be wrapped are used as the keys.
|
||||
return new BlackboardArtifactTagNode(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,17 +47,3 @@ ImageDetailsPanel.imgSectorSizeLabel.text=Sector Size:
|
||||
ImageDetailsPanel.imgSectorSizeValue.text=...
|
||||
DirectoryTreeTopComponent.backButton.text=
|
||||
DirectoryTreeTopComponent.forwardButton.text=
|
||||
CreateTagDialog.cancelButton.text=Cancel
|
||||
CreateTagDialog.okButton.text=OK
|
||||
CreateTagDialog.tagNameField.text=
|
||||
CreateTagDialog.tagNameLabel.text=Tag Name:
|
||||
CreateTagDialog.preexistingLabel.text=Pre-existing Tags:
|
||||
CreateTagDialog.newTagPanel.border.title=New Tag
|
||||
TagAndCommentDialog.tagLabel.text=Tag:
|
||||
TagAndCommentDialog.tagCombo.toolTipText=Select tag to use
|
||||
TagAndCommentDialog.cancelButton.text=Cancel
|
||||
TagAndCommentDialog.okButton.text=OK
|
||||
TagAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank
|
||||
TagAndCommentDialog.commentText.text=
|
||||
TagAndCommentDialog.commentLabel.text=Comment:
|
||||
TagAndCommentDialog.newTagButton.text=New Tag
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.directorytree;
|
||||
|
||||
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.beans.PropertyVetoException;
|
||||
import java.util.ArrayList;
|
||||
@@ -33,10 +35,12 @@ import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.FilterNode;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType;
|
||||
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
|
||||
import org.sleuthkit.autopsy.datamodel.ArtifactTypeNode;
|
||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentTagTypeNode;
|
||||
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
|
||||
@@ -61,8 +65,7 @@ import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode;
|
||||
import org.sleuthkit.autopsy.datamodel.RecentFilesNode;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypesNode;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot;
|
||||
import org.sleuthkit.autopsy.datamodel.TagNameNode;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
@@ -168,6 +171,8 @@ public class DataResultFilterNode extends FilterNode {
|
||||
//set up actions for artifact node based on its Content object
|
||||
//TODO all actions need to be consolidated in single place!
|
||||
//they should be set in individual Node subclass and using a utility to get Actions per Content sub-type
|
||||
// TODO UPDATE: There is now a DataModelActionsFactory utility; also tags are no longer artifacts so conditionals
|
||||
// can be removed.
|
||||
|
||||
List<Action> actions = new ArrayList<>();
|
||||
|
||||
@@ -182,10 +187,13 @@ public class DataResultFilterNode extends FilterNode {
|
||||
|| artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
||||
actions.add(new ViewContextAction("View File in Directory", ban));
|
||||
} else {
|
||||
// if the artifact links to another file, add an action to go to
|
||||
// that file
|
||||
Content c = findLinked(ban);
|
||||
if (c != null) {
|
||||
actions.add(new ViewContextAction("View File in Directory", c));
|
||||
}
|
||||
// action to go to the source file of the artifact
|
||||
actions.add(new ViewContextAction("View Source File in Directory", ban));
|
||||
}
|
||||
File f = ban.getLookup().lookup(File.class);
|
||||
@@ -206,8 +214,9 @@ public class DataResultFilterNode extends FilterNode {
|
||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
}
|
||||
}
|
||||
if ((d = ban.getLookup().lookup(Directory.class)) != null) {
|
||||
@@ -222,8 +231,9 @@ public class DataResultFilterNode extends FilterNode {
|
||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
}
|
||||
}
|
||||
if ((vd = ban.getLookup().lookup(VirtualDirectory.class)) != null) {
|
||||
@@ -238,8 +248,9 @@ public class DataResultFilterNode extends FilterNode {
|
||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
}
|
||||
} else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) {
|
||||
LayoutFileNode lfn = new LayoutFileNode(lf);
|
||||
@@ -253,8 +264,9 @@ public class DataResultFilterNode extends FilterNode {
|
||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
}
|
||||
} else if ((locF = ban.getLookup().lookup(LocalFile.class)) != null
|
||||
|| (locF = ban.getLookup().lookup(DerivedFile.class)) != null) {
|
||||
@@ -269,8 +281,9 @@ public class DataResultFilterNode extends FilterNode {
|
||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,15 +417,20 @@ public class DataResultFilterNode extends FilterNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(TagNodeRoot tnr) {
|
||||
return openChild(tnr);
|
||||
public AbstractAction visit(TagNameNode node) {
|
||||
return openChild(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(TagsNodeRoot tnr) {
|
||||
return openChild(tnr);
|
||||
public AbstractAction visit(ContentTagTypeNode node) {
|
||||
return openChild(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(BlackboardArtifactTagTypeNode node) {
|
||||
return openChild(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(DirectoryNode dn) {
|
||||
if (dn.getDisplayName().equals(DirectoryNode.DOTDOTDIR)) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
@@ -804,7 +805,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
* Refreshes the nodes in the tree to reflect updates in the database should
|
||||
* be called in the gui thread
|
||||
*/
|
||||
void refreshTree(final BlackboardArtifact.ARTIFACT_TYPE... types) {
|
||||
public void refreshTree(final BlackboardArtifact.ARTIFACT_TYPE... types) {
|
||||
//save current selection
|
||||
Node selectedNode = getSelectedNode();
|
||||
final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
|
||||
@@ -856,38 +857,53 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
}
|
||||
|
||||
/**
|
||||
* Set selected node using the previously saved selection path to the
|
||||
* selected node
|
||||
* Set the selected node using a path to a previously selected node.
|
||||
*
|
||||
* @param path node path with node names
|
||||
* @param rootNodeName name of the root node to match or null if any
|
||||
* @param previouslySelectedNodePath Path to a previously selected node.
|
||||
* @param rootNodeName Name of the root node to match, may be null.
|
||||
*/
|
||||
private void setSelectedNode(final String[] path, final String rootNodeName) {
|
||||
if (path == null) {
|
||||
private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) {
|
||||
if (previouslySelectedNodePath == null) {
|
||||
return;
|
||||
}
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
if (path.length > 0 && (rootNodeName == null || path[0].equals(rootNodeName))) {
|
||||
try {
|
||||
Node newSelection = NodeOp.findPath(em.getRootContext(), path);
|
||||
|
||||
if (newSelection != null) {
|
||||
if (rootNodeName != null) {
|
||||
//called from tree auto refresh context
|
||||
//remove last from backlist, because auto select will result in duplication
|
||||
backList.pollLast();
|
||||
}
|
||||
em.setExploredContextAndSelection(newSelection, new Node[]{newSelection});
|
||||
if (previouslySelectedNodePath.length > 0 && (rootNodeName == null || previouslySelectedNodePath[0].equals(rootNodeName))) {
|
||||
Node selectedNode = null;
|
||||
ArrayList<String> selectedNodePath = new ArrayList<>(Arrays.asList(previouslySelectedNodePath));
|
||||
while (null == selectedNode && !selectedNodePath.isEmpty()) {
|
||||
try {
|
||||
selectedNode = NodeOp.findPath(em.getRootContext(), selectedNodePath.toArray(new String[0]));
|
||||
}
|
||||
catch (NodeNotFoundException ex) {
|
||||
// The selected node may have been deleted (e.g., a deleted tag), so truncate the path and try again.
|
||||
if (selectedNodePath.size() > 1) {
|
||||
selectedNodePath.remove(selectedNodePath.size() - 1);
|
||||
}
|
||||
else {
|
||||
StringBuilder nodePath = new StringBuilder();
|
||||
for (int i = 0; i < previouslySelectedNodePath.length; ++i) {
|
||||
nodePath.append(previouslySelectedNodePath[i]).append("/");
|
||||
}
|
||||
logger.log(Level.WARNING, "Failed to find any nodes to select on path " + nodePath.toString(), ex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null != selectedNode) {
|
||||
if (rootNodeName != null) {
|
||||
//called from tree auto refresh context
|
||||
//remove last from backlist, because auto select will result in duplication
|
||||
backList.pollLast();
|
||||
}
|
||||
try {
|
||||
em.setExploredContextAndSelection(selectedNode, new Node[]{selectedNode});
|
||||
}
|
||||
catch (PropertyVetoException ex) {
|
||||
logger.log(Level.WARNING, "Property veto from ExplorerManager setting selection to " + selectedNode.getName(), ex);
|
||||
}
|
||||
|
||||
// We need to set the selection, which will refresh dataresult and get rid of the oob exception
|
||||
} catch (NodeNotFoundException ex) {
|
||||
logger.log(Level.WARNING, "Node not found", ex);
|
||||
} catch (PropertyVetoException ex) {
|
||||
logger.log(Level.WARNING, "Property Veto", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011 - 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.directorytree;
|
||||
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
@@ -35,6 +36,7 @@ import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.ContentVisitor;
|
||||
@@ -100,40 +102,44 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
||||
|
||||
@Override
|
||||
public List<? extends Action> visit(final Directory d) {
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Action> visit(final VirtualDirectory d) {
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Action> visit(final DerivedFile d) {
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Action> visit(final LocalFile d) {
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
|
||||
List<Action> actions = new ArrayList<Action>();
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.directorytree;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.Collection;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.JMenuItem;
|
||||
import org.openide.util.Utilities;
|
||||
import org.openide.util.actions.Presenter;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
|
||||
public class TagAbstractFileAction extends AbstractAction implements Presenter.Popup {
|
||||
// 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 TagAbstractFileAction instance;
|
||||
|
||||
public static synchronized TagAbstractFileAction getInstance() {
|
||||
if (null == instance) {
|
||||
instance = new TagAbstractFileAction();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private TagAbstractFileAction() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JMenuItem getPopupPresenter() {
|
||||
return new TagAbstractFileMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
// Do nothing - this action should never be performed.
|
||||
// Submenu actions are invoked instead.
|
||||
}
|
||||
|
||||
private static class TagAbstractFileMenu extends TagMenu {
|
||||
public TagAbstractFileMenu() {
|
||||
super(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTag(String tagName, String comment) {
|
||||
Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
|
||||
for (AbstractFile file : selectedFiles) {
|
||||
Tags.createTag(file, tagName, comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.directorytree;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.Collection;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.JMenuItem;
|
||||
import org.openide.util.Utilities;
|
||||
import org.openide.util.actions.Presenter;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
|
||||
public class TagBlackboardArtifactAction extends AbstractAction implements Presenter.Popup {
|
||||
// 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 TagBlackboardArtifactAction instance;
|
||||
|
||||
public static synchronized TagBlackboardArtifactAction getInstance() {
|
||||
if (null == instance) {
|
||||
instance = new TagBlackboardArtifactAction();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private TagBlackboardArtifactAction() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JMenuItem getPopupPresenter() {
|
||||
return new TagBlackboardArtifactMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
// Do nothing - this action should never be performed.
|
||||
// Submenu actions are invoked instead.
|
||||
}
|
||||
|
||||
|
||||
private static class TagBlackboardArtifactMenu extends TagMenu {
|
||||
public TagBlackboardArtifactMenu() {
|
||||
super(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).size() > 1 ? "Tag Results" : "Tag Result");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTag(String tagName, String comment) {
|
||||
Collection<? extends BlackboardArtifact> selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
|
||||
for (BlackboardArtifact artifact : selectedArtifacts) {
|
||||
Tags.createTag(artifact, tagName, comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.directorytree;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.TreeSet;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
|
||||
/**
|
||||
* The menu that results when one right-clicks on a file or artifact.
|
||||
*/
|
||||
public abstract class TagMenu extends JMenu {
|
||||
public TagMenu(String menuItemText) {
|
||||
super(menuItemText);
|
||||
|
||||
// Create the 'Quick Tag' sub-menu and add it to the tag menu.
|
||||
JMenu quickTagMenu = new JMenu("Quick Tag");
|
||||
add(quickTagMenu);
|
||||
|
||||
// Get the existing tag names.
|
||||
TreeSet<String> tagNames = Tags.getAllTagNames();
|
||||
if (tagNames.isEmpty()) {
|
||||
JMenuItem empty = new JMenuItem("No tags");
|
||||
empty.setEnabled(false);
|
||||
quickTagMenu.add(empty);
|
||||
}
|
||||
|
||||
// Add a menu item for each existing tag name to the 'Quick Tag' menu.
|
||||
for (final String tagName : tagNames) {
|
||||
JMenuItem tagNameItem = new JMenuItem(tagName);
|
||||
tagNameItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
applyTag(tagName, "");
|
||||
refreshDirectoryTree();
|
||||
}
|
||||
});
|
||||
quickTagMenu.add(tagNameItem);
|
||||
}
|
||||
|
||||
quickTagMenu.addSeparator();
|
||||
|
||||
// Create the 'New Tag' menu item and add it to the 'Quick Tag' menu.
|
||||
JMenuItem newTagMenuItem = new JMenuItem("New Tag");
|
||||
newTagMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String tagName = CreateTagDialog.getNewTagNameDialog(null);
|
||||
if (tagName != null) {
|
||||
applyTag(tagName, "");
|
||||
refreshDirectoryTree();
|
||||
}
|
||||
}
|
||||
});
|
||||
quickTagMenu.add(newTagMenuItem);
|
||||
|
||||
// Create the 'Tag and Comment' menu item and add it to the tag menu.
|
||||
JMenuItem tagAndCommentItem = new JMenuItem("Tag and Comment");
|
||||
tagAndCommentItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
TagAndCommentDialog.CommentedTag commentedTag = TagAndCommentDialog.doDialog();
|
||||
if (null != commentedTag) {
|
||||
applyTag(commentedTag.getName(), commentedTag.getComment());
|
||||
refreshDirectoryTree();
|
||||
}
|
||||
}
|
||||
});
|
||||
add(tagAndCommentItem);
|
||||
}
|
||||
|
||||
private void refreshDirectoryTree() {
|
||||
//TODO instead should send event to node children, which will call its refresh() / refreshKeys()
|
||||
DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance();
|
||||
viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
|
||||
viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
|
||||
}
|
||||
|
||||
protected abstract void applyTag(String tagName, String comment);
|
||||
}
|
||||
@@ -24,12 +24,14 @@ import java.beans.PropertyVetoException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.SwingWorker;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.explorer.view.TreeView;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
|
||||
@@ -44,7 +46,14 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.VolumeSystem;
|
||||
|
||||
/**
|
||||
* View the directory content associated with the given Artifact
|
||||
* View the directory content associated with the given Artifact in the DataResultViewer.
|
||||
*
|
||||
* 1. Expands the Directory Tree to the location of the parent Node of the
|
||||
* associated Content.
|
||||
* 2. Selects the parent Node of the associated Content in the Directory Tree,
|
||||
* which causes the parent Node's Children to be visible in the DataResultViewer.
|
||||
* 3. Waits for all the Children to be contentNode in the DataResultViewer and
|
||||
* selects the Node that represents the Content.
|
||||
*/
|
||||
public class ViewContextAction extends AbstractAction {
|
||||
|
||||
@@ -81,61 +90,116 @@ public class ViewContextAction extends AbstractAction {
|
||||
Node generated = new DirectoryTreeFilterNode(new AbstractNode(new RootContentChildren(hierarchy)), true);
|
||||
Children genChilds = generated.getChildren();
|
||||
|
||||
final DirectoryTreeTopComponent directoryTree = DirectoryTreeTopComponent.findInstance();
|
||||
TreeView tree = directoryTree.getTree();
|
||||
ExplorerManager man = directoryTree.getExplorerManager();
|
||||
Node dirRoot = man.getRootContext();
|
||||
Children dirChilds = dirRoot.getChildren();
|
||||
Node imagesRoot = dirChilds.findChild(DataSourcesNode.NAME);
|
||||
dirChilds = imagesRoot.getChildren();
|
||||
final DirectoryTreeTopComponent dirTree = DirectoryTreeTopComponent.findInstance();
|
||||
TreeView dirTreeView = dirTree.getTree();
|
||||
ExplorerManager dirTreeExplorerManager = dirTree.getExplorerManager();
|
||||
Node dirTreeRootNode = dirTreeExplorerManager.getRootContext();
|
||||
Children dirChilds = dirTreeRootNode.getChildren();
|
||||
Children currentChildren = dirChilds.findChild(DataSourcesNode.NAME).getChildren();
|
||||
|
||||
Node dirExplored = null;
|
||||
|
||||
// Find the parent node of the content in the directory tree
|
||||
for (int i = 0; i < genChilds.getNodesCount() - 1; i++) {
|
||||
Node currentGeneratedNode = genChilds.getNodeAt(i);
|
||||
for (int j = 0; j < dirChilds.getNodesCount(); j++) {
|
||||
Node currentDirectoryTreeNode = dirChilds.getNodeAt(j);
|
||||
for (int j = 0; j < currentChildren.getNodesCount(); j++) {
|
||||
Node currentDirectoryTreeNode = currentChildren.getNodeAt(j);
|
||||
if (currentGeneratedNode.getDisplayName().equals(currentDirectoryTreeNode.getDisplayName())) {
|
||||
dirExplored = currentDirectoryTreeNode;
|
||||
tree.expandNode(dirExplored);
|
||||
dirChilds = currentDirectoryTreeNode.getChildren();
|
||||
dirTreeView.expandNode(dirExplored);
|
||||
currentChildren = currentDirectoryTreeNode.getChildren();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the parent node of the content as the selection in the
|
||||
// directory tree
|
||||
try {
|
||||
if (dirExplored != null) {
|
||||
tree.expandNode(dirExplored);
|
||||
man.setExploredContextAndSelection(dirExplored, new Node[]{dirExplored});
|
||||
dirTreeView.expandNode(dirExplored);
|
||||
dirTreeExplorerManager.setExploredContextAndSelection(dirExplored, new Node[]{dirExplored});
|
||||
}
|
||||
|
||||
} catch (PropertyVetoException ex) {
|
||||
logger.log(Level.WARNING, "Couldn't set selected node", ex);
|
||||
}
|
||||
|
||||
// Another thread is needed because we have to wait for dataResult to populate
|
||||
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
DataResultTopComponent dataResult = directoryTree.getDirectoryListing();
|
||||
Node resultRoot = dataResult.getRootNode();
|
||||
Children resultChilds = resultRoot.getChildren();
|
||||
Node generated = content.accept(new RootContentChildren.CreateSleuthkitNodeVisitor());
|
||||
for (int i = 0; i < resultChilds.getNodesCount(); i++) {
|
||||
Node current = resultChilds.getNodeAt(i);
|
||||
if (generated.getName().equals(current.getName())) {
|
||||
dataResult.requestActive();
|
||||
dataResult.setSelectedNodes(new Node[]{current});
|
||||
DirectoryTreeTopComponent.getDefault().fireViewerComplete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
DataResultTopComponent dataResultTC = dirTree.getDirectoryListing();
|
||||
Node currentRootNodeOfDataResultTC = dataResultTC.getRootNode();
|
||||
Node contentNode = content.accept(new RootContentChildren.CreateSleuthkitNodeVisitor());
|
||||
new SelectionWorker(dataResultTC, contentNode.getName(), currentRootNodeOfDataResultTC).execute();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a Node's children to be generated, regardless of whether they
|
||||
* are lazily loaded, then sets the correct selection in a specified
|
||||
* DataResultTopComponent.
|
||||
*/
|
||||
private class SelectionWorker extends SwingWorker<Node[], Integer> {
|
||||
|
||||
DataResultTopComponent dataResultTC;
|
||||
String nameOfNodeToSelect;
|
||||
Node originalRootNodeOfDataResultTC;
|
||||
|
||||
SelectionWorker(DataResultTopComponent dataResult, String nameToSelect, Node originalRoot) {
|
||||
this.dataResultTC = dataResult;
|
||||
this.nameOfNodeToSelect = nameToSelect;
|
||||
this.originalRootNodeOfDataResultTC = originalRoot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node[] doInBackground() throws Exception {
|
||||
// Calls to Children::getNodes(true) block until all child Nodes have
|
||||
// been created, regardless of whether they are created lazily.
|
||||
// This means that this call will return the actual child Nodes
|
||||
// and will *NEVER* return a proxy wait Node. This is done on the
|
||||
// background thread to ensure we are not hanging the ui as it could
|
||||
// be a lengthy operation.
|
||||
return originalRootNodeOfDataResultTC.getChildren().getNodes(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
Node[] nodesDisplayedInDataResultViewer;
|
||||
try {
|
||||
nodesDisplayedInDataResultViewer = get();
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
logger.log(Level.WARNING, "Failed to get nodes in selection worker.", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
// It is possible the user selected a different Node to be displayed
|
||||
// in the DataResultViewer while the child Nodes were being generated.
|
||||
// In that case, we don't want to set the selection because it the
|
||||
// nodes returned from get() won't be in the DataResultTopComponent's
|
||||
// ExplorerManager. If we did call setSelectedNodes, it would clear
|
||||
// the current selection, which is not good.
|
||||
if (dataResultTC.getRootNode().equals(originalRootNodeOfDataResultTC) == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the correct node to select from the nodes that are displayed
|
||||
// in the data result viewer and set it as the selection of the
|
||||
// DataResultTopComponent.
|
||||
for (Node node : nodesDisplayedInDataResultViewer) {
|
||||
if (nameOfNodeToSelect.equals(node.getName())) {
|
||||
dataResultTC.requestActive();
|
||||
dataResultTC.setSelectedNodes(new Node[]{node});
|
||||
DirectoryTreeTopComponent.getDefault().fireViewerComplete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The ReverseHierarchyVisitor class is designed to return a list of Content
|
||||
|
||||
@@ -24,7 +24,7 @@ FileSearchTopComponent.dateCheckBox1.text=Date:
|
||||
FileSearchTopComponent.dateFiltersButton1.text=Date Filters
|
||||
KnownStatusSearchPanel.knownCheckBox.text=Known Status:
|
||||
KnownStatusSearchPanel.knownBadOptionCheckBox.text=Known bad
|
||||
KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL)
|
||||
KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL or other)
|
||||
KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown
|
||||
DateSearchPanel.dateCheckBox.text=Date:
|
||||
DateSearchPanel.jLabel4.text=Timezone:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011 - 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -55,7 +55,7 @@ class KnownStatusSearchFilter extends AbstractFileSearchFilter<KnownStatusSearch
|
||||
|
||||
String expr = "0";
|
||||
if (unknown) {
|
||||
expr += " or " + predicateHelper(FileKnown.UKNOWN);
|
||||
expr += " or " + predicateHelper(FileKnown.UNKNOWN);
|
||||
}
|
||||
if (known) {
|
||||
expr += " or " + predicateHelper(FileKnown.KNOWN);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.1" encoding="UTF-8" ?>
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<AuxValues>
|
||||
@@ -64,6 +64,9 @@
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="KnownStatusSearchPanel.knownOptionCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="knownOptionCheckBoxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="knownBadOptionCheckBox">
|
||||
<Properties>
|
||||
|
||||
@@ -74,6 +74,11 @@ class KnownStatusSearchPanel extends javax.swing.JPanel {
|
||||
|
||||
knownOptionCheckBox.setSelected(true);
|
||||
knownOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownOptionCheckBox.text")); // NOI18N
|
||||
knownOptionCheckBox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
knownOptionCheckBoxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
knownBadOptionCheckBox.setSelected(true);
|
||||
knownBadOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownBadOptionCheckBox.text")); // NOI18N
|
||||
@@ -102,6 +107,11 @@ class KnownStatusSearchPanel extends javax.swing.JPanel {
|
||||
.addComponent(knownBadOptionCheckBox))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void knownOptionCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownOptionCheckBoxActionPerformed
|
||||
// TODO add your handling code here:
|
||||
}//GEN-LAST:event_knownOptionCheckBoxActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JCheckBox knownBadOptionCheckBox;
|
||||
private javax.swing.JCheckBox knownCheckBox;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user