diff --git a/API-CHANGES.txt b/API-CHANGES.txt index 7ca06f56f9..4ba7cae545 100644 --- a/API-CHANGES.txt +++ b/API-CHANGES.txt @@ -1,4 +1,5 @@ Changes to make to API when we are ready to make backward incompatible changes: - HTMLReport has special API for more context on columns and special handling in REportGenerator. Change all reports to the new API. -- DataaContentViewer.isPreferred does not need isSupported to be passed in +- DataContentViewer.isPreferred does not need isSupported to be passed in +- DataContentViewerHex and STrings can have the public setDataView methods removed in favor of the new private ones \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java index 8b4ef96f1d..cdfb561ae0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java @@ -109,7 +109,7 @@ public final class AddImageAction extends CallableSystemAction implements Presen Logger.noteAction(AddImageAction.class); final IngestConfigurator ingestConfig = Lookup.getDefault().lookup(IngestConfigurator.class); - if (ingestConfig.isIngestRunning()) { + if (null != ingestConfig && ingestConfig.isIngestRunning()) { final String msg = "Ingest is ongoing on another data source. Adding a new source now might slow down the current ingest.
Do you want to proceed and add a new data source now?"; if (JOptionPane.showConfirmDialog(null, msg, "Ingest in progress", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.NO_OPTION) { return; @@ -128,7 +128,6 @@ public final class AddImageAction extends CallableSystemAction implements Presen dialog.setVisible(true); dialog.toFront(); - // Do any cleanup that needs to happen (potentially: stopping the //add-image process, reverting an image) runCleanupTasks(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardPanel3.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardPanel3.java index 7ec7090c03..98aa035b8a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardPanel3.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardPanel3.java @@ -55,7 +55,7 @@ import org.sleuthkit.datamodel.TskException; class AddImageWizardPanel3 implements WizardDescriptor.Panel { private static final Logger logger = Logger.getLogger(AddImageWizardPanel3.class.getName()); - private IngestConfigurator ingestConfig = Lookup.getDefault().lookup(IngestConfigurator.class); + private IngestConfigurator ingestConfig; /** * The visual component that displays this panel. If you need to access the * component from this class, just use getComponent(). @@ -85,6 +85,8 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel { AddImageWizardPanel3(AddImageAction action, AddImageWizardPanel2 wizPanel) { this.action = action; this.wizPanel = wizPanel; + ingestConfig = Lookup.getDefault().lookup(IngestConfigurator.class); + ingestConfig.setContext(AddImageWizardPanel3.class.getCanonicalName()); } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 5dee9feb54..6c1d0d6db1 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -326,7 +326,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 */ - Image addImage(String imgPath, long imgId, String timeZone) throws CaseActionException { + 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}); try { @@ -372,7 +372,7 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Closes this case. This methods close the xml and clear all the fields. */ - void closeCase() throws CaseActionException { + public void closeCase() throws CaseActionException { changeCase(null); try { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/GeneralIngestConfigurator.java b/Core/src/org/sleuthkit/autopsy/casemodule/GeneralIngestConfigurator.java new file mode 100644 index 0000000000..ba486f33a6 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/GeneralIngestConfigurator.java @@ -0,0 +1,159 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit 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.List; +import javax.swing.JPanel; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.ingest.IngestDialogPanel; +import static org.sleuthkit.autopsy.ingest.IngestDialogPanel.DISABLED_MOD; +import static org.sleuthkit.autopsy.ingest.IngestDialogPanel.PARSE_UNALLOC; +import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.IngestModuleAbstract; +import org.sleuthkit.datamodel.Content; + +@ServiceProvider(service = IngestConfigurator.class) +public class GeneralIngestConfigurator implements IngestConfigurator { + private List contentToIngest; + private IngestManager manager; + private IngestDialogPanel ingestDialogPanel; + private String moduleContext; + + public GeneralIngestConfigurator() { + this.moduleContext = IngestManager.MODULE_PROPERTIES; // Hard-code this for now. + ingestDialogPanel = new IngestDialogPanel(); + ingestDialogPanel.setContext(moduleContext); + manager = IngestManager.getDefault(); + loadSettings(); + } + + @Override + public void setContext(String context) { + moduleContext = context; + ingestDialogPanel.setContext(moduleContext); + reload(); + } + + @Override + public JPanel getIngestConfigPanel() { + return ingestDialogPanel; + } + + @Override + public void setContent(List inputContent) { + this.contentToIngest = inputContent; + } + + @Override + public void start() { + // Get the list of ingest modules selected by the user. + List modulesToStart = ingestDialogPanel.getModulesToStart(); + + // Get the user's selection of whether or not to process unallocated space. + manager.setProcessUnallocSpace(ingestDialogPanel.processUnallocSpaceEnabled()); + + // Start the ingest. + if (!modulesToStart.isEmpty()) { + manager.execute(modulesToStart, contentToIngest); + } + } + + @Override + public void save() { + // Save the user's configuration of the currently selected module. + IngestModuleAbstract currentModule = ingestDialogPanel.getCurrentIngestModule(); + if (currentModule != null && currentModule.hasSimpleConfiguration()) { + currentModule.saveSimpleConfiguration(); + } + + // Create a list of the modules the user wants to be disabled. + List disabledModules = IngestManager.getDefault().enumerateAllModules(); + disabledModules.removeAll(ingestDialogPanel.getModulesToStart()); + String disabledModulesCsv = moduleListToCsv(disabledModules); + + // Save the user's general ingest configuration. + ModuleSettings.setConfigSetting(moduleContext, DISABLED_MOD, disabledModulesCsv); + String processUnalloc = Boolean.toString(ingestDialogPanel.processUnallocSpaceEnabled()); + ModuleSettings.setConfigSetting(moduleContext, PARSE_UNALLOC, processUnalloc); + } + + @Override + public void reload() { + loadSettings(); + } + + @Override + public boolean isIngestRunning() { + return manager.isIngestRunning(); + } + + private static String moduleListToCsv(List lst) { + if (lst == null || lst.isEmpty()) { + return ""; + } + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < lst.size() - 1; ++i) { + sb.append(lst.get(i).getName()).append(", "); + } + + // and the last one + sb.append(lst.get(lst.size() - 1).getName()); + + return sb.toString(); + } + + private static List csvToModuleList(String csv) { + List modules = new ArrayList<>(); + + if (csv == null || csv.isEmpty()) { + return modules; + } + + String[] moduleNames = csv.split(", "); + List allModules = IngestManager.getDefault().enumerateAllModules(); + for (String moduleName : moduleNames) { + for (IngestModuleAbstract module : allModules) { + if (moduleName.equals(module.getName())) { + modules.add(module); + break; + } + } + } + + return modules; + } + + private void loadSettings() { + // get the csv list of disabled modules + String disabledModulesCsv = ModuleSettings.getConfigSetting(moduleContext, DISABLED_MOD); + + // create a list of modules from it + List disabledModules = csvToModuleList(disabledModulesCsv); + + // tell the ingestDialogPanel to unselect these modules + ingestDialogPanel.setDisabledModules(disabledModules); + + boolean processUnalloc = Boolean.parseBoolean(ModuleSettings.getConfigSetting(moduleContext, PARSE_UNALLOC)); + ingestDialogPanel.setProcessUnallocSpaceEnabled(processUnalloc); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/IngestConfigurator.java b/Core/src/org/sleuthkit/autopsy/casemodule/IngestConfigurator.java index cca3e2d064..3b585b2167 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/IngestConfigurator.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/IngestConfigurator.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -60,4 +60,10 @@ public interface IngestConfigurator { */ boolean isIngestRunning(); + /** + * Set the context for the configuration. + * @param context + */ + public void setContext(String context); + } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java index e4c497346d..66d0089f6b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java @@ -77,9 +77,11 @@ public class FileManager implements Closeable { } /** - * @param dataSource data source Content (Image, parent-less - * VirtualDirectory) where to find files - * @param fileName the name of the file or directory to match + * Finds a set of files that meets the name criteria. + * @param dataSource Root data source to limit search results to (Image, + * VirtualDirectory, etc.). + * @param fileName Pattern of the name of the file or directory to match (case + * insensitive, used in LIKE SQL statement). * @return a list of AbstractFile for files/directories whose name matches * the given fileName */ @@ -90,11 +92,15 @@ public class FileManager implements Closeable { return tskCase.findFiles(dataSource, fileName); } + /** - * @param dataSource data source Content (Image, parent-less - * VirtualDirectory) where to find files - * @param fileName the name of the file or directory to match - * @param dirName the name of a parent directory of fileName + * Finds a set of files that meets the name criteria. + * @param dataSource Root data source to limit search results to (Image, + * VirtualDirectory, etc.). + * @param fileName Pattern of the name of the file or directory to match (case + * insensitive, used in LIKE SQL statement). + * @param dirName Pattern of the name of the parent directory to use as the root + * of the search (case insensitive, used in LIKE SQL statement). * @return a list of AbstractFile for files/directories whose name matches * fileName and whose parent directory contains dirName. */ @@ -106,10 +112,12 @@ public class FileManager implements Closeable { } /** - * @param dataSource data source Content (Image, parent-less - * VirtualDirectory) where to find files - * @param fileName the name of the file or directory to match - * @param parentFile parent file/dir of the file to find + * Finds a set of files that meets the name criteria. + * @param dataSource Root data source to limit search results to (Image, + * VirtualDirectory, etc.). + * @param fileName Pattern of the name of the file or directory to match (case + * insensitive, used in LIKE SQL statement). + * @param parentFile Object of root/parent directory to restrict search to. * @return a list of AbstractFile for files/directories whose name matches * fileName and that were inside a directory described by parentFsContent. */ diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java index afc782da06..0ad466151e 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java @@ -27,7 +27,6 @@ import org.openide.nodes.Node; * Interface for the different viewers that show a set of nodes in the DataResult area. * AbstractDataResultViewer has default implementations for the action handlers. * - * @author jantonius */ public interface DataResultViewer { /** @@ -47,7 +46,7 @@ public interface DataResultViewer { public DataResultViewer createInstance(); /** - * Get Component to display this DataResultViewer + * Get the Swing component (i.e. JPanel) for this viewer */ public Component getComponent(); @@ -74,7 +73,7 @@ public interface DataResultViewer { public void setSelectedNodes(Node[] selected); /** - * Checks whether the currently selected node + * Checks whether the currently selected root node * is supported by this viewer * @param selectedNode the selected node * @return True if supported, else false diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java index 3387065d1d..dfff6f0e83 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java @@ -36,7 +36,8 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; import org.sleuthkit.autopsy.coreutils.Logger; /** - * Holds commonalities between all DataResultViewers + * Holds commonalities between all DataResultViewers, such as: + * - Pushes selection to DataContentViewers */ public abstract class AbstractDataResultViewer extends JPanel implements DataResultViewer, Provider { @@ -81,21 +82,17 @@ public abstract class AbstractDataResultViewer extends JPanel implements // change the cursor to "waiting cursor" for this operation setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); try { - Node selectedNode = getSelectedNode(); - - nodeSelected(selectedNode); - - - - if (selectedNode != null) { + Node[] selectedNodes = getExplorerManager().getSelectedNodes(); + if (selectedNodes.length == 1) { + nodeSelected(selectedNodes[0]); + // there's a new/changed node to display - Node newSelectedNode = selectedNode; // get the selected Node on the table // push the node to default "DataContent" //TODO only the active viewer should be calling setNode //not all of them, otherwise it results in multiple setNode() invocations //alternative is to use a single instance of the event listener //, per top component and not the tab perhaps - contentViewer.setNode(newSelectedNode); + contentViewer.setNode(selectedNodes[0]); } else { // clear the node viewer contentViewer.setNode(null); @@ -131,6 +128,7 @@ public abstract class AbstractDataResultViewer extends JPanel implements } } + @Deprecated public Node getSelectedNode() { Node result = null; Node[] selectedNodes = this.getExplorerManager().getSelectedNodes(); diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentPanel.java index e0778d537f..a825751e4c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentPanel.java @@ -178,7 +178,7 @@ public class DataContentPanel extends javax.swing.JPanel implements DataContent, jTabbedPane1.setEnabledAt(i, true); // remember the viewer with the highest preference value - int currentPreferred = dcv.isPreferred(selectedNode, false); + int currentPreferred = dcv.isPreferred(selectedNode, true); if (currentPreferred > maxPreferred) { preferredViewerIndex = i; maxPreferred = currentPreferred; @@ -191,7 +191,14 @@ public class DataContentPanel extends javax.swing.JPanel implements DataContent, // set the tab to the one the user wants, then set that viewer's node. jTabbedPane1.setSelectedIndex(tabIndex); - viewers.get(tabIndex).setNode(selectedNode); + UpdateWrapper dcv = viewers.get(tabIndex); + // this is really only needed if no tabs were enabled + if (jTabbedPane1.isEnabledAt(tabIndex) == false) { + dcv.resetComponent(); + } + else { + dcv.setNode(selectedNode); + } } @Override diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java index c34ee0d254..5ecab8489f 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java @@ -231,18 +231,21 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat @Override public void setNode(Node selectedNode) { if (selectedNode == null) { - this.setDataView(new ArrayList(), 1); + resetComponent(); return; } Lookup lookup = selectedNode.getLookup(); Content content = lookup.lookup(Content.class); - if (content != null) { - try { - this.setDataView(content.getAllArtifacts(), 1); - } catch (TskException ex) { - logger.log(Level.WARNING, "Couldn't get artifacts: ", ex); - } + if (content == null) { + resetComponent(); + return; + } + + try { + this.setDataView(content.getAllArtifacts(), 1); + } catch (TskException ex) { + logger.log(Level.WARNING, "Couldn't get artifacts: ", ex); } // focus on a specific artifact if it is in the node @@ -279,9 +282,11 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat this.artifacts = new ArrayList(); currentPageLabel.setText(""); totalPageLabel.setText(""); + outputViewPane.setText(""); prevPageButton.setEnabled(false); nextPageButton.setEnabled(false); setComponentsVisibility(false); // hides the components that not needed + this.setCursor(null); } /** @@ -380,9 +385,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); if(artifacts.isEmpty()){ - setComponentsVisibility(false); - this.setCursor(null); - outputViewPane.setText(""); + resetComponent(); return; } this.artifacts = artifacts; diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index d77c86013f..1df9d11a96 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -247,7 +247,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont currentOffset -= pageLength; currentPage = currentPage - 1; currentPageLabel.setText(Integer.toString(currentPage)); - setDataView(dataSource, currentOffset, false); + setDataView(dataSource, currentOffset); }//GEN-LAST:event_prevPageButtonActionPerformed private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed @@ -255,7 +255,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont currentOffset += pageLength; currentPage = currentPage + 1; currentPageLabel.setText(Integer.toString(currentPage)); - setDataView(dataSource, currentOffset, false); + setDataView(dataSource, currentOffset); }//GEN-LAST:event_nextPageButtonActionPerformed private void goToPageTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToPageTextFieldActionPerformed @@ -275,7 +275,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont currentOffset = (pageNumber - 1) * pageLength; currentPage = pageNumber; currentPageLabel.setText(Integer.toString(currentPage)); - setDataView(dataSource, currentOffset, false); + setDataView(dataSource, currentOffset); }//GEN-LAST:event_goToPageTextFieldActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JMenuItem copyMenuItem; @@ -295,14 +295,23 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont private javax.swing.JLabel totalPageLabel; // End of variables declaration//GEN-END:variables + + @Deprecated + public void setDataView(Content dataSource, long offset, boolean reset) { + if (reset) { + resetComponent(); + return; + } + setDataView(dataSource, offset); + } + /** * Sets the DataView (The tabbed panel) * * @param dataSource the content that want to be shown * @param offset the starting offset - * @param reset whether to reset the dataView or not */ - public void setDataView(Content dataSource, long offset, boolean reset) { + private void setDataView(Content dataSource, long offset) { if (dataSource == null) { return; } @@ -312,14 +321,12 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont this.dataSource = dataSource; String errorText = null; - Boolean setVisible = false; int bytesRead = 0; - if (!reset && dataSource.getSize() > 0) { + if (dataSource.getSize() > 0) { try { bytesRead = dataSource.read(data, offset, pageLength); // read the data } catch (TskException ex) { - setVisible = true; errorText = "(offset " + currentOffset + "-" + (currentOffset + pageLength) + " could not be read)"; logger.log(Level.WARNING, "Error while trying to show the hex content.", ex); @@ -327,73 +334,58 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont } // set the data on the bottom and show it - if (bytesRead > 0) { - setVisible = true; - } - else { + if (bytesRead <= 0) { errorText = "(offset " + currentOffset + "-" + (currentOffset + pageLength) + " could not be read)"; - setVisible = true; } // disable or enable the next button - if (!reset && offset + pageLength < dataSource.getSize()) { + if ((errorText != null) && (offset + pageLength < dataSource.getSize())) { nextPageButton.setEnabled(true); } else { nextPageButton.setEnabled(false); } - if (offset == 0) { + if ((offset == 0) || (errorText == null)) { prevPageButton.setEnabled(false); currentPage = 1; // reset the page number } else { prevPageButton.setEnabled(true); } - if (setVisible) { - int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1; - totalPageLabel.setText(Integer.toString(totalPage)); - currentPageLabel.setText(Integer.toString(currentPage)); - setComponentsVisibility(true); // shows the components that not needed + int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1; + totalPageLabel.setText(Integer.toString(totalPage)); + currentPageLabel.setText(Integer.toString(currentPage)); + setComponentsVisibility(true); // shows the components that not needed - // set the output view + // set the output view + if (errorText == null) { int showLength = bytesRead < pageLength ? bytesRead : (int) pageLength; - if (errorText == null) { - outputViewPane.setText(DataConversion.byteArrayToHex(data, showLength, offset, outputViewPane.getFont())); - } - else { - outputViewPane.setText(errorText); - } - - } else { - // reset or hide the labels - totalPageLabel.setText(""); - currentPageLabel.setText(""); - outputViewPane.setText(""); // reset the output view - setComponentsVisibility(false); // hides the components that not needed + outputViewPane.setText(DataConversion.byteArrayToHex(data, showLength, offset, outputViewPane.getFont())); + } + else { + outputViewPane.setText(errorText); } outputViewPane.moveCaretPosition(0); - this.setCursor(null); - } @Override public void setNode(Node selectedNode) { if ((selectedNode == null) || (!isSupported(selectedNode))) { - setDataView(null, 0, true); + resetComponent(); return; } Content content = (selectedNode).getLookup().lookup(Content.class); if (content == null) { - this.setDataView(null, 0, true); + resetComponent(); return; } - this.setDataView(content, 0, false); + this.setDataView(content, 0); } @Override @@ -420,8 +412,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont this.dataSource = null; currentPageLabel.setText(""); totalPageLabel.setText(""); - prevPageButton.setEnabled(false); - nextPageButton.setEnabled(false); + outputViewPane.setText(""); setComponentsVisibility(false); // hides the components that not needed } @@ -448,8 +439,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont return false; } Content content = node.getLookup().lookup(Content.class); - - if (content != null && content.getSize() != 0) { + if (content != null && content.getSize() > 0) { return true; } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java index 13abbad67b..a6f4b34cfe 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java @@ -1,259 +1,256 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2013 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.corecomponents; - -import java.awt.CardLayout; -import java.awt.Component; -import java.awt.Dimension; -import java.util.Arrays; -import java.util.logging.Level; -import javax.imageio.ImageIO; -import org.sleuthkit.autopsy.coreutils.Logger; -import javax.swing.SwingUtilities; -import org.openide.nodes.Node; -import org.openide.util.Exceptions; -import org.openide.util.lookup.ServiceProvider; -import org.openide.util.lookup.ServiceProviders; -import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; - -/** - * Media content viewer for videos, sounds and images. - */ -@ServiceProviders(value = { - @ServiceProvider(service = DataContentViewer.class, position = 5) -}) -public class DataContentViewerMedia extends javax.swing.JPanel implements DataContentViewer { - - private String[] IMAGES; // use javafx supported - private static final String[] VIDEOS = new String[]{".swf", ".mov", ".m4v", ".flv", ".mp4", ".3gp", ".avi", ".mpg", ".mpeg", ".wmv"}; - private static final String[] AUDIOS = new String[]{".mp3", ".wav", ".wma"}; - - private static final Logger logger = Logger.getLogger(DataContentViewerMedia.class.getName()); - - private AbstractFile lastFile; - //UI - private final MediaViewVideoPanel videoPanel; - private final MediaViewImagePanel imagePanel; - private boolean videoPanelInited; - private boolean imagePanelInited; - - private static final String IMAGE_VIEWER_LAYER = "IMAGE"; - private static final String VIDEO_VIEWER_LAYER = "VIDEO"; - - /** - * Creates new form DataContentViewerVideo - */ - public DataContentViewerMedia() { - - initComponents(); - - videoPanel = MediaViewVideoPanel.createVideoPanel(); - imagePanel = new MediaViewImagePanel(); - videoPanelInited = videoPanel.isInited(); - imagePanelInited = imagePanel.isInited(); - - customizeComponents(); - logger.log(Level.INFO, "Created MediaView instance: " + this); - } - - private void customizeComponents() { - logger.log(Level.INFO, "Supported image formats by javafx image viewer: "); - //initialize supported image types - //TODO use mime-types instead once we have support - String[] fxSupportedImagesSuffixes = ImageIO.getReaderFileSuffixes(); - IMAGES = new String[fxSupportedImagesSuffixes.length]; - for (int i = 0; i < fxSupportedImagesSuffixes.length; ++i) { - String suffix = fxSupportedImagesSuffixes[i]; - logger.log(Level.INFO, "suffix: " + suffix); - IMAGES[i] = "." + suffix; - } - - add(imagePanel, IMAGE_VIEWER_LAYER); - add(videoPanel, VIDEO_VIEWER_LAYER); - - switchPanels(false); - - } - - /** - * 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") - // //GEN-BEGIN:initComponents - private void initComponents() { - - setLayout(new java.awt.CardLayout()); - getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(DataContentViewerMedia.class, "DataContentViewerMedia.AccessibleContext.accessibleDescription")); // NOI18N - }// //GEN-END:initComponents - // Variables declaration - do not modify//GEN-BEGIN:variables - // End of variables declaration//GEN-END:variables - - @Override - public void setNode(Node selectedNode) { - try { - if (selectedNode == null) { - videoPanel.reset(); - return; - } - - AbstractFile file = selectedNode.getLookup().lookup(AbstractFile.class); - if (file == null) { - return; - } - - if (file.equals(lastFile)) { - return; //prevent from loading twice if setNode() called mult. times - } else { - lastFile = file; - } - - videoPanel.reset(); - - final Dimension dims = DataContentViewerMedia.this.getSize(); - - if (imagePanelInited && containsExt(file.getName(), IMAGES)) { - imagePanel.showImageFx(file, dims); - this.switchPanels(false); - } else if (videoPanelInited - && (containsExt(file.getName(), VIDEOS) || containsExt(file.getName(), AUDIOS))) { - videoPanel.setupVideo(file, dims); - switchPanels(true); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "Exception while setting node", e); - } - } - - /** - * switch to visible video or image panel - * - * @param showVideo true if video panel, false if image panel - */ - private void switchPanels(boolean showVideo) { - CardLayout layout = (CardLayout)this.getLayout(); - if (showVideo) { - layout.show(this, VIDEO_VIEWER_LAYER); - } else { - layout.show(this, IMAGE_VIEWER_LAYER); - } - } - - @Override - public String getTitle() { - return "Media View"; - } - - @Override - public String getToolTip() { - return "Displays supported multimedia files (images, videos, audio)"; - } - - @Override - public DataContentViewer createInstance() { - return new DataContentViewerMedia(); - } - - @Override - public Component getComponent() { - return this; - } - - @Override - public void resetComponent() { - // we don't want this to do anything - // because we already reset on each selected node - } - - - - @Override - public boolean isSupported(Node node) { - - if (node == null) { - return false; - } - - AbstractFile file = node.getLookup().lookup(AbstractFile.class); - if (file == null) { - return false; - } - - - if (file.getSize() == 0) { - return false; - } - - String name = file.getName().toLowerCase(); - - if (imagePanelInited && containsExt(name, IMAGES)) { - return true; - } //for gstreamer formats, check if initialized first, then - //support audio formats, and video formats - else if (videoPanelInited && videoPanel.isInited() - && (containsExt(name, AUDIOS) - || (containsExt(name, VIDEOS)))) { - return true; - } - - return false; - } - - @Override - public int isPreferred(Node node, boolean isSupported) { - if (isSupported) { - //special case, check if deleted video, then do not make it preferred - AbstractFile file = node.getLookup().lookup(AbstractFile.class); - if (file == null) { - return 0; - } - String name = file.getName().toLowerCase(); - - boolean deleted = file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC); - if (containsExt(name, VIDEOS) && deleted) { - return 0; - } else { - return 7; - } - } else { - return 0; - } - } - - private static boolean containsExt(String name, String[] exts) { - int extStart = name.lastIndexOf("."); - String ext = ""; - if (extStart != -1) { - ext = name.substring(extStart, name.length()).toLowerCase(); - } - return Arrays.asList(exts).contains(ext); - } -} - - - - - - - - - +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2013 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.corecomponents; + +import java.awt.CardLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.util.Arrays; +import java.util.logging.Level; +import javax.imageio.ImageIO; +import org.sleuthkit.autopsy.coreutils.Logger; +import javax.swing.SwingUtilities; +import org.openide.nodes.Node; +import org.openide.util.Exceptions; +import org.openide.util.lookup.ServiceProvider; +import org.openide.util.lookup.ServiceProviders; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; + +/** + * Media content viewer for videos, sounds and images. + */ +@ServiceProviders(value = { + @ServiceProvider(service = DataContentViewer.class, position = 5) +}) +public class DataContentViewerMedia extends javax.swing.JPanel implements DataContentViewer { + + private String[] IMAGES; // use javafx supported + private static final String[] VIDEOS = new String[]{".swf", ".mov", ".m4v", ".flv", ".mp4", ".3gp", ".avi", ".mpg", ".mpeg", ".wmv"}; + private static final String[] AUDIOS = new String[]{".mp3", ".wav", ".wma"}; + + private static final Logger logger = Logger.getLogger(DataContentViewerMedia.class.getName()); + + private AbstractFile lastFile; + //UI + private final MediaViewVideoPanel videoPanel; + private final MediaViewImagePanel imagePanel; + private boolean videoPanelInited; + private boolean imagePanelInited; + + private static final String IMAGE_VIEWER_LAYER = "IMAGE"; + private static final String VIDEO_VIEWER_LAYER = "VIDEO"; + + /** + * Creates new form DataContentViewerVideo + */ + public DataContentViewerMedia() { + + initComponents(); + + videoPanel = MediaViewVideoPanel.createVideoPanel(); + imagePanel = new MediaViewImagePanel(); + videoPanelInited = videoPanel.isInited(); + imagePanelInited = imagePanel.isInited(); + + customizeComponents(); + logger.log(Level.INFO, "Created MediaView instance: " + this); + } + + private void customizeComponents() { + logger.log(Level.INFO, "Supported image formats by javafx image viewer: "); + //initialize supported image types + //TODO use mime-types instead once we have support + String[] fxSupportedImagesSuffixes = ImageIO.getReaderFileSuffixes(); + IMAGES = new String[fxSupportedImagesSuffixes.length]; + for (int i = 0; i < fxSupportedImagesSuffixes.length; ++i) { + String suffix = fxSupportedImagesSuffixes[i]; + logger.log(Level.INFO, "suffix: " + suffix); + IMAGES[i] = "." + suffix; + } + + add(imagePanel, IMAGE_VIEWER_LAYER); + add(videoPanel, VIDEO_VIEWER_LAYER); + + switchPanels(false); + + } + + /** + * 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") + // //GEN-BEGIN:initComponents + private void initComponents() { + + setLayout(new java.awt.CardLayout()); + getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(DataContentViewerMedia.class, "DataContentViewerMedia.AccessibleContext.accessibleDescription")); // NOI18N + }// //GEN-END:initComponents + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables + + @Override + public void setNode(Node selectedNode) { + try { + if (selectedNode == null) { + resetComponent(); + return; + } + + AbstractFile file = selectedNode.getLookup().lookup(AbstractFile.class); + if (file == null) { + resetComponent(); + return; + } + + if (file.equals(lastFile)) { + return; //prevent from loading twice if setNode() called mult. times + } else { + lastFile = file; + } + + videoPanel.reset(); + + final Dimension dims = DataContentViewerMedia.this.getSize(); + + if (imagePanelInited && containsExt(file.getName(), IMAGES)) { + imagePanel.showImageFx(file, dims); + this.switchPanels(false); + } else if (videoPanelInited + && (containsExt(file.getName(), VIDEOS) || containsExt(file.getName(), AUDIOS))) { + videoPanel.setupVideo(file, dims); + switchPanels(true); + } + } catch (Exception e) { + logger.log(Level.SEVERE, "Exception while setting node", e); + } + } + + /** + * switch to visible video or image panel + * + * @param showVideo true if video panel, false if image panel + */ + private void switchPanels(boolean showVideo) { + CardLayout layout = (CardLayout)this.getLayout(); + if (showVideo) { + layout.show(this, VIDEO_VIEWER_LAYER); + } else { + layout.show(this, IMAGE_VIEWER_LAYER); + } + } + + @Override + public String getTitle() { + return "Media View"; + } + + @Override + public String getToolTip() { + return "Displays supported multimedia files (images, videos, audio)"; + } + + @Override + public DataContentViewer createInstance() { + return new DataContentViewerMedia(); + } + + @Override + public Component getComponent() { + return this; + } + + @Override + public void resetComponent() { + videoPanel.reset(); + } + + + + @Override + public boolean isSupported(Node node) { + if (node == null) { + return false; + } + + AbstractFile file = node.getLookup().lookup(AbstractFile.class); + if (file == null) { + return false; + } + + if (file.getSize() == 0) { + return false; + } + + String name = file.getName().toLowerCase(); + if (imagePanelInited && containsExt(name, IMAGES)) { + return true; + } //for gstreamer formats, check if initialized first, then + //support audio formats, and video formats + else if (videoPanelInited && videoPanel.isInited() + && (containsExt(name, AUDIOS) + || (containsExt(name, VIDEOS)))) { + return true; + } + + return false; + } + + @Override + public int isPreferred(Node node, boolean isSupported) { + if (isSupported) { + //special case, check if deleted video, then do not make it preferred + AbstractFile file = node.getLookup().lookup(AbstractFile.class); + if (file == null) { + return 0; + } + String name = file.getName().toLowerCase(); + + boolean deleted = file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC); + if (containsExt(name, VIDEOS) && deleted) { + return 0; + } else { + return 7; + } + } else { + return 0; + } + } + + private static boolean containsExt(String name, String[] exts) { + int extStart = name.lastIndexOf("."); + String ext = ""; + if (extStart != -1) { + ext = name.substring(extStart, name.length()).toLowerCase(); + } + return Arrays.asList(exts).contains(ext); + } +} + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.java index 765ba62f42..c5bc6b9970 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.java @@ -265,7 +265,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC currentOffset -= pageLength; currentPage = currentPage - 1; currentPageLabel.setText(Integer.toString(currentPage)); - setDataView(dataSource, currentOffset, false); + setDataView(dataSource, currentOffset); }//GEN-LAST:event_prevPageButtonActionPerformed private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed @@ -273,7 +273,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC currentOffset += pageLength; currentPage = currentPage + 1; currentPageLabel.setText(Integer.toString(currentPage)); - setDataView(dataSource, currentOffset, false); + setDataView(dataSource, currentOffset); }//GEN-LAST:event_nextPageButtonActionPerformed private void goToPageTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToPageTextFieldActionPerformed @@ -293,13 +293,13 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC currentOffset = (pageNumber - 1) * pageLength; currentPage = pageNumber; currentPageLabel.setText(Integer.toString(currentPage)); - setDataView(dataSource, currentOffset, false); + setDataView(dataSource, currentOffset); }//GEN-LAST:event_goToPageTextFieldActionPerformed private void languageComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_languageComboActionPerformed if (dataSource != null) { - setDataView(dataSource, currentOffset, false); + setDataView(dataSource, currentOffset); } }//GEN-LAST:event_languageComboActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables @@ -322,14 +322,22 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC private javax.swing.JLabel totalPageLabel; // End of variables declaration//GEN-END:variables + @Deprecated + public void setDataView(Content dataSource, long offset, boolean reset) { + if (reset) { + resetComponent(); + return; + } + setDataView(dataSource, offset); + } + /** * Sets the DataView (The tabbed panel) * * @param dataSource the content that want to be shown * @param offset the starting offset - * @param reset whether to reset the dataView or not */ - public void setDataView(Content dataSource, long offset, boolean reset) { + private void setDataView(Content dataSource, long offset) { if (dataSource == null) { return; } @@ -342,14 +350,12 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC int bytesRead = 0; // set the data on the bottom and show it String text = ""; - Boolean setVisible = false; - if (!reset && dataSource.getSize() > 0) { + if (dataSource.getSize() > 0) { try { bytesRead = dataSource.read(data, offset, pageLength); // read the data } catch (TskException ex) { text = "(offset " + currentOffset + "-" + (currentOffset + pageLength) + " could not be read)"; - setVisible = true; logger.log(Level.WARNING, "Error while trying to show the String content.", ex); } } @@ -364,16 +370,13 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC text = "(offset " + currentOffset + "-" + (currentOffset + pageLength) + " contains no text)"; } - - setVisible = true; } else { text = "(offset " + currentOffset + "-" + (currentOffset + pageLength) + " could not be read)"; - setVisible = true; } // disable or enable the next button - if (!reset && offset + pageLength < dataSource.getSize()) { + if (offset + pageLength < dataSource.getSize()) { nextPageButton.setEnabled(true); } else { nextPageButton.setEnabled(false); @@ -386,23 +389,15 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC prevPageButton.setEnabled(true); } - if (setVisible) { - int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1; - totalPageLabel.setText(Integer.toString(totalPage)); - currentPageLabel.setText(Integer.toString(currentPage)); - outputViewPane.setText(text); // set the output view - setComponentsVisibility(true); // shows the components that not needed - } else { - // reset or hide the labels - totalPageLabel.setText(""); - currentPageLabel.setText(""); - outputViewPane.setText(""); // reset the output view - setComponentsVisibility(false); // hides the components that not needed - } + + int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1; + totalPageLabel.setText(Integer.toString(totalPage)); + currentPageLabel.setText(Integer.toString(currentPage)); + outputViewPane.setText(text); // set the output view + setComponentsVisibility(true); // shows the components that not needed outputViewPane.moveCaretPosition(0); this.setCursor(null); - } /** @@ -422,31 +417,28 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC goToPageLabel.setVisible(isVisible); languageCombo.setVisible(isVisible); languageLabel.setVisible(isVisible); - } @Override public void setNode(Node selectedNode) { - if (!isSupported(selectedNode)) { - setDataView(null, 0, true); + if ((selectedNode == null) || (!isSupported(selectedNode))) { + resetComponent(); return; } - if (selectedNode != null) { - Lookup lookup = selectedNode.getLookup(); - Content content = lookup.lookup(Content.class); - if (content - != null) { - this.setDataView(content, 0, false); + + Lookup lookup = selectedNode.getLookup(); + Content content = lookup.lookup(Content.class); + if (content != null) { + this.setDataView(content, 0); + return; + } else { + StringContent scontent = selectedNode.getLookup().lookup(StringContent.class); + if (scontent != null) { + this.setDataView(scontent); return; - } else { - StringContent scontent = selectedNode.getLookup().lookup(StringContent.class); - if (scontent != null) { - this.setDataView(scontent); - return; - } } } - this.setDataView(null, 0, true); + resetComponent(); } @Override @@ -474,6 +466,7 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC totalPageLabel.setText(""); prevPageButton.setEnabled(false); nextPageButton.setEnabled(false); + outputViewPane.setText(""); // reset the output view setComponentsVisibility(false); // hides the components that not needed } @@ -481,14 +474,9 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC public boolean isSupported(Node node) { if (node == null) { return false; - - } Content content = node.getLookup().lookup(Content.class); - - if (content - != null && content.getSize() - != 0) { + if (content != null && content.getSize() > 0) { return true; } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java index ecdf121466..61560f9e99 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.List; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResult; import java.util.logging.Level; +import org.openide.explorer.ExplorerUtils; import org.openide.util.NbBundle; import org.openide.windows.TopComponent; import org.openide.nodes.Node; @@ -54,6 +55,7 @@ public class DataResultTopComponent extends TopComponent implements DataResult { private static final Logger logger = Logger.getLogger(DataResultTopComponent.class.getName()); private DataResultPanel dataResultPanel; //embedded component with all the logic private boolean isMain; + private boolean lookupSet = false; private String customModeName; //keep track of tcs openeded for menu presenters @@ -96,9 +98,9 @@ public class DataResultTopComponent extends TopComponent implements DataResult { initComponents(); customizeComponent(isMain, name);; - + } - + private void customizeComponent(boolean isMain, String title) { this.isMain = isMain; this.customModeName = null; @@ -260,6 +262,21 @@ public class DataResultTopComponent extends TopComponent implements DataResult { super.componentOpened(); this.dataResultPanel.open(); + + /* @@@ Short-term hack to associate lookup with the table view so that we can do multi-select. + * Longer-term solution is to use same explorer Manager for all viewers. + */ + if (!this.lookupSet) { + List resultViewers = this.dataResultPanel.getViewers(); + for (DataResultViewer viewer : resultViewers) { + if (viewer instanceof DataResultViewerTable) { + associateLookup(ExplorerUtils.createLookup(((DataResultViewerTable)viewer).getExplorerManager(), getActionMap())); + break; + } + } + + this.lookupSet = true; + } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index 9ab0d40dea..6f5368578b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -62,7 +62,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { ov.setAllowedDropActions(DnDConstants.ACTION_NONE); // only allow one item to be selected at a time - ov.getOutline().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + ov.getOutline().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); // don't show the root node ov.getOutline().setRootVisible(false); diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java index 831cdb652e..8589b0ea7d 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java @@ -144,6 +144,10 @@ public class MediaViewImagePanel extends javax.swing.JPanel { try { //original input stream BufferedImage bi = ImageIO.read(inputStream); + if (bi == null) { + logger.log(Level.WARNING, "Could image reader not found for file: " + fileName); + return; + } //scale image using Scalr BufferedImage biScaled = ScalrWrapper.resizeHighQuality(bi, (int) dims.getWidth(), (int) dims.getHeight()); //convert from awt imageto fx image diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java index 92ee76109f..ef562ae0c4 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java @@ -86,6 +86,9 @@ class ThumbnailViewNode extends FilterNode { if (getFile(content.getId()).exists()) { try { icon = ImageIO.read(getFile(content.getId())); + if (icon == null) { + icon = ThumbnailViewNode.defaultIcon; + } } catch (IOException ex) { icon = ThumbnailViewNode.defaultIcon; } @@ -120,6 +123,10 @@ class ThumbnailViewNode extends FilterNode { try { inputStream = new ReadContentInputStream(content); BufferedImage bi = ImageIO.read(inputStream); + if (bi == null) { + logger.log(Level.WARNING, "No image reader for file: " + content.getName()); + return null; + } BufferedImage biScaled = ScalrWrapper.resizeFast(bi, 100, 100); return biScaled; }catch (OutOfMemoryError e) { diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ModuleSettings.java b/Core/src/org/sleuthkit/autopsy/coreutils/ModuleSettings.java index 117c5eb4ab..15d5e3d7a3 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ModuleSettings.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ModuleSettings.java @@ -19,12 +19,17 @@ package org.sleuthkit.autopsy.coreutils; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.logging.Level; + /** * This class contains the framework to read, add, update, and remove * from the property files located at %USERDIR%/Config/x.properties @@ -33,15 +38,12 @@ public class ModuleSettings { // The directory where the properties file is lcoated private final static String moduleDirPath = PlatformUtil.getUserConfigDirectory(); - public static final String MAIN_SETTINGS="Case"; + public static final String DEFAULT_CONTEXT = "GeneralContext"; + public static final String MAIN_SETTINGS = "Case"; - /** the constructor */ - private ModuleSettings() { - - } - - + private ModuleSettings() {} + /** * Makes a new config file of the specified name. Do not include the extension. * @param moduleName - The name of the config file to make @@ -161,9 +163,7 @@ public class ModuleSettings { return null; } } - - - + /** * Sets the given properties file to the given setting map. * @param moduleName - The name of the module to be written to. @@ -215,14 +215,12 @@ public class ModuleSettings { Logger.getLogger(ModuleSettings.class.getName()).log(Level.WARNING, "Property file exists for [" + moduleName + "] at [" + getPropertyPath(moduleName) + "] but could not be loaded.", e); } } - /** * Removes the given key from the given properties file. * @param moduleName - The name of the properties file to be modified. * @param key - the name of the key to remove. */ - public static synchronized void removeProperty(String moduleName, String key){ try{ if(getConfigSetting(moduleName, key) != null){ @@ -268,5 +266,4 @@ public class ModuleSettings { return new File(getPropertyPath(moduleName)); } } - } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java old mode 100644 new mode 100755 index a364071ac7..3c4d33c253 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -1,97 +1,97 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 Basis Technology Corp. - * Contact: carrier sleuthkit 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.TagAction; -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 { - - 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 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(new ExtractAction("Extract Directory", this)); - actions.add(null); // creates a menu separator - actions.add(new TagAction(this)); - return actions.toArray(new Action[0]); - } - - @Override - public T accept(ContentNodeVisitor v) { - return v.visit(this); - } - - @Override - public T accept(DisplayableItemNodeVisitor v) { - return v.visit(this); - } - - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.CONTENT; - } -} +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit 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 { + + 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 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 accept(ContentNodeVisitor v) { + return v.visit(this); + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + @Override + public TYPE getDisplayableItemNodeType() { + return TYPE.CONTENT; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java old mode 100644 new mode 100755 index 6c3f739624..9ca87fd8a7 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -1,181 +1,180 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 Basis Technology Corp. - * Contact: carrier sleuthkit 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.TagAction; -import org.sleuthkit.autopsy.directorytree.ViewContextAction; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.FsContent; -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 { - - /** - * @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 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(new ExtractAction("Extract File", this)); - actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); - actionsList.add(null); // creates a menu separator - actionsList.add(new TagAction(this)); - return actionsList.toArray(new Action[0]); - } - - @Override - public T accept(ContentNodeVisitor< T> v) { - return v.visit(this); - } - - @Override - public 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 Basis Technology Corp. + * Contact: carrier sleuthkit 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 { + + /** + * @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 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 accept(ContentNodeVisitor< T> v) { + return v.visit(this); + } + + @Override + public 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; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index 36f2fc8c02..9224131ad6 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -24,11 +24,10 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; -import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.TagAction; +import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.TskData; @@ -104,14 +103,12 @@ public class LayoutFileNode extends AbstractAbstractFileNode { @Override public Action[] getActions(boolean context) { List 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(new ExtractAction("Extract File", content)); + actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator - actionsList.add(new TagAction(content)); - + actionsList.add(TagAbstractFileAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index f2dc17d9a0..78711736b9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -30,9 +30,8 @@ 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.TagAction; +import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.LocalFile; /** * A Node for a LocalFile or DerivedFile content object. @@ -86,16 +85,14 @@ public class LocalFileNode extends AbstractAbstractFileNode { @Override public Action[] getActions(boolean context) { - List actionsList = new ArrayList(); - + List 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(new ExtractAction("Extract", content)); //might not need this actions - already local file + 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(new TagAction(content)); - + actionsList.add(TagAbstractFileAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 319d36e737..064f953660 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -22,7 +22,6 @@ import java.awt.event.ActionEvent; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; -import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; @@ -656,36 +655,4 @@ public class Tags implements AutopsyVisitableItem { return tagNames; } - - public interface Taggable { - void createTag(String name, String comment); - } - - public static class TaggableFile implements Taggable { - - private AbstractFile file; - - public TaggableFile(AbstractFile file) { - this.file = file; - } - - @Override - public void createTag(String name, String comment) { - Tags.createTag(file, name, comment); - } - } - - public static class TaggableBlackboardArtifact implements Taggable { - - private BlackboardArtifact bba; - - public TaggableBlackboardArtifact(BlackboardArtifact bba) { - this.bba = bba; - } - - @Override - public void createTag(String name, String comment) { - Tags.createTag(bba, name, comment); - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 59e523ff81..756a376d11 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -27,7 +27,7 @@ import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.TagAction; +import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.datamodel.TskData; @@ -76,16 +76,15 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode actions = new ArrayList(); - + List actions = new ArrayList<>(); actions.add(new NewWindowViewAction("View in New Window", this)); actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract Directory", this)); + actions.add(ExtractAction.getInstance()); actions.add(null); // creates a menu separator - actions.add(new TagAction(this)); + actions.add(TagAbstractFileAction.getInstance()); return actions.toArray(new Action[0]); } - + @Override protected Sheet createSheet() { Sheet s = super.createSheet(); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java old mode 100644 new mode 100755 index a439a066bf..e30e9b56b1 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -1,520 +1,520 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 Basis Technology Corp. - * Contact: carrier sleuthkit 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.beans.PropertyVetoException; -import java.util.ArrayList; -import java.util.List; -import org.sleuthkit.autopsy.datamodel.VolumeNode; -import org.sleuthkit.autopsy.datamodel.DirectoryNode; -import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; -import javax.swing.AbstractAction; -import javax.swing.Action; -import org.openide.explorer.ExplorerManager; -import org.openide.nodes.AbstractNode; -import org.openide.nodes.FilterNode; -import org.openide.nodes.Node; -import org.openide.nodes.Sheet; -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.LocalFileNode; -import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode; -import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode; -import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; -import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; -import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedAccountNode; -import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedFolderNode; -import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedRootNode; -import org.sleuthkit.autopsy.datamodel.ExtractedContentNode; -import org.sleuthkit.autopsy.datamodel.FileNode; -import org.sleuthkit.autopsy.datamodel.FileSearchFilterNode; -import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode; -import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode; -import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsRootNode; -import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode; -import org.sleuthkit.autopsy.datamodel.ImageNode; -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.VirtualDirectoryNode; -import org.sleuthkit.autopsy.datamodel.LayoutFileNode; -import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode; -import org.sleuthkit.autopsy.datamodel.RecentFilesNode; -import org.sleuthkit.autopsy.datamodel.SearchFiltersNode; -import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot; -import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -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.TskException; -import org.sleuthkit.datamodel.VirtualDirectory; - -/** - * This class wraps nodes as they are passed to the DataResult viewers. It - * defines the actions that the node should have. - */ -public class DataResultFilterNode extends FilterNode { - - private ExplorerManager sourceEm; - private final DisplayableItemNodeVisitor> getActionsDIV; - private final DisplayableItemNodeVisitor getPreferredActionsDIV; - - /** - * the constructor - */ - public DataResultFilterNode(Node node, ExplorerManager em) { - super(node, new DataResultFilterChildren(node, em)); - this.sourceEm = em; - getActionsDIV = new GetPopupActionsDisplayableItemNodeVisitor(); - getPreferredActionsDIV = new GetPreferredActionsDisplayableItemNodeVisitor(); - } - - /** - * Right click action for the nodes that we want to pass to the directory - * table and the output view. - * - * @param popup - * @return actions - */ - @Override - public Action[] getActions(boolean popup) { - - List actions = new ArrayList(); - - final DisplayableItemNode originalNode = (DisplayableItemNode) this.getOriginal(); - actions.addAll(originalNode.accept(getActionsDIV)); - - //actions.add(new IndexContentFilesAction(nodeContent, "Index")); - - return actions.toArray(new Action[actions.size()]); - } - - /** - * Double click action for the nodes that we want to pass to the directory - * table and the output view. - * - * @return action - */ - @Override - public Action getPreferredAction() { - // double click action(s) for volume node or directory node - - final DisplayableItemNode originalNode; - originalNode = (DisplayableItemNode) this.getOriginal(); - - return originalNode.accept(getPreferredActionsDIV); - } - - @Override - public Node.PropertySet[] getPropertySets() { - Node.PropertySet[] propertySets = super.getPropertySets(); - - for (int i = 0; i < propertySets.length; i++) { - Node.PropertySet ps = propertySets[i]; - - if (ps.getName().equals(Sheet.PROPERTIES)) { - Sheet.Set newPs = new Sheet.Set(); - newPs.setName(ps.getName()); - newPs.setDisplayName(ps.getDisplayName()); - newPs.setShortDescription(ps.getShortDescription()); - - newPs.put(ps.getProperties()); - if (newPs.remove(AbstractFsContentNode.HIDE_PARENT) != null) { - newPs.remove(AbstractFilePropertyType.LOCATION.toString()); - } - propertySets[i] = newPs; - } - } - - return propertySets; - } - - /** - * Uses the default nodes actions per node, adds some custom ones and - * returns them per visited node type - */ - private static class GetPopupActionsDisplayableItemNodeVisitor extends DisplayableItemNodeVisitor.Default> { - - @Override - public List visit(BlackboardArtifactNode ban) { - //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 - - List actions = new ArrayList(); - - //merge predefined specific node actions if bban subclasses have their own - for (Action a : ban.getActions(true)) { - actions.add(a); - } - BlackboardArtifact ba = ban.getLookup().lookup(BlackboardArtifact.class); - final int artifactTypeID = ba.getArtifactTypeID(); - - if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() - || artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - actions.add(new ViewContextAction("View File in Directory", ban)); - } else { - Content c = findLinked(ban); - if (c != null) { - actions.add(new ViewContextAction("View File in Directory", c)); - } - actions.add(new ViewContextAction("View Source File in Directory", ban)); - } - File f = ban.getLookup().lookup(File.class); - LayoutFile lf = null; - AbstractFile locF = null; - Directory d = null; - VirtualDirectory vd = null; - if (f != null) { - final FileNode fn = new FileNode(f); - actions.add(null); // creates a menu separator - actions.add(new NewWindowViewAction("View in New Window", fn)); - actions.add(new ExternalViewerAction("Open in External Viewer", fn)); - actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract File", new FileNode(f))); - actions.add(new HashSearchAction("Search for files with the same MD5 hash", fn)); - - //add file/result tag if itself is not a tag - 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(new TagAction(f)); - actions.add(new TagAction(ba)); - } - } - if ((d = ban.getLookup().lookup(Directory.class)) != null) { - DirectoryNode dn = new DirectoryNode(d); - actions.add(null); // creates a menu separator - actions.add(new NewWindowViewAction("View in New Window", dn)); - actions.add(new ExternalViewerAction("Open in External Viewer", dn)); - actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract Directory", dn)); - - //add file/result tag if itself is not a tag - 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(new TagAction(d)); - actions.add(new TagAction(ba)); - } - } - if ((vd = ban.getLookup().lookup(VirtualDirectory.class)) != null) { - VirtualDirectoryNode dn = new VirtualDirectoryNode(vd); - actions.add(null); // creates a menu separator - actions.add(new NewWindowViewAction("View in New Window", dn)); - actions.add(new ExternalViewerAction("Open in External Viewer", dn)); - actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract Directory", dn)); - - //add file/result tag if itself is not a tag - 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(new TagAction(d)); - actions.add(new TagAction(ba)); - } - } else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) { - LayoutFileNode lfn = new LayoutFileNode(lf); - actions.add(null); // creates a menu separator - actions.add(new NewWindowViewAction("View in New Window", lfn)); - actions.add(new ExternalViewerAction("Open in External Viewer", lfn)); - actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract File", lfn)); - - //add tag if itself is not a tag - 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(new TagAction(lf)); - actions.add(new TagAction(ba)); - } - } else if ((locF = ban.getLookup().lookup(LocalFile.class)) != null - || (locF = ban.getLookup().lookup(DerivedFile.class)) != null) { - final LocalFileNode locfn = new LocalFileNode(locF); - actions.add(null); // creates a menu separator - actions.add(new NewWindowViewAction("View in New Window", locfn)); - actions.add(new ExternalViewerAction("Open in External Viewer", locfn)); - actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract File", locfn)); - - //add tag if itself is not a tag - 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(new TagAction(lf)); - actions.add(new TagAction(ba)); - } - } - - return actions; - } - - @Override - protected List defaultVisit(DisplayableItemNode ditem) { - //preserve the default node's actions - List actions = new ArrayList(); - - for (Action action : ditem.getActions(true)) { - actions.add(action); - } - - return actions; - } - - private Content findLinked(BlackboardArtifactNode ba) { - BlackboardArtifact art = ba.getLookup().lookup(BlackboardArtifact.class); - Content c = null; - try { - for (BlackboardAttribute attr : art.getAttributes()) { - if (attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()) { - switch (attr.getValueType()) { - case INTEGER: - int i = attr.getValueInt(); - if (i != -1) { - c = art.getSleuthkitCase().getContentById(i); - } - break; - case LONG: - long l = attr.getValueLong(); - if (l != -1) { - c = art.getSleuthkitCase().getContentById(l); - } - break; - } - } - } - } catch (TskException ex) { - Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error getting linked file", ex); - } - return c; - } - } - - private class GetPreferredActionsDisplayableItemNodeVisitor extends DisplayableItemNodeVisitor.Default { - - @Override - public AbstractAction visit(ImageNode in) { - return openChild(in); - } - - @Override - public AbstractAction visit(VolumeNode vn) { - return openChild(vn); - } - - @Override - public AbstractAction visit(ExtractedContentNode ecn) { - return openChild(ecn); - } - - @Override - public AbstractAction visit(KeywordHitsRootNode khrn) { - return openChild(khrn); - } - - @Override - public AbstractAction visit(HashsetHitsRootNode hhrn) { - return openChild(hhrn); - } - - @Override - public AbstractAction visit(HashsetHitsSetNode hhsn) { - return openChild(hhsn); - } - - @Override - public AbstractAction visit(EmailExtractedRootNode eern) { - return openChild(eern); - } - - @Override - public AbstractAction visit(EmailExtractedAccountNode eean) { - return openChild(eean); - } - - @Override - public AbstractAction visit(EmailExtractedFolderNode eefn) { - return openChild(eefn); - } - - @Override - public AbstractAction visit(RecentFilesNode rfn) { - return openChild(rfn); - } - - @Override - public AbstractAction visit(DeletedContentsNode dcn) { - return openChild(dcn); - } - - @Override - public AbstractAction visit(DeletedContentNode dcn) { - return openChild(dcn); - } - - @Override - public AbstractAction visit(FileSizeRootNode fsrn) { - return openChild(fsrn); - } - - @Override - public AbstractAction visit(FileSizeNode fsn) { - return openChild(fsn); - } - - @Override - public AbstractAction visit(BlackboardArtifactNode ban) { - return new ViewContextAction("View in Directory", ban); - } - - @Override - public AbstractAction visit(ArtifactTypeNode atn) { - return openChild(atn); - } - - @Override - public AbstractAction visit(TagNodeRoot tnr) { - return openChild(tnr); - } - - @Override - public AbstractAction visit(TagsNodeRoot tnr) { - return openChild(tnr); - } - - @Override - public AbstractAction visit(DirectoryNode dn) { - if (dn.getDisplayName().equals(DirectoryNode.DOTDOTDIR)) { - return openParent(dn); - } else if (!dn.getDisplayName().equals(DirectoryNode.DOTDIR)) { - return openChild(dn); - } else { - return null; - } - } - - @Override - public AbstractAction visit(VirtualDirectoryNode ldn) { - return openChild(ldn); - } - - @Override - public AbstractAction visit(FileNode fn) { - if (fn.hasContentChildren()) { - return openChild(fn); - } else { - return null; - } - } - - @Override - public AbstractAction visit(LocalFileNode dfn) { - if (dfn.hasContentChildren()) { - return openChild(dfn); - } else { - return null; - } - } - - @Override - public AbstractAction visit(FileSearchFilterNode fsfn) { - return openChild(fsfn); - } - - @Override - public AbstractAction visit(SearchFiltersNode sfn) { - return openChild(sfn); - } - - @Override - public AbstractAction visit(RecentFilesFilterNode rffn) { - return openChild(rffn); - } - - @Override - public AbstractAction visit(KeywordHitsListNode khsn) { - return openChild(khsn); - } - - @Override - public AbstractAction visit(KeywordHitsKeywordNode khmln) { - return openChild(khmln); - } - - @Override - protected AbstractAction defaultVisit(DisplayableItemNode c) { - return null; - } - - private AbstractAction openChild(AbstractNode node) { - final Node[] parentNode = sourceEm.getSelectedNodes(); - final Node parentContext = parentNode[0]; - final Node original = node; - - return new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - if (parentContext != null) { - final int childrenNodesCount = parentContext.getChildren().getNodesCount(); - for (int i = 0; i < childrenNodesCount; i++) { - Node selectedNode = parentContext.getChildren().getNodeAt(i); - if (selectedNode != null && selectedNode.getName().equals(original.getName())) { - try { - sourceEm.setExploredContextAndSelection(selectedNode, new Node[]{selectedNode}); - } catch (PropertyVetoException ex) { - // throw an error here - Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); - logger.log(Level.WARNING, "Error: can't open the selected directory.", ex); - } - } - } - } - } - }; - } - - private AbstractAction openParent(AbstractNode node) { - Node[] selectedNode = sourceEm.getSelectedNodes(); - Node selectedContext = selectedNode[0]; - final Node parentNode = selectedContext.getParentNode(); - - return new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - try { - sourceEm.setSelectedNodes(new Node[]{parentNode}); - } catch (PropertyVetoException ex) { - Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); - logger.log(Level.WARNING, "Error: can't open the parent directory.", ex); - } - } - }; - } - } +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit 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.beans.PropertyVetoException; +import java.util.ArrayList; +import java.util.List; +import org.sleuthkit.autopsy.datamodel.VolumeNode; +import org.sleuthkit.autopsy.datamodel.DirectoryNode; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coreutils.Logger; +import javax.swing.AbstractAction; +import javax.swing.Action; +import org.openide.explorer.ExplorerManager; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.FilterNode; +import org.openide.nodes.Node; +import org.openide.nodes.Sheet; +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.LocalFileNode; +import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode; +import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode; +import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; +import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; +import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedAccountNode; +import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedFolderNode; +import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedRootNode; +import org.sleuthkit.autopsy.datamodel.ExtractedContentNode; +import org.sleuthkit.autopsy.datamodel.FileNode; +import org.sleuthkit.autopsy.datamodel.FileSearchFilterNode; +import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode; +import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode; +import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsRootNode; +import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode; +import org.sleuthkit.autopsy.datamodel.ImageNode; +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.VirtualDirectoryNode; +import org.sleuthkit.autopsy.datamodel.LayoutFileNode; +import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode; +import org.sleuthkit.autopsy.datamodel.RecentFilesNode; +import org.sleuthkit.autopsy.datamodel.SearchFiltersNode; +import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot; +import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +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.TskException; +import org.sleuthkit.datamodel.VirtualDirectory; + +/** + * This class wraps nodes as they are passed to the DataResult viewers. It + * defines the actions that the node should have. + */ +public class DataResultFilterNode extends FilterNode { + + private ExplorerManager sourceEm; + private final DisplayableItemNodeVisitor> getActionsDIV; + private final DisplayableItemNodeVisitor getPreferredActionsDIV; + + /** + * the constructor + */ + public DataResultFilterNode(Node node, ExplorerManager em) { + super(node, new DataResultFilterChildren(node, em)); + this.sourceEm = em; + getActionsDIV = new GetPopupActionsDisplayableItemNodeVisitor(); + getPreferredActionsDIV = new GetPreferredActionsDisplayableItemNodeVisitor(); + } + + /** + * Right click action for the nodes that we want to pass to the directory + * table and the output view. + * + * @param popup + * @return actions + */ + @Override + public Action[] getActions(boolean popup) { + + List actions = new ArrayList<>(); + + final DisplayableItemNode originalNode = (DisplayableItemNode) this.getOriginal(); + actions.addAll(originalNode.accept(getActionsDIV)); + + //actions.add(new IndexContentFilesAction(nodeContent, "Index")); + + return actions.toArray(new Action[actions.size()]); + } + + /** + * Double click action for the nodes that we want to pass to the directory + * table and the output view. + * + * @return action + */ + @Override + public Action getPreferredAction() { + // double click action(s) for volume node or directory node + + final DisplayableItemNode originalNode; + originalNode = (DisplayableItemNode) this.getOriginal(); + + return originalNode.accept(getPreferredActionsDIV); + } + + @Override + public Node.PropertySet[] getPropertySets() { + Node.PropertySet[] propertySets = super.getPropertySets(); + + for (int i = 0; i < propertySets.length; i++) { + Node.PropertySet ps = propertySets[i]; + + if (ps.getName().equals(Sheet.PROPERTIES)) { + Sheet.Set newPs = new Sheet.Set(); + newPs.setName(ps.getName()); + newPs.setDisplayName(ps.getDisplayName()); + newPs.setShortDescription(ps.getShortDescription()); + + newPs.put(ps.getProperties()); + if (newPs.remove(AbstractFsContentNode.HIDE_PARENT) != null) { + newPs.remove(AbstractFilePropertyType.LOCATION.toString()); + } + propertySets[i] = newPs; + } + } + + return propertySets; + } + + /** + * Uses the default nodes actions per node, adds some custom ones and + * returns them per visited node type + */ + private static class GetPopupActionsDisplayableItemNodeVisitor extends DisplayableItemNodeVisitor.Default> { + + @Override + public List visit(BlackboardArtifactNode ban) { + //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 + + List actions = new ArrayList<>(); + + //merge predefined specific node actions if bban subclasses have their own + for (Action a : ban.getActions(true)) { + actions.add(a); + } + BlackboardArtifact ba = ban.getLookup().lookup(BlackboardArtifact.class); + final int artifactTypeID = ba.getArtifactTypeID(); + + if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + || artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { + actions.add(new ViewContextAction("View File in Directory", ban)); + } else { + Content c = findLinked(ban); + if (c != null) { + actions.add(new ViewContextAction("View File in Directory", c)); + } + actions.add(new ViewContextAction("View Source File in Directory", ban)); + } + File f = ban.getLookup().lookup(File.class); + LayoutFile lf = null; + AbstractFile locF = null; + Directory d = null; + VirtualDirectory vd = null; + if (f != null) { + final FileNode fn = new FileNode(f); + actions.add(null); // creates a menu separator + actions.add(new NewWindowViewAction("View in New Window", fn)); + actions.add(new ExternalViewerAction("Open in External Viewer", fn)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance()); + actions.add(new HashSearchAction("Search for files with the same MD5 hash", fn)); + + //add file/result tag if itself is not a tag + 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()); + } + } + if ((d = ban.getLookup().lookup(Directory.class)) != null) { + DirectoryNode dn = new DirectoryNode(d); + actions.add(null); // creates a menu separator + actions.add(new NewWindowViewAction("View in New Window", dn)); + actions.add(new ExternalViewerAction("Open in External Viewer", dn)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance()); + + //add file/result tag if itself is not a tag + 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()); + } + } + if ((vd = ban.getLookup().lookup(VirtualDirectory.class)) != null) { + VirtualDirectoryNode dn = new VirtualDirectoryNode(vd); + actions.add(null); // creates a menu separator + actions.add(new NewWindowViewAction("View in New Window", dn)); + actions.add(new ExternalViewerAction("Open in External Viewer", dn)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance()); + + //add file/result tag if itself is not a tag + 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()); + } + } else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) { + LayoutFileNode lfn = new LayoutFileNode(lf); + actions.add(null); // creates a menu separator + actions.add(new NewWindowViewAction("View in New Window", lfn)); + actions.add(new ExternalViewerAction("Open in External Viewer", lfn)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance()); + + //add tag if itself is not a tag + 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()); + } + } else if ((locF = ban.getLookup().lookup(LocalFile.class)) != null + || (locF = ban.getLookup().lookup(DerivedFile.class)) != null) { + final LocalFileNode locfn = new LocalFileNode(locF); + actions.add(null); // creates a menu separator + actions.add(new NewWindowViewAction("View in New Window", locfn)); + actions.add(new ExternalViewerAction("Open in External Viewer", locfn)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance()); + + //add tag if itself is not a tag + 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()); + } + } + + return actions; + } + + @Override + protected List defaultVisit(DisplayableItemNode ditem) { + //preserve the default node's actions + List actions = new ArrayList<>(); + + for (Action action : ditem.getActions(true)) { + actions.add(action); + } + + return actions; + } + + private Content findLinked(BlackboardArtifactNode ba) { + BlackboardArtifact art = ba.getLookup().lookup(BlackboardArtifact.class); + Content c = null; + try { + for (BlackboardAttribute attr : art.getAttributes()) { + if (attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()) { + switch (attr.getValueType()) { + case INTEGER: + int i = attr.getValueInt(); + if (i != -1) { + c = art.getSleuthkitCase().getContentById(i); + } + break; + case LONG: + long l = attr.getValueLong(); + if (l != -1) { + c = art.getSleuthkitCase().getContentById(l); + } + break; + } + } + } + } catch (TskException ex) { + Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error getting linked file", ex); + } + return c; + } + } + + private class GetPreferredActionsDisplayableItemNodeVisitor extends DisplayableItemNodeVisitor.Default { + + @Override + public AbstractAction visit(ImageNode in) { + return openChild(in); + } + + @Override + public AbstractAction visit(VolumeNode vn) { + return openChild(vn); + } + + @Override + public AbstractAction visit(ExtractedContentNode ecn) { + return openChild(ecn); + } + + @Override + public AbstractAction visit(KeywordHitsRootNode khrn) { + return openChild(khrn); + } + + @Override + public AbstractAction visit(HashsetHitsRootNode hhrn) { + return openChild(hhrn); + } + + @Override + public AbstractAction visit(HashsetHitsSetNode hhsn) { + return openChild(hhsn); + } + + @Override + public AbstractAction visit(EmailExtractedRootNode eern) { + return openChild(eern); + } + + @Override + public AbstractAction visit(EmailExtractedAccountNode eean) { + return openChild(eean); + } + + @Override + public AbstractAction visit(EmailExtractedFolderNode eefn) { + return openChild(eefn); + } + + @Override + public AbstractAction visit(RecentFilesNode rfn) { + return openChild(rfn); + } + + @Override + public AbstractAction visit(DeletedContentsNode dcn) { + return openChild(dcn); + } + + @Override + public AbstractAction visit(DeletedContentNode dcn) { + return openChild(dcn); + } + + @Override + public AbstractAction visit(FileSizeRootNode fsrn) { + return openChild(fsrn); + } + + @Override + public AbstractAction visit(FileSizeNode fsn) { + return openChild(fsn); + } + + @Override + public AbstractAction visit(BlackboardArtifactNode ban) { + return new ViewContextAction("View in Directory", ban); + } + + @Override + public AbstractAction visit(ArtifactTypeNode atn) { + return openChild(atn); + } + + @Override + public AbstractAction visit(TagNodeRoot tnr) { + return openChild(tnr); + } + + @Override + public AbstractAction visit(TagsNodeRoot tnr) { + return openChild(tnr); + } + + @Override + public AbstractAction visit(DirectoryNode dn) { + if (dn.getDisplayName().equals(DirectoryNode.DOTDOTDIR)) { + return openParent(dn); + } else if (!dn.getDisplayName().equals(DirectoryNode.DOTDIR)) { + return openChild(dn); + } else { + return null; + } + } + + @Override + public AbstractAction visit(VirtualDirectoryNode ldn) { + return openChild(ldn); + } + + @Override + public AbstractAction visit(FileNode fn) { + if (fn.hasContentChildren()) { + return openChild(fn); + } else { + return null; + } + } + + @Override + public AbstractAction visit(LocalFileNode dfn) { + if (dfn.hasContentChildren()) { + return openChild(dfn); + } else { + return null; + } + } + + @Override + public AbstractAction visit(FileSearchFilterNode fsfn) { + return openChild(fsfn); + } + + @Override + public AbstractAction visit(SearchFiltersNode sfn) { + return openChild(sfn); + } + + @Override + public AbstractAction visit(RecentFilesFilterNode rffn) { + return openChild(rffn); + } + + @Override + public AbstractAction visit(KeywordHitsListNode khsn) { + return openChild(khsn); + } + + @Override + public AbstractAction visit(KeywordHitsKeywordNode khmln) { + return openChild(khmln); + } + + @Override + protected AbstractAction defaultVisit(DisplayableItemNode c) { + return null; + } + + private AbstractAction openChild(AbstractNode node) { + final Node[] parentNode = sourceEm.getSelectedNodes(); + final Node parentContext = parentNode[0]; + final Node original = node; + + return new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (parentContext != null) { + final int childrenNodesCount = parentContext.getChildren().getNodesCount(); + for (int i = 0; i < childrenNodesCount; i++) { + Node selectedNode = parentContext.getChildren().getNodeAt(i); + if (selectedNode != null && selectedNode.getName().equals(original.getName())) { + try { + sourceEm.setExploredContextAndSelection(selectedNode, new Node[]{selectedNode}); + } catch (PropertyVetoException ex) { + // throw an error here + Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); + logger.log(Level.WARNING, "Error: can't open the selected directory.", ex); + } + } + } + } + } + }; + } + + private AbstractAction openParent(AbstractNode node) { + Node[] selectedNode = sourceEm.getSelectedNodes(); + Node selectedContext = selectedNode[0]; + final Node parentNode = selectedContext.getParentNode(); + + return new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + try { + sourceEm.setSelectedNodes(new Node[]{parentNode}); + } catch (PropertyVetoException ex) { + Logger logger = Logger.getLogger(DataResultFilterNode.class.getName()); + logger.log(Level.WARNING, "Error: can't open the parent directory.", ex); + } + } + }; + } + } } \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java old mode 100644 new mode 100755 index 018679ae2c..d71ea25216 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java @@ -1,160 +1,159 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 Basis Technology Corp. - * Contact: carrier sleuthkit 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.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.logging.Level; -import javax.swing.AbstractAction; -import javax.swing.Action; -import org.openide.nodes.FilterNode; -import org.openide.nodes.Node; -import org.openide.util.lookup.Lookups; -import org.openide.util.lookup.ProxyLookup; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.AbstractContentNode; -import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; -import org.sleuthkit.autopsy.ingest.IngestDialog; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.Directory; -import org.sleuthkit.datamodel.Image; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * This class sets the actions for the nodes in the directory tree and creates - * the children filter so that files and such are hidden from the tree. - * - */ -class DirectoryTreeFilterNode extends FilterNode { - - private static final Action collapseAll = new CollapseAction("Collapse All"); - private static final Logger logger = Logger.getLogger(DirectoryTreeFilterNode.class.getName()); - - /** - * the constructor - */ - DirectoryTreeFilterNode(Node arg, boolean createChildren) { - super(arg, DirectoryTreeFilterChildren.createInstance(arg, createChildren), - new ProxyLookup(Lookups.singleton(new OriginalNode(arg)), - arg.getLookup())); - } - - @Override - public String getDisplayName() { - final Node orig = getOriginal(); - - String name = orig.getDisplayName(); - - //do not show children counts for non content nodes - if (orig instanceof AbstractContentNode) { - //show only for file content nodes - AbstractFile file = getLookup().lookup(AbstractFile.class); - if (file != null) { - try { - final int numChildren = file.getChildrenCount(); - name = name + " (" + numChildren + ")"; - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting children count to display for file: " + file, ex); - } - - } - } - - return name; - } - - /** - * Right click action for the nodes in the directory tree. - * - * @param popup - * @return - */ - @Override - public Action[] getActions(boolean popup) { - List actions = new ArrayList(); - - final Content content = this.getLookup().lookup(Content.class); - if (content != null) { - actions.addAll(DirectoryTreeFilterNode.getDetailActions(content)); - - //extract dir action - Directory dir = this.getLookup().lookup(Directory.class); - if (dir != null) { - actions.add(new ExtractAction("Extract Directory", - getOriginal())); - } - - // file search action - final Image img = this.getLookup().lookup(Image.class); - if (img != null) { - actions.add(new FileSearchAction("Open File Search by Attributes")); - } - - //ingest action - actions.add(new AbstractAction("Run Ingest Modules") { - @Override - public void actionPerformed(ActionEvent e) { - final IngestDialog ingestDialog = new IngestDialog(); - ingestDialog.setContent(Collections.singletonList(content)); - ingestDialog.display(); - } - }); - } - - //check if delete actions should be added - final Node orig = getOriginal(); - //TODO add a mechanism to determine if DisplayableItemNode - if (orig instanceof DisplayableItemNode) { - actions.addAll(getDeleteActions((DisplayableItemNode) orig)); - } - - actions.add(collapseAll); - return actions.toArray(new Action[actions.size()]); - } - - private static List getDeleteActions(DisplayableItemNode original) { - List actions = new ArrayList(); - //actions.addAll(original.accept(getDeleteActionVisitor)); - return actions; - } - - private static List getDetailActions(Content c) { - List actions = new ArrayList(); - - actions.addAll(ExplorerNodeActionVisitor.getActions(c)); - - return actions; - } -} - -class OriginalNode { - - private Node original; - - OriginalNode(Node original) { - this.original = original; - } - - Node getNode() { - return original; - } +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit 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.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import javax.swing.AbstractAction; +import javax.swing.Action; +import org.openide.nodes.FilterNode; +import org.openide.nodes.Node; +import org.openide.util.lookup.Lookups; +import org.openide.util.lookup.ProxyLookup; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.AbstractContentNode; +import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; +import org.sleuthkit.autopsy.ingest.IngestDialog; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.Directory; +import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * This class sets the actions for the nodes in the directory tree and creates + * the children filter so that files and such are hidden from the tree. + * + */ +class DirectoryTreeFilterNode extends FilterNode { + + private static final Action collapseAll = new CollapseAction("Collapse All"); + private static final Logger logger = Logger.getLogger(DirectoryTreeFilterNode.class.getName()); + + /** + * the constructor + */ + DirectoryTreeFilterNode(Node arg, boolean createChildren) { + super(arg, DirectoryTreeFilterChildren.createInstance(arg, createChildren), + new ProxyLookup(Lookups.singleton(new OriginalNode(arg)), + arg.getLookup())); + } + + @Override + public String getDisplayName() { + final Node orig = getOriginal(); + + String name = orig.getDisplayName(); + + //do not show children counts for non content nodes + if (orig instanceof AbstractContentNode) { + //show only for file content nodes + AbstractFile file = getLookup().lookup(AbstractFile.class); + if (file != null) { + try { + final int numChildren = file.getChildrenCount(); + name = name + " (" + numChildren + ")"; + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error getting children count to display for file: " + file, ex); + } + + } + } + + return name; + } + + /** + * Right click action for the nodes in the directory tree. + * + * @param popup + * @return + */ + @Override + public Action[] getActions(boolean popup) { + List actions = new ArrayList(); + + final Content content = this.getLookup().lookup(Content.class); + if (content != null) { + actions.addAll(DirectoryTreeFilterNode.getDetailActions(content)); + + //extract dir action + Directory dir = this.getLookup().lookup(Directory.class); + if (dir != null) { + actions.add(ExtractAction.getInstance()); + } + + // file search action + final Image img = this.getLookup().lookup(Image.class); + if (img != null) { + actions.add(new FileSearchAction("Open File Search by Attributes")); + } + + //ingest action + actions.add(new AbstractAction("Run Ingest Modules") { + @Override + public void actionPerformed(ActionEvent e) { + final IngestDialog ingestDialog = new IngestDialog(); + ingestDialog.setContent(Collections.singletonList(content)); + ingestDialog.display(); + } + }); + } + + //check if delete actions should be added + final Node orig = getOriginal(); + //TODO add a mechanism to determine if DisplayableItemNode + if (orig instanceof DisplayableItemNode) { + actions.addAll(getDeleteActions((DisplayableItemNode) orig)); + } + + actions.add(collapseAll); + return actions.toArray(new Action[actions.size()]); + } + + private static List getDeleteActions(DisplayableItemNode original) { + List actions = new ArrayList(); + //actions.addAll(original.accept(getDeleteActionVisitor)); + return actions; + } + + private static List getDetailActions(Content c) { + List actions = new ArrayList(); + + actions.addAll(ExplorerNodeActionVisitor.getActions(c)); + + return actions; + } +} + +class OriginalNode { + + private Node original; + + OriginalNode(Node original) { + this.original = original; + } + + Node getNode() { + return original; + } } \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java old mode 100644 new mode 100755 index 28479e83c3..90c1eded2e --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java @@ -1,383 +1,383 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 Basis Technology Corp. - * Contact: carrier sleuthkit 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.Toolkit; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.logging.Level; -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JTable; -import javax.swing.table.DefaultTableModel; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentVisitor; -import org.sleuthkit.datamodel.DerivedFile; -import org.sleuthkit.datamodel.Directory; -import org.sleuthkit.datamodel.FileSystem; -import org.sleuthkit.datamodel.Image; -import org.sleuthkit.datamodel.LocalFile; -import org.sleuthkit.datamodel.VirtualDirectory; -import org.sleuthkit.datamodel.Volume; - -public class ExplorerNodeActionVisitor extends ContentVisitor.Default> { - - private static ExplorerNodeActionVisitor instance = new ExplorerNodeActionVisitor(); - - public static List getActions(Content c) { - List actions = new ArrayList(); - - actions.addAll(c.accept(instance)); - //TODO: fix this - /* - while (c.isOnto()) { - try { - List children = c.getChildren(); - if (!children.isEmpty()) { - c = c.getChildren().get(0); - } else { - return actions; - } - } catch (TskException ex) { - Log.get(ExplorerNodeActionVisitor.class).log(Level.WARNING, "Error getting show detail actions.", ex); - return actions; - } - actions.addAll(c.accept(instance)); - }*/ - return actions; - } - - ExplorerNodeActionVisitor() { - } - - @Override - public List visit(final Image img) { - List lst = new ArrayList(); - lst.add(new ImageDetails("Image Details", img)); - //TODO lst.add(new ExtractAction("Extract Image", img)); - lst.add(new ExtractUnallocAction("Extract Unallocated Space to Single Files", img)); - return lst; - } - - @Override - public List visit(final FileSystem fs) { - return Collections.singletonList(new FileSystemDetails("File System Details", fs)); - } - - @Override - public List visit(final Volume vol) { - List lst = new ArrayList(); - lst.add(new VolumeDetails("Volume Details", vol)); - lst.add(new ExtractUnallocAction("Extract Unallocated Space to Single File", vol)); - return lst; - } - - @Override - public List visit(final Directory d) { - List actions = new ArrayList(); - actions.add(new TagAction(d)); - return actions; - } - - @Override - public List visit(final VirtualDirectory d) { - List actions = new ArrayList(); - actions.add(new TagAction(d)); - actions.add(new ExtractAction("Extract Directory", d)); - return actions; - } - - @Override - public List visit(final DerivedFile d) { - List actions = new ArrayList(); - actions.add(new ExtractAction("Extract File", d)); - actions.add(new TagAction(d)); - return actions; - } - - @Override - public List visit(final LocalFile d) { - List actions = new ArrayList(); - actions.add(new ExtractAction("Extract File", d)); - actions.add(new TagAction(d)); - return actions; - } - - @Override - public List visit(final org.sleuthkit.datamodel.File d) { - List actions = new ArrayList(); - actions.add(new ExtractAction("Extract File", d)); - actions.add(new TagAction(d)); - return actions; - } - - @Override - protected List defaultVisit(Content di) { - return Collections.emptyList(); - } - - //Below here are classes regarding node-specific actions - /** - * VolumeDetails class - */ - private class VolumeDetails extends AbstractAction { - - private final String title; - private final Volume vol; - - VolumeDetails(String title, Volume vol) { - super(title); - this.title = title; - this.vol = vol; - } - - @Override - public void actionPerformed(ActionEvent e) { - Logger.noteAction(ExplorerNodeActionVisitor.class); - - final JFrame frame = new JFrame(title); - final JDialog popUpWindow = new JDialog(frame, title, true); // to make the popUp Window to be modal - - - Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); - - // set the popUp window / JFrame - popUpWindow.setSize(800, 400); - - int w = popUpWindow.getSize().width; - int h = popUpWindow.getSize().height; - - // set the location of the popUp Window on the center of the screen - popUpWindow.setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); - - VolumeDetailsPanel volumeDetailPanel = new VolumeDetailsPanel(); - Boolean counter = false; - - volumeDetailPanel.setVolumeIDValue(Long.toString(vol.getAddr())); - volumeDetailPanel.setStartValue(Long.toString(vol.getStart())); - volumeDetailPanel.setLengthValue(Long.toString(vol.getLength())); - volumeDetailPanel.setDescValue(vol.getDescription()); - volumeDetailPanel.setFlagsValue(vol.getFlagsAsString()); - counter = true; - - if (counter) { - // add the volume detail panel to the popUp window - popUpWindow.add(volumeDetailPanel); - } else { - // error handler if no volume matches - JLabel error = new JLabel("Error: No Volume Matches."); - error.setFont(new Font("Arial", Font.BOLD, 24)); - popUpWindow.add(error); - } - - // add the command to close the window to the button on the Volume Detail Panel - volumeDetailPanel.setOKButtonActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - popUpWindow.dispose(); - } - }); - popUpWindow.pack(); - popUpWindow.setResizable(false); - popUpWindow.setVisible(true); - - } - } - - /** - * ImageDetails panel class - */ - private class ImageDetails extends AbstractAction { - - final String title; - final Image img; - - ImageDetails(String title, Image img) { - super(title); - this.title = title; - this.img = img; - } - - @Override - public void actionPerformed(ActionEvent e) { - Logger.noteAction(ExplorerNodeActionVisitor.class); - - final JFrame frame = new JFrame(title); - final JDialog popUpWindow = new JDialog(frame, title, true); // to make the popUp Window to be modal - // if we select the Image Details menu - - Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); - - // set the popUp window / JFrame - popUpWindow.setSize(750, 400); - - int w = popUpWindow.getSize().width; - int h = popUpWindow.getSize().height; - - // set the location of the popUp Window on the center of the screen - popUpWindow.setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); - - ImageDetailsPanel imgDetailPanel = new ImageDetailsPanel(); - Boolean counter = false; - - imgDetailPanel.setImgNameValue(img.getName()); - imgDetailPanel.setImgTypeValue(Image.imageTypeToString(img.getType())); - imgDetailPanel.setImgSectorSizeValue(Long.toString(img.getSsize())); - counter = true; - - if (counter) { - // add the volume detail panel to the popUp window - popUpWindow.add(imgDetailPanel); - } else { - // error handler if no volume matches - JLabel error = new JLabel("Error: No Volume Matches."); - error.setFont(new Font("Arial", Font.BOLD, 24)); - popUpWindow.add(error); - } - - // add the command to close the window to the button on the Volume Detail Panel - imgDetailPanel.setOKButtonActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - popUpWindow.dispose(); - } - }); - - - popUpWindow.pack(); - popUpWindow.setResizable(false); - popUpWindow.setVisible(true); - } - } - - /** - * FileSystemDetails class - */ - private class FileSystemDetails extends AbstractAction { - - private final FileSystem fs; - private final String title; - - FileSystemDetails(String title, FileSystem fs) { - super(title); - this.title = title; - this.fs = fs; - } - - @Override - public void actionPerformed(ActionEvent e) { - Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); - - Logger.noteAction(ExplorerNodeActionVisitor.class); - - final JFrame frame = new JFrame(title); - final JDialog popUpWindow = new JDialog(frame, title, true); // to make the popUp Window to be modal - - // set the popUp window / JFrame - - popUpWindow.setSize(1000, 500); - - int w = popUpWindow.getSize().width; - int h = popUpWindow.getSize().height; - - // set the location of the popUp Window on the center of the screen - popUpWindow.setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); - - String[] columnNames = new String[]{ - "fs_id", - "img_offset", - "par_id", - "fs_type", - "block_size", - "block_count", - "root_inum", - "first_inum", - "last_inum" - }; - - Object[][] rowValues = new Object[1][9]; - - Content parent = null; - try { - parent = fs.getParent(); - } catch (Exception ex) { - throw new RuntimeException("Problem getting parent from " + FileSystem.class.getName() + ": " + fs, ex); - } - long id = -1; - if (parent != null) { - id = parent.getId(); - } - - Arrays.fill(rowValues, 0, 1, new Object[]{ - fs.getId(), - fs.getImageOffset(), - id, - fs.getFsType(), - fs.getBlock_size(), - fs.getBlock_count(), - fs.getRoot_inum(), - fs.getFirst_inum(), - fs.getLastInum() - }); - - - JTable table = new JTable(new DefaultTableModel(rowValues, columnNames)); - - FileSystemDetailsPanel fsdPanel = new FileSystemDetailsPanel(); - - // add the command to close the window to the button on the Volume Detail Panel - fsdPanel.setOKButtonActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - popUpWindow.dispose(); - } - }); - - try { - fsdPanel.setFileSystemTypeValue(table.getValueAt(0, 3).toString()); - fsdPanel.setImageOffsetValue(table.getValueAt(0, 1).toString()); - fsdPanel.setVolumeIDValue(table.getValueAt(0, 2).toString()); //TODO: fix this to parent id, not vol id - fsdPanel.setBlockSizeValue(table.getValueAt(0, 4).toString()); - fsdPanel.setBlockCountValue(table.getValueAt(0, 5).toString()); - fsdPanel.setRootInumValue(table.getValueAt(0, 6).toString()); - fsdPanel.setFirstInumValue(table.getValueAt(0, 7).toString()); - fsdPanel.setLastInumValue(table.getValueAt(0, 8).toString()); - - popUpWindow.add(fsdPanel); - } catch (Exception ex) { - Logger.getLogger(ExplorerNodeActionVisitor.class.getName()).log(Level.WARNING, "Error setting up File System Details panel.", ex); - } - - popUpWindow.pack(); - popUpWindow.setResizable(false); - popUpWindow.setVisible(true); - - } - } +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit 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.Toolkit; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.table.DefaultTableModel; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentVisitor; +import org.sleuthkit.datamodel.DerivedFile; +import org.sleuthkit.datamodel.Directory; +import org.sleuthkit.datamodel.FileSystem; +import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.VirtualDirectory; +import org.sleuthkit.datamodel.Volume; + +public class ExplorerNodeActionVisitor extends ContentVisitor.Default> { + + private static ExplorerNodeActionVisitor instance = new ExplorerNodeActionVisitor(); + + public static List getActions(Content c) { + List actions = new ArrayList(); + + actions.addAll(c.accept(instance)); + //TODO: fix this + /* + while (c.isOnto()) { + try { + List children = c.getChildren(); + if (!children.isEmpty()) { + c = c.getChildren().get(0); + } else { + return actions; + } + } catch (TskException ex) { + Log.get(ExplorerNodeActionVisitor.class).log(Level.WARNING, "Error getting show detail actions.", ex); + return actions; + } + actions.addAll(c.accept(instance)); + }*/ + return actions; + } + + ExplorerNodeActionVisitor() { + } + + @Override + public List visit(final Image img) { + List lst = new ArrayList(); + lst.add(new ImageDetails("Image Details", img)); + //TODO lst.add(new ExtractAction("Extract Image", img)); + lst.add(new ExtractUnallocAction("Extract Unallocated Space to Single Files", img)); + return lst; + } + + @Override + public List visit(final FileSystem fs) { + return Collections.singletonList(new FileSystemDetails("File System Details", fs)); + } + + @Override + public List visit(final Volume vol) { + List lst = new ArrayList(); + lst.add(new VolumeDetails("Volume Details", vol)); + lst.add(new ExtractUnallocAction("Extract Unallocated Space to Single File", vol)); + return lst; + } + + @Override + public List visit(final Directory d) { + List actions = new ArrayList(); + actions.add(TagAbstractFileAction.getInstance()); + return actions; + } + + @Override + public List visit(final VirtualDirectory d) { + List actions = new ArrayList(); + actions.add(ExtractAction.getInstance()); + actions.add(TagAbstractFileAction.getInstance()); + return actions; + } + + @Override + public List visit(final DerivedFile d) { + List actions = new ArrayList(); + actions.add(ExtractAction.getInstance()); + actions.add(TagAbstractFileAction.getInstance()); + return actions; + } + + @Override + public List visit(final LocalFile d) { + List actions = new ArrayList(); + actions.add(ExtractAction.getInstance()); + actions.add(TagAbstractFileAction.getInstance()); + return actions; + } + + @Override + public List visit(final org.sleuthkit.datamodel.File d) { + List actions = new ArrayList(); + actions.add(ExtractAction.getInstance()); + actions.add(TagAbstractFileAction.getInstance()); + return actions; + } + + @Override + protected List defaultVisit(Content di) { + return Collections.emptyList(); + } + + //Below here are classes regarding node-specific actions + /** + * VolumeDetails class + */ + private class VolumeDetails extends AbstractAction { + + private final String title; + private final Volume vol; + + VolumeDetails(String title, Volume vol) { + super(title); + this.title = title; + this.vol = vol; + } + + @Override + public void actionPerformed(ActionEvent e) { + Logger.noteAction(ExplorerNodeActionVisitor.class); + + final JFrame frame = new JFrame(title); + final JDialog popUpWindow = new JDialog(frame, title, true); // to make the popUp Window to be modal + + + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); + + // set the popUp window / JFrame + popUpWindow.setSize(800, 400); + + int w = popUpWindow.getSize().width; + int h = popUpWindow.getSize().height; + + // set the location of the popUp Window on the center of the screen + popUpWindow.setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); + + VolumeDetailsPanel volumeDetailPanel = new VolumeDetailsPanel(); + Boolean counter = false; + + volumeDetailPanel.setVolumeIDValue(Long.toString(vol.getAddr())); + volumeDetailPanel.setStartValue(Long.toString(vol.getStart())); + volumeDetailPanel.setLengthValue(Long.toString(vol.getLength())); + volumeDetailPanel.setDescValue(vol.getDescription()); + volumeDetailPanel.setFlagsValue(vol.getFlagsAsString()); + counter = true; + + if (counter) { + // add the volume detail panel to the popUp window + popUpWindow.add(volumeDetailPanel); + } else { + // error handler if no volume matches + JLabel error = new JLabel("Error: No Volume Matches."); + error.setFont(new Font("Arial", Font.BOLD, 24)); + popUpWindow.add(error); + } + + // add the command to close the window to the button on the Volume Detail Panel + volumeDetailPanel.setOKButtonActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + popUpWindow.dispose(); + } + }); + popUpWindow.pack(); + popUpWindow.setResizable(false); + popUpWindow.setVisible(true); + + } + } + + /** + * ImageDetails panel class + */ + private class ImageDetails extends AbstractAction { + + final String title; + final Image img; + + ImageDetails(String title, Image img) { + super(title); + this.title = title; + this.img = img; + } + + @Override + public void actionPerformed(ActionEvent e) { + Logger.noteAction(ExplorerNodeActionVisitor.class); + + final JFrame frame = new JFrame(title); + final JDialog popUpWindow = new JDialog(frame, title, true); // to make the popUp Window to be modal + // if we select the Image Details menu + + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); + + // set the popUp window / JFrame + popUpWindow.setSize(750, 400); + + int w = popUpWindow.getSize().width; + int h = popUpWindow.getSize().height; + + // set the location of the popUp Window on the center of the screen + popUpWindow.setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); + + ImageDetailsPanel imgDetailPanel = new ImageDetailsPanel(); + Boolean counter = false; + + imgDetailPanel.setImgNameValue(img.getName()); + imgDetailPanel.setImgTypeValue(Image.imageTypeToString(img.getType())); + imgDetailPanel.setImgSectorSizeValue(Long.toString(img.getSsize())); + counter = true; + + if (counter) { + // add the volume detail panel to the popUp window + popUpWindow.add(imgDetailPanel); + } else { + // error handler if no volume matches + JLabel error = new JLabel("Error: No Volume Matches."); + error.setFont(new Font("Arial", Font.BOLD, 24)); + popUpWindow.add(error); + } + + // add the command to close the window to the button on the Volume Detail Panel + imgDetailPanel.setOKButtonActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + popUpWindow.dispose(); + } + }); + + + popUpWindow.pack(); + popUpWindow.setResizable(false); + popUpWindow.setVisible(true); + } + } + + /** + * FileSystemDetails class + */ + private class FileSystemDetails extends AbstractAction { + + private final FileSystem fs; + private final String title; + + FileSystemDetails(String title, FileSystem fs) { + super(title); + this.title = title; + this.fs = fs; + } + + @Override + public void actionPerformed(ActionEvent e) { + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); + + Logger.noteAction(ExplorerNodeActionVisitor.class); + + final JFrame frame = new JFrame(title); + final JDialog popUpWindow = new JDialog(frame, title, true); // to make the popUp Window to be modal + + // set the popUp window / JFrame + + popUpWindow.setSize(1000, 500); + + int w = popUpWindow.getSize().width; + int h = popUpWindow.getSize().height; + + // set the location of the popUp Window on the center of the screen + popUpWindow.setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); + + String[] columnNames = new String[]{ + "fs_id", + "img_offset", + "par_id", + "fs_type", + "block_size", + "block_count", + "root_inum", + "first_inum", + "last_inum" + }; + + Object[][] rowValues = new Object[1][9]; + + Content parent = null; + try { + parent = fs.getParent(); + } catch (Exception ex) { + throw new RuntimeException("Problem getting parent from " + FileSystem.class.getName() + ": " + fs, ex); + } + long id = -1; + if (parent != null) { + id = parent.getId(); + } + + Arrays.fill(rowValues, 0, 1, new Object[]{ + fs.getId(), + fs.getImageOffset(), + id, + fs.getFsType(), + fs.getBlock_size(), + fs.getBlock_count(), + fs.getRoot_inum(), + fs.getFirst_inum(), + fs.getLastInum() + }); + + + JTable table = new JTable(new DefaultTableModel(rowValues, columnNames)); + + FileSystemDetailsPanel fsdPanel = new FileSystemDetailsPanel(); + + // add the command to close the window to the button on the Volume Detail Panel + fsdPanel.setOKButtonActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + popUpWindow.dispose(); + } + }); + + try { + fsdPanel.setFileSystemTypeValue(table.getValueAt(0, 3).toString()); + fsdPanel.setImageOffsetValue(table.getValueAt(0, 1).toString()); + fsdPanel.setVolumeIDValue(table.getValueAt(0, 2).toString()); //TODO: fix this to parent id, not vol id + fsdPanel.setBlockSizeValue(table.getValueAt(0, 4).toString()); + fsdPanel.setBlockCountValue(table.getValueAt(0, 5).toString()); + fsdPanel.setRootInumValue(table.getValueAt(0, 6).toString()); + fsdPanel.setFirstInumValue(table.getValueAt(0, 7).toString()); + fsdPanel.setLastInumValue(table.getValueAt(0, 8).toString()); + + popUpWindow.add(fsdPanel); + } catch (Exception ex) { + Logger.getLogger(ExplorerNodeActionVisitor.class.getName()).log(Level.WARNING, "Error setting up File System Details panel.", ex); + } + + popUpWindow.pack(); + popUpWindow.setResizable(false); + popUpWindow.setVisible(true); + + } + } } \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java index 6b183644f1..1442cb57cd 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.directorytree; import java.awt.Component; import java.awt.event.ActionEvent; import java.io.File; +import java.util.Collection; import java.util.concurrent.CancellationException; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; @@ -30,83 +31,37 @@ import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; -import org.openide.nodes.Node; import org.openide.util.Cancellable; +import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentVisitor; -import org.sleuthkit.datamodel.Directory; /** * Exports files and folders */ public final class ExtractAction extends AbstractAction { - - private static final InitializeContentVisitor initializeCV = new InitializeContentVisitor(); - private AbstractFile content; private Logger logger = Logger.getLogger(ExtractAction.class.getName()); - public ExtractAction(String title, Node contentNode) { - super(title); - Content tempContent = contentNode.getLookup().lookup(Content.class); + // 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 ExtractAction instance; - this.content = tempContent.accept(initializeCV); - this.setEnabled(content != null); - } - - public ExtractAction(String title, Content content) { - super(title); + public static synchronized ExtractAction getInstance() { + if (null == instance) { + instance = new ExtractAction(); + } - this.content = content.accept(initializeCV); - this.setEnabled(this.content != null); + return instance; } - /** - * Returns the FsContent if it is supported, otherwise null - */ - private static class InitializeContentVisitor extends ContentVisitor.Default { - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.File f) { - return f; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.LayoutFile lf) { - return lf; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.DerivedFile df) { - return df; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.LocalFile lf) { - return lf; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.VirtualDirectory vd) { - return vd; - } - - @Override - public AbstractFile visit(Directory dir) { - return ContentUtils.isDotDirectory(dir) ? null : dir; - } - - @Override - protected AbstractFile defaultVisit(Content cntnt) { - return null; - } + private ExtractAction() { + super("Extract"); } - + /** * Asks user to choose destination, then extracts content/directory to * destination (recursing on directories) @@ -114,10 +69,17 @@ public final class ExtractAction extends AbstractAction { */ @Override public void actionPerformed(ActionEvent e) { + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + for (AbstractFile file : selectedFiles) { + extractFile(e, file); + } + } + + private void extractFile(ActionEvent e, AbstractFile file) { // Get content and check that it's okay to overwrite existing content JFileChooser fc = new JFileChooser(); fc.setCurrentDirectory(new File(Case.getCurrentCase().getCaseDirectory())); - fc.setSelectedFile(new File(this.content.getName())); + fc.setSelectedFile(new File(file.getName())); int returnValue = fc.showSaveDialog((Component) e.getSource()); if (returnValue == JFileChooser.APPROVE_OPTION) { @@ -144,12 +106,12 @@ public final class ExtractAction extends AbstractAction { try { ExtractFileThread extract = new ExtractFileThread(); - extract.init(this.content, e, destination); + extract.init(file, e, destination); extract.execute(); } catch (Exception ex) { logger.log(Level.WARNING, "Unable to start background thread.", ex); } - } + } } private class ExtractFileThread extends SwingWorker { @@ -230,6 +192,5 @@ public final class ExtractAction extends AbstractAction { } } } - } - + } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java new file mode 100755 index 0000000000..657673ac74 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java @@ -0,0 +1,70 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit 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 selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + for (AbstractFile file : selectedFiles) { + Tags.createTag(file, tagName, comment); + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagAction.java deleted file mode 100644 index 35c755c0e2..0000000000 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagAction.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 Basis Technology Corp. - * Contact: carrier sleuthkit 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.logging.Level; -import javax.swing.AbstractAction; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import org.openide.nodes.Node; -import org.openide.util.actions.Presenter; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentVisitor; -import org.sleuthkit.datamodel.Directory; - -/** - * Action on a file or artifact that adds a tag and - * reloads the directory tree. Supports tagging of AbstractFiles and - * BlackboardArtifacts. - * - * TODO add use enters description and hierarchy (TSK_TAG_NAME with slashes) - */ -public class TagAction extends AbstractAction implements Presenter.Popup { - - private static final Logger logger = Logger.getLogger(TagAction.class.getName()); - private JMenu tagMenu; - private final InitializeBookmarkFileV initializer = new InitializeBookmarkFileV(); - - public TagAction(Node contentNode) { - AbstractFile file = contentNode.getLookup().lookup(AbstractFile.class); - if (file != null) { - tagMenu = new TagMenu(file); - return; - } - - BlackboardArtifact bba = contentNode.getLookup().lookup(BlackboardArtifact.class); - if (bba != null) { - tagMenu = new TagMenu(bba); - return; - } - - logger.log(Level.SEVERE, "Tried to create a " + TagAction.class.getName() - + " using a Node whose lookup did not contain an AbstractFile or a BlackboardArtifact."); - } - - public TagAction(AbstractFile file) { - tagMenu = new TagMenu(file); - } - - public TagAction(BlackboardArtifact bba) { - tagMenu = new TagMenu(bba); - } - - @Override - public JMenuItem getPopupPresenter() { - return tagMenu; - } - - /** - * Returns the FsContent if it is supported, otherwise null - */ - private static class InitializeBookmarkFileV extends ContentVisitor.Default { - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.File f) { - return f; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.LayoutFile lf) { - return lf; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.DerivedFile lf) { - return lf; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.LocalFile lf) { - return lf; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.VirtualDirectory ld) { - return ld; - } - - @Override - public AbstractFile visit(Directory dir) { - return ContentUtils.isDotDirectory(dir) ? null : dir; - } - - @Override - protected AbstractFile defaultVisit(Content cntnt) { - return null; - } - } - - @Override - public void actionPerformed(ActionEvent e) { - // Do nothing - this action should never be performed - // Submenu actions are invoked instead - } -} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagAndCommentDialog.java index a36a78809b..6a66e55689 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagAndCommentDialog.java @@ -30,28 +30,50 @@ import javax.swing.JFrame; import javax.swing.KeyStroke; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.datamodel.Tags; -import org.sleuthkit.autopsy.datamodel.Tags.Taggable; -import org.sleuthkit.datamodel.BlackboardArtifact; /** * Tag dialog for tagging files and results. User enters an optional comment. */ public class TagAndCommentDialog extends JDialog { - private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; - private static final String BOOKMARK_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png"; - private static final String NO_TAG_MESSAGE = "No Tags"; - - private Taggable taggable; + private static final String NO_TAG_MESSAGE = "No Tags"; + private String tagName = ""; + private String comment = ""; + public static class CommentedTag { + private String name; + private String comment; + + CommentedTag(String name, String comment) { + this.name = name; + this.comment = comment; + } + + public String getName() { + return name; + } + + public String getComment() { + return comment; + } + } + + public static CommentedTag doDialog() { + TagAndCommentDialog dialog = new TagAndCommentDialog(); + if (!dialog.tagName.isEmpty()) { + return new CommentedTag(dialog.tagName, dialog.comment); + } + else { + return null; + } + } + /** * Creates new form TagDialog */ - public TagAndCommentDialog(Taggable taggable) { + private TagAndCommentDialog() { super((JFrame)WindowManager.getDefault().getMainWindow(), "Tag and Comment", true); - this.taggable = taggable; - initComponents(); // Close the dialog when Esc is pressed @@ -60,8 +82,8 @@ public class TagAndCommentDialog extends JDialog { inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); ActionMap actionMap = getRootPane().getActionMap(); actionMap.put(cancelName, new AbstractAction() { + @Override public void actionPerformed(ActionEvent e) { - //doClose(RET_CANCEL); dispose(); } }); @@ -81,15 +103,10 @@ public class TagAndCommentDialog extends JDialog { //center it this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); - - customizeComponent(); setVisible(true); // blocks } - - private void customizeComponent() { - } - + /** * 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 @@ -195,22 +212,12 @@ public class TagAndCommentDialog extends JDialog { }// //GEN-END:initComponents private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - //doClose(RET_OK); - - // get the selected tag and comment - String selectedTag = (String)tagCombo.getSelectedItem(); - String comment = commentText.getText(); - - // create the tag - taggable.createTag(selectedTag, comment); - - refreshDirectoryTree(); - + tagName = (String)tagCombo.getSelectedItem(); + comment = commentText.getText(); dispose(); }//GEN-LAST:event_okButtonActionPerformed private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed - //doClose(RET_CANCEL); dispose(); }//GEN-LAST:event_cancelButtonActionPerformed @@ -218,14 +225,12 @@ public class TagAndCommentDialog extends JDialog { * Closes the dialog */ private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog - //doClose(RET_CANCEL); dispose(); }//GEN-LAST:event_closeDialog private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed String newTagName = CreateTagDialog.getNewTagNameDialog(null); if (newTagName != null) { - //tagsModel.addElement(newTagName); tagCombo.addItem(newTagName); tagCombo.setSelectedItem(newTagName); } @@ -240,12 +245,4 @@ public class TagAndCommentDialog extends JDialog { private javax.swing.JComboBox tagCombo; private javax.swing.JLabel tagLabel; // End of variables declaration//GEN-END:variables - //private int returnStatus = RET_CANCEL; - - 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); - } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java new file mode 100755 index 0000000000..3d1a9641b3 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java @@ -0,0 +1,71 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit 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 selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); + for (BlackboardArtifact artifact : selectedArtifacts) { + Tags.createTag(artifact, tagName, comment); + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagMenu.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagMenu.java index af432e199a..e329dde10c 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagMenu.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagMenu.java @@ -24,38 +24,20 @@ import java.util.List; import javax.swing.JMenu; import javax.swing.JMenuItem; import org.sleuthkit.autopsy.datamodel.Tags; -import org.sleuthkit.autopsy.datamodel.Tags.Taggable; -import org.sleuthkit.autopsy.datamodel.Tags.TaggableBlackboardArtifact; -import org.sleuthkit.autopsy.datamodel.Tags.TaggableFile; -import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; /** * The menu that results when one right-clicks on a file or artifact. */ -public class TagMenu extends JMenu { - - private Taggable tagCreator; - - public TagMenu(AbstractFile file) { - super("Tag File"); - tagCreator = new TaggableFile(file); - init(); - } - - public TagMenu(BlackboardArtifact bba) { - super("Tag Result"); - tagCreator = new TaggableBlackboardArtifact(bba); - init(); - } +public abstract class TagMenu extends JMenu { + public TagMenu(String menuItemText) { + super(menuItemText); - private void init() { - - // create the 'Quick Tag' menu and add it to the 'Tag File' menu + // Create the 'Quick Tag' sub-menu and add it to the tag menu. JMenu quickTagMenu = new JMenu("Quick Tag"); - add(quickTagMenu); - - // create the 'Quick Tag' sub-menu items and add them to the 'Quick Tag' menu + add(quickTagMenu); + + // Get the existing tag names. List tagNames = Tags.getTagNames(); if (tagNames.isEmpty()) { JMenuItem empty = new JMenuItem("No tags"); @@ -63,50 +45,56 @@ public class TagMenu extends JMenu { quickTagMenu.add(empty); } + // Add a menu item for each existing tag name to the 'Quick Tag' menu. for (final String tagName : tagNames) { - JMenuItem tagItem = new JMenuItem(tagName); - tagItem.addActionListener(new ActionListener() { + JMenuItem tagNameItem = new JMenuItem(tagName); + tagNameItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - tagCreator.createTag(tagName, ""); + applyTag(tagName, ""); refreshDirectoryTree(); } }); - quickTagMenu.add(tagItem); + quickTagMenu.add(tagNameItem); } quickTagMenu.addSeparator(); - // create the 'New Tag' menu item + // 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 newTagName = CreateTagDialog.getNewTagNameDialog(null); - if (newTagName != null) { - tagCreator.createTag(newTagName, ""); + String tagName = CreateTagDialog.getNewTagNameDialog(null); + if (tagName != null) { + applyTag(tagName, ""); refreshDirectoryTree(); } } }); - - // add the 'New Tag' menu item to the 'Quick Tag' menu quickTagMenu.add(newTagMenuItem); - JMenuItem newTagItem = new JMenuItem("Tag and Comment"); - newTagItem.addActionListener(new ActionListener() { + // 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) { - new TagAndCommentDialog(tagCreator); + TagAndCommentDialog.CommentedTag commentedTag = TagAndCommentDialog.doDialog(); + if (null != commentedTag) { + applyTag(commentedTag.getName(), commentedTag.getComment()); + refreshDirectoryTree(); + } } }); - add(newTagItem); + 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); } diff --git a/Core/src/org/sleuthkit/autopsy/examples/SampleDataSourceIngestModule.java b/Core/src/org/sleuthkit/autopsy/examples/SampleDataSourceIngestModule.java new file mode 100755 index 0000000000..e6061fdd76 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/examples/SampleDataSourceIngestModule.java @@ -0,0 +1,125 @@ +/* +* Sample module in the public domain. Feel free to use this as a template +* for your modules. +* +* Contact: Brian Carrier [carrier sleuthkit [dot] org] +* +* This is free and unencumbered software released into the public domain. +* +* Anyone is free to copy, modify, publish, use, compile, sell, or +* distribute this software, either in source code form or as a compiled +* binary, for any purpose, commercial or non-commercial, and by any +* means. +* +* In jurisdictions that recognize copyright laws, the author or authors +* of this software dedicate any and all copyright interest in the +* software to the public domain. We make this dedication for the benefit +* of the public at large and to the detriment of our heirs and +* successors. We intend this dedication to be an overt act of +* relinquishment in perpetuity of all present and future rights to this +* software under copyright law. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +package org.sleuthkit.autopsy.examples; + +import java.util.List; +import org.apache.log4j.Logger; +import org.openide.util.Exceptions; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.FileManager; +import org.sleuthkit.autopsy.casemodule.services.Services; +import org.sleuthkit.autopsy.ingest.IngestDataSourceWorkerController; +import org.sleuthkit.autopsy.ingest.IngestModuleDataSource; +import org.sleuthkit.autopsy.ingest.IngestModuleInit; +import org.sleuthkit.autopsy.ingest.PipelineContext; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.FsContent; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Sample DataSource-level ingest module that doesn't do much at all. + * Just exists to show basic idea of these modules + */ +public class SampleDataSourceIngestModule extends org.sleuthkit.autopsy.ingest.IngestModuleDataSource { + + /* Data Source modules operate on a disk or set of logical files. They + * are passed in teh data source refernce and query it for things they want. + */ + @Override + public void process(PipelineContext pipelineContext, Content dataSource, IngestDataSourceWorkerController controller) { + + Case case1 = Case.getCurrentCase(); + SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); + + Services services = new Services(sleuthkitCase); + FileManager fm = services.getFileManager(); + try { + /* you can use the findFiles method in FileManager (or similar ones in + * SleuthkitCase to find files based only on their name. This + * one finds files that have a .doc extension. */ + List docFiles = fm.findFiles(dataSource, "%.doc"); + for (AbstractFile file : docFiles) { + // do something with each doc file + } + + /* We can also do more general queries with findFilesWhere, which + * allows us to make our own WHERE clause in the database. + */ + long currentTime = System.currentTimeMillis()/1000; + // go back 2 weeks + long minTime = currentTime - (14 * 24 * 60 * 60); + List otherFiles = sleuthkitCase.findFilesWhere("crtime > " + minTime); + // do something with these files... + + } catch (TskCoreException ex) { + Logger log = Logger.getLogger(SampleDataSourceIngestModule.class); + log.fatal("Error retrieving files from database: " + ex.getLocalizedMessage()); + return; + } + } + + @Override + public void init(IngestModuleInit initContext) { + // do nothing + } + + @Override + public void complete() { + // do nothing + } + + @Override + public void stop() { + // do nothing + } + + @Override + public String getName() { + return "SampleDataSourceIngestModule"; + } + + @Override + public String getVersion() { + return "1.0"; + } + + @Override + public String getDescription() { + return "Doesn't do much"; + } + + @Override + public boolean hasBackgroundJobsRunning() { + return false; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/examples/SampleFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/examples/SampleFileIngestModule.java new file mode 100755 index 0000000000..e4152604c0 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/examples/SampleFileIngestModule.java @@ -0,0 +1,178 @@ +/* +* Sample module in the public domain. Feel free to use this as a template +* for your modules. +* +* Contact: Brian Carrier [carrier sleuthkit [dot] org] +* +* This is free and unencumbered software released into the public domain. +* +* Anyone is free to copy, modify, publish, use, compile, sell, or +* distribute this software, either in source code form or as a compiled +* binary, for any purpose, commercial or non-commercial, and by any +* means. +* +* In jurisdictions that recognize copyright laws, the author or authors +* of this software dedicate any and all copyright interest in the +* software to the public domain. We make this dedication for the benefit +* of the public at large and to the detriment of our heirs and +* successors. We intend this dedication to be an overt act of +* relinquishment in perpetuity of all present and future rights to this +* software under copyright law. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +package org.sleuthkit.autopsy.examples; + +import org.apache.log4j.Logger; +import org.openide.util.Exceptions; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile; +import org.sleuthkit.autopsy.ingest.IngestModuleInit; +import org.sleuthkit.autopsy.ingest.PipelineContext; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskData; + +/** + * This is a sample and simple module. It is a file-level ingest module, meaning + * that it will get called on each file in the disk image / logical file set. + * It does a stupid calculation of the number of null bytes in the beginning of the + * file in order to show the basic flow. + * + * Autopsy has been hard coded to ignore this module based on the it's package name. + * IngestModuleLoader will not load things from the org.sleuthkit.autopsy.examples package. + * Either change the package or the loading code to make this module actually run. + */ +public class SampleFileIngestModule extends org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile { + private int attrId = -1; + private static SampleFileIngestModule defaultInstance = null; + + // Private to ensure Singleton status + private SampleFileIngestModule() { + } + + // File-level ingest modules are currently singleton -- this is required + public static synchronized SampleFileIngestModule getDefault() { + //defaultInstance is a private static class variable + if (defaultInstance == null) { + defaultInstance = new SampleFileIngestModule(); + } + return defaultInstance; + } + + + @Override + public void init(IngestModuleInit initContext) { + /* For this demo, we are going to make a private attribute to post our + * results to the blackbaord with. There are many standard blackboard artifact + * and attribute types and you should first consider using one of those before + * making private ones because other modules won't know about provate ones. + * Because our demo has results that have no real value, we do not have an + * official attribute for them. + */ + Case case1 = Case.getCurrentCase(); + SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); + + // see if the type already exists in the blackboard. + try { + attrId = sleuthkitCase.getAttrTypeID("ATTR_SAMPLE"); + } catch (TskCoreException ex) { + // create it if not + try { + attrId = sleuthkitCase.addAttrType("ATTR_SAMPLE", "Sample Attribute"); + } catch (TskCoreException ex1) { + Logger log = Logger.getLogger(SampleFileIngestModule.class); + log.fatal("Error adding attribute type: " + ex1.getLocalizedMessage()); + attrId = -1; + } + } + } + + @Override + public ProcessResult process(PipelineContext pipelineContext, AbstractFile abstractFile) { + // skip non-files + if ((abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) || + (abstractFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) { + return ProcessResult.OK; + } + + // skip NSRL / known files + if (abstractFile.getKnown() == TskData.FileKnown.KNOWN) { + return ProcessResult.OK; + } + + + /* Do a non-sensical calculation of the number of 0x00 bytes + * in the first 1024-bytes of the file. This is for demo + * purposes only. + */ + try { + byte buffer[] = new byte[1024]; + int len = abstractFile.read(buffer, 0, 1024); + int count = 0; + for (int i = 0; i < len; i++) { + if (buffer[i] == 0x00) { + count++; + } + } + + if (attrId != -1) { + // Make an attribute using the ID for the private type that we previously created. + BlackboardAttribute attr = new BlackboardAttribute(attrId, getName(), count); + + /* add it to the general info artifact. In real modules, you would likely have + * more complex data types and be making more specific artifacts. + */ + BlackboardArtifact art = abstractFile.getGenInfoArtifact(); + art.addAttribute(attr); + } + + return ProcessResult.OK; + } catch (TskCoreException ex) { + Exceptions.printStackTrace(ex); + return ProcessResult.ERROR; + } + } + + + @Override + public void complete() { + + } + + @Override + public void stop() { + + } + + @Override + public String getVersion() { + return "1.0"; + } + + @Override + public String getName() { + return "SampleFileIngestModule"; + } + + @Override + public String getDescription() { + return "Doesn't do much"; + } + + @Override + public boolean hasBackgroundJobsRunning() { + // we're single threaded... + return false; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestDialog.java index 01cfba4239..5305700839 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestDialog.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestDialog.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,36 +26,37 @@ import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.List; -import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JPanel; +import org.openide.util.Lookup; +import org.sleuthkit.autopsy.casemodule.GeneralIngestConfigurator; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.autopsy.casemodule.IngestConfigurator; /** - * IngestDialog shown on Case.CASE_ADD_IMAGE property change + * Dialog box that allows ingest modules to be run on an image. + * Used outside of the wizards. */ public class IngestDialog extends JDialog { private static final String TITLE = "Ingest Modules"; private static Dimension DIMENSIONS = new Dimension(500, 300); - private IngestDialogPanel panel = null; + private IngestConfigurator ingestConfigurator; - private static final Logger logger = Logger.getLogger(IngestDialog.class.getName()); - public IngestDialog(JFrame frame, String title, boolean modal) { super(frame, title, modal); - panel = new IngestDialogPanel(); + ingestConfigurator = new GeneralIngestConfigurator(); + ingestConfigurator.setContext(IngestDialog.class.getCanonicalName()); + ingestConfigurator.reload(); } public IngestDialog(){ this(new JFrame(TITLE), TITLE, true); } - - /** * Shows the Ingest dialog. */ @@ -71,17 +72,15 @@ public class IngestDialog extends JDialog { // set the location of the popUp Window on the center of the screen setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); - panel.reload(); // reload the simple panel - add(panel, BorderLayout.PAGE_START); + add(ingestConfigurator.getIngestConfigPanel(), BorderLayout.PAGE_START); JButton startButton = new JButton("Start"); JButton closeButton = new JButton("Close"); startButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - - panel.save(); - panel.start(); + ingestConfigurator.save(); + ingestConfigurator.start(); close(); } }); @@ -89,7 +88,7 @@ public class IngestDialog extends JDialog { @Override public void actionPerformed(ActionEvent e) { - panel.save(); + ingestConfigurator.save(); close(); } }); @@ -97,7 +96,7 @@ public class IngestDialog extends JDialog { @Override public void windowClosing(WindowEvent e) { - panel.save(); + ingestConfigurator.save(); close(); } }); @@ -113,11 +112,10 @@ public class IngestDialog extends JDialog { setResizable(false); setVisible(true); } - + public void setContent(List inputContent) { - panel.setContent(inputContent); - } - + ingestConfigurator.setContent(inputContent); + } /** * Closes the Ingest dialog @@ -126,6 +124,4 @@ public class IngestDialog extends JDialog { setVisible(false); dispose(); } - - } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestDialogPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestDialogPanel.java index d6e65d2bac..b5308da4ce 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestDialogPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestDialogPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,24 +18,15 @@ */ package org.sleuthkit.autopsy.ingest; -import java.awt.Color; import java.awt.Component; -import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; +import java.util.AbstractMap; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; -import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; @@ -43,80 +34,55 @@ import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableColumn; -import org.openide.util.lookup.ServiceProvider; -import org.sleuthkit.autopsy.casemodule.IngestConfigurator; import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationDialog; import org.sleuthkit.autopsy.coreutils.ModuleSettings; -import org.sleuthkit.autopsy.ingest.IngestModuleAbstract.ModuleType; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.TskCoreException; /** * main configuration panel for all ingest modules, reusable JPanel component */ -@ServiceProvider(service = IngestConfigurator.class) -public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfigurator { +public class IngestDialogPanel extends javax.swing.JPanel { - private IngestManager manager = null; - private List modules; private IngestModuleAbstract currentModule; - private Map moduleStates; private ModulesTableModel tableModel; - private static final Logger logger = Logger.getLogger(IngestDialogPanel.class.getName()); public static final String DISABLED_MOD = "Disabled_Ingest_Modules"; public static final String PARSE_UNALLOC = "Process_Unallocated_Space"; - // The input content that's just been added to the database - private List inputContent; - // private static IngestDialogPanel instance = null; + private String context; /** * Creates new form IngestDialogPanel */ public IngestDialogPanel() { tableModel = new ModulesTableModel(); - modules = new ArrayList(); - moduleStates = new HashMap(); + context = ModuleSettings.DEFAULT_CONTEXT; initComponents(); customizeComponents(); } + + public void setContext(String context) { + this.context = context; + } + - private void loadModules() { - this.modules.clear(); - //this.moduleStates.clear(); maintain the state - Collection imageModules = manager.enumerateDataSourceModules(); - for (final IngestModuleDataSource module : imageModules) { - addModule(module); - } - Collection fsModules = manager.enumerateAbstractFileModules(); - for (final IngestModuleAbstractFile module : fsModules) { - addModule(module); - } + public IngestModuleAbstract getCurrentIngestModule() { + return currentModule; + } + + public List getModulesToStart() { + return tableModel.getSelectedModules(); + } + + public boolean processUnallocSpaceEnabled() { + return processUnallocCheckbox.isSelected(); } private void customizeComponents() { modulesTable.setModel(tableModel); - this.manager = IngestManager.getDefault(); - - loadModules(); - try { - IngestModuleLoader.getDefault().addModulesReloadedListener(new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(IngestModuleLoader.Event.ModulesReloaded.toString())) { - loadModules(); - } - } - }); - } catch (IngestModuleLoaderException ex) { - logger.log(Level.SEVERE, "Could not initialize ingest module loader to listen for module config changes", ex); - } - modulesTable.setTableHeader(null); modulesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); //custom renderer for tooltips - ModulesTableRenderer renderer = new ModulesTableRenderer(); + //customize column witdhs final int width = modulesScrollPane.getPreferredSize().width; TableColumn column = null; @@ -135,40 +101,30 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi public void valueChanged(ListSelectionEvent e) { ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource(); if (!listSelectionModel.isSelectionEmpty()) { - save(); int index = listSelectionModel.getMinSelectionIndex(); - currentModule = modules.get(index); - reload(); + currentModule = tableModel.getModule(index); + + // add the module-specific configuration panel, if there is one + simplePanel.removeAll(); + if (currentModule.hasSimpleConfiguration()) { + simplePanel.add(currentModule.getSimpleConfiguration(context)); + } + simplePanel.revalidate(); + simplePanel.repaint(); advancedButton.setEnabled(currentModule.hasAdvancedConfiguration()); } else { currentModule = null; } } }); - - processUnallocCheckbox.setSelected(manager.getProcessUnallocSpace()); - } - private void setProcessUnallocSpaceEnabled(boolean enabled) { - processUnallocCheckbox.setEnabled(enabled); + public void setProcessUnallocSpaceEnabled(final boolean enabled) { + processUnallocCheckbox.setSelected(enabled); } - - @Override - public void paint(Graphics g) { - super.paint(g); - if (manager.isIngestRunning()) { - setProcessUnallocSpaceEnabled(false); - - } else { - setProcessUnallocSpaceEnabled(true); - } - } - - private void addModule(IngestModuleAbstract module) { - final String moduleName = module.getName(); - modules.add(module); - moduleStates.put(moduleName, true); + + public void setDisabledModules(List disabledModules) { + tableModel.setUnselectedModules(disabledModules); } /** @@ -311,22 +267,19 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi public void actionPerformed(ActionEvent e) { dialog.close(); currentModule.saveAdvancedConfiguration(); - reload(); } }); dialog.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { dialog.close(); - reload(); } }); - save(); // save the simple panel - dialog.display(currentModule.getAdvancedConfiguration(null)); + dialog.display(currentModule.getAdvancedConfiguration(context)); }//GEN-LAST:event_advancedButtonActionPerformed private void processUnallocCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_processUnallocCheckboxActionPerformed - // TODO add your handling code here: + // nothing to do here }//GEN-LAST:event_processUnallocCheckboxActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton advancedButton; @@ -342,10 +295,19 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi // End of variables declaration//GEN-END:variables private class ModulesTableModel extends AbstractTableModel { + + private List>moduleData = new ArrayList<>(); + + public ModulesTableModel() { + List modules = IngestManager.getDefault().enumerateAllModules(); + for (IngestModuleAbstract ingestModuleAbstract : modules) { + moduleData.add(new AbstractMap.SimpleEntry<>(ingestModuleAbstract, Boolean.TRUE)); + } + } @Override public int getRowCount() { - return modules.size(); + return moduleData.size(); } @Override @@ -355,11 +317,11 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi @Override public Object getValueAt(int rowIndex, int columnIndex) { - String name = modules.get(rowIndex).getName(); + Map.Entry entry = moduleData.get(rowIndex); if (columnIndex == 0) { - return moduleStates.get(name); + return entry.getValue(); } else { - return name; + return entry.getKey().getName(); } } @@ -371,8 +333,7 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if (columnIndex == 0) { - moduleStates.put((String) getValueAt(rowIndex, 1), (Boolean) aValue); - + moduleData.get(rowIndex).setValue((Boolean)aValue); } } @@ -380,183 +341,96 @@ public class IngestDialogPanel extends javax.swing.JPanel implements IngestConfi public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); } - } - - List getModulesToStart() { - List modulesToStart = new ArrayList(); - for (IngestModuleAbstract module : modules) { - boolean moduleEnabled = moduleStates.get(module.getName()); - if (moduleEnabled) { - modulesToStart.add(module); - } - } - return modulesToStart; - } - - private boolean processUnallocSpaceEnabled() { - return processUnallocCheckbox.isEnabled(); - } - - /** - * To be called whenever the next, close, or start buttons are pressed. - * - */ - @Override - public void save() { - // Save the current module - if (currentModule != null && currentModule.hasSimpleConfiguration()) { - currentModule.saveSimpleConfiguration(); - } - // Save this panel - List modulesDisabled = new ArrayList(); - for (int i = 0; i < modulesTable.getRowCount(); i++) { - // Column 0 is always the module's checkbox (which is retreived as a boolean) - Boolean enabled = (Boolean) modulesTable.getValueAt(i, 0); - if (!enabled) { - // Column 1 is always the module name - String moduleName = (String) modulesTable.getValueAt(i, 1); - modulesDisabled.add(moduleName); - } - } - // Add all the enabled modules to the properties separated by a coma - String list = ""; - for (int i = 0; i < modulesDisabled.size(); i++) { - list += modulesDisabled.get(i); - if (i + 1 < modulesDisabled.size()) { - list += ", "; - } - } - ModuleSettings.setConfigSetting(IngestManager.MODULE_PROPERTIES, DISABLED_MOD, list); - String processUnalloc = Boolean.toString(processUnallocCheckbox.isSelected()); - ModuleSettings.setConfigSetting(IngestManager.MODULE_PROPERTIES, PARSE_UNALLOC, processUnalloc); - - } - - /** - * Called when the dialog needs to be reloaded. Most commonly used to - * refresh the simple panel. - * - * Called every time this panel is displayed. - */ - @Override - public void reload() { - // Reload the simple panel - if (this.modulesTable.getSelectedRow() != -1) { - simplePanel.removeAll(); - if (currentModule.hasSimpleConfiguration()) { - simplePanel.add(currentModule.getSimpleConfiguration(null)); - } - simplePanel.revalidate(); - simplePanel.repaint(); - } - // Reload this panel - String list = ModuleSettings.getConfigSetting(IngestManager.MODULE_PROPERTIES, DISABLED_MOD); - if (list != null) { // if no property is found, list will be null - List modulesDisabled = new ArrayList(Arrays.asList(list.split(", "))); - // For every row, see if that module name is in the ArrayList - for (int i = 0; i < modulesTable.getRowCount(); i++) { - String moduleName = (String) modulesTable.getValueAt(i, 1); - if (modulesDisabled.contains(moduleName)) { - modulesTable.setValueAt(false, i, 0); // we found it, disable the module - } else { - modulesTable.setValueAt(true, i, 0); // not on disabled list, or a new module, enable it + + public List getSelectedModules() { + List selectedModules = new ArrayList<>(); + for (Map.Entry entry : moduleData) { + if (entry.getValue().booleanValue()) { + selectedModules.add(entry.getKey()); } } + return selectedModules; } - String processUnalloc = ModuleSettings.getConfigSetting(IngestManager.MODULE_PROPERTIES, PARSE_UNALLOC); - if (processUnalloc != null) { - processUnallocCheckbox.setSelected(Boolean.parseBoolean(processUnalloc)); + + /** + * Sets the given modules as selected in the modules table + * @param selectedModules + */ + public void setSelectedModules(List selectedModules) { + // unselect all modules + for (Map.Entry entry : moduleData) { + entry.setValue(Boolean.FALSE); + } + + // select only the given modules + for (IngestModuleAbstract selectedModule : selectedModules) { + getEntryForModule(selectedModule).setValue(Boolean.TRUE); + } + + // tell everyone about it + fireTableDataChanged(); } - } - - @Override - public JPanel getIngestConfigPanel() { - this.reload(); - return this; - } - - @Override - public void setContent(List inputContent) { - this.inputContent = inputContent; - } - - @Override - public void start() { - //pick the modules - List modulesToStart = getModulesToStart(); - - //update ingest proc. unalloc space - if (processUnallocSpaceEnabled()) { - manager.setProcessUnallocSpace(processUnallocCheckbox.isSelected()); + + /** + * Sets the given modules as NOT selected in the modules table + * @param selectedModules + */ + public void setUnselectedModules(List unselectedModules) { + // select all modules + for (Map.Entry entry : moduleData) { + entry.setValue(Boolean.TRUE); + } + + // unselect only the given modules + for (IngestModuleAbstract unselectedModule : unselectedModules) { + getEntryForModule(unselectedModule).setValue(Boolean.FALSE); + } + + // tell everyone about it + fireTableDataChanged(); } - - if (!modulesToStart.isEmpty()) { - manager.execute(modulesToStart, inputContent); + + public IngestModuleAbstract getModule(int row) { + return moduleData.get(row).getKey(); + } + + private Map.Entry getEntryForModule(IngestModuleAbstract module) { + Map.Entry entry = null; + for (Map.Entry anEntry : moduleData) { + if (anEntry.getKey().equals(module)) { + entry = anEntry; + break; + } + } + return entry; } - - } - - @Override - public boolean isIngestRunning() { - return manager.isIngestRunning(); } /** * Custom cell renderer for tooltips with module description */ private class ModulesTableRenderer extends DefaultTableCellRenderer { + + List tooltips = new ArrayList<>(); + + public ModulesTableRenderer() { + List modules = IngestManager.getDefault().enumerateAllModules(); + for (IngestModuleAbstract ingestModuleAbstract : modules) { + tooltips.add(ingestModuleAbstract.getDescription()); + } + } @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, - int row, int column) { - - final Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (column == 1) { - //String moduleName = (String) table.getModel().getValueAt(row, column); - IngestModuleAbstract module = modules.get(row); - String moduleDescr = module.getDescription(); - String toolTip = moduleDescr; - - if (inputContent != null && module.getType().equals(ModuleType.DataSource)) { - - //DataSource module accepts only data source, does not work on any child - //show warning to user and set fg red for that module - boolean isDataSource = true; - for (Content content : inputContent) { - try { - if (content.getParent() != null) { - isDataSource = false; - break; - } - } catch (TskCoreException e) { - logger.log(Level.SEVERE, "Error checking if module input content is parentless data source", e); - } - - } - - if (! isDataSource ) { - cell.setForeground(Color.red); - toolTip = toolTip + "
WARNING: this module will not run on current selection because it operates only on root-level data-source (such as Image, Filesets)."; - } - else { - cell.setForeground(Color.black); - } - - - - } //end data source - else { - cell.setForeground(Color.black); - } - // - - setToolTipText("" + toolTip+ ""); + setToolTipText(tooltips.get(row)); } - - return cell; + return this; } } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index a1ddb6e3d2..77df96496a 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012 Basis Technology Corp. + * Copyright 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -154,8 +154,6 @@ public class IngestManager { } catch (IngestModuleLoaderException ex) { logger.log(Level.SEVERE, "Error getting module loader"); } - - } /** @@ -243,7 +241,6 @@ public class IngestManager { if (ui != null) { ui.restoreMessages(); } - } /** @@ -346,17 +343,15 @@ public class IngestManager { } } } - //} - //AbstractFile ingester boolean startAbstractFileIngester = false; if (fileScheduler.hasNext()) { - if (abstractFileIngester - == null) { + if (abstractFileIngester == null) { startAbstractFileIngester = true; logger.log(Level.INFO, "Starting initial AbstractFile ingester"); - } //if worker had completed, restart it in case data is still enqueued + } + //if worker had completed, restart it in case data is still enqueued else if (abstractFileIngester.isDone()) { startAbstractFileIngester = true; logger.log(Level.INFO, "Restarting AbstractFile ingester"); @@ -369,6 +364,9 @@ public class IngestManager { stats = new IngestManagerStats(); abstractFileIngester = new IngestAbstractFileProcessor(); //init all fs modules, everytime new worker starts + /* @@@ I don't understand why we do an init on each module. Should do only modules + * that we are going to be using in the pipeline + */ for (IngestModuleAbstractFile s : abstractFileModules) { IngestModuleInit moduleInit = new IngestModuleInit(); try { @@ -421,7 +419,6 @@ public class IngestManager { List toStop = new ArrayList(); toStop.addAll(dataSourceIngesters); - for (IngestDataSourceThread dataSourceWorker : toStop) { IngestModuleDataSource s = dataSourceWorker.getModule(); @@ -440,7 +437,6 @@ public class IngestManager { logger.log(Level.WARNING, "Exception while stopping module: " + s.getName(), e); } } - } logger.log(Level.INFO, "stopped all"); @@ -545,7 +541,6 @@ public class IngestManager { return module.hasBackgroundJobsRunning(); } - } else { //data source module synchronized (this) { @@ -570,10 +565,7 @@ public class IngestManager { return false; } } - } - - } /** @@ -607,7 +599,7 @@ public class IngestManager { * * @param processUnallocSpace */ - void setProcessUnallocSpace(boolean processUnallocSpace) { + public void setProcessUnallocSpace(boolean processUnallocSpace) { this.processUnallocSpace = processUnallocSpace; } @@ -671,6 +663,13 @@ public class IngestManager { public List enumerateAbstractFileModules() { return moduleLoader.getAbstractFileIngestModules(); } + + public List enumerateAllModules() { + List modules = new ArrayList<>(); + modules.addAll(enumerateDataSourceModules()); + modules.addAll(enumerateAbstractFileModules()); + return modules; + } //data source worker to remove itself when complete or interrupted void removeDataSourceIngestWorker(IngestDataSourceThread worker) { @@ -697,7 +696,6 @@ public class IngestManager { IngestManagerStats() { errors = new HashMap(); - } /** @@ -775,19 +773,8 @@ public class IngestManager { public String toHtmlString() { StringBuilder sb = new StringBuilder(); sb.append(""); - sb.append("Ingest time: ").append(getTotalTimeString()).append("
"); sb.append("Total errors: ").append(errorsTotal).append("
"); - /* - if (errorsTotal > 0) { - sb.append("Errors per module:"); - for (IngestModuleAbstract module : errors.keySet()) { - final int errorsModule = errors.get(module); - sb.append("\t").append(module.getName()).append(": ").append(errorsModule).append("
"); - } - } - * */ - sb.append(""); return sb.toString(); } @@ -1082,10 +1069,7 @@ public class IngestManager { } private void queueAll(List modules, final List inputs) { - - final IngestScheduler.DataSourceScheduler dataSourceScheduler = scheduler.getDataSourceScheduler(); - final IngestScheduler.FileScheduler fileScheduler = scheduler.getFileScheduler(); - + int processed = 0; for (Content input : inputs) { final String inputName = input.getName(); @@ -1112,16 +1096,16 @@ public class IngestManager { logger.log(Level.INFO, "Error loading module and adding input " + inputName + " with module " + module.getName()); } - break; case AbstractFile: //enqueue the same singleton AbstractFile module logger.log(Level.INFO, "Adding input " + inputName - + " number of AbstractFile to module " + module.getName()); + + " for AbstractFileModule " + module.getName()); fileMods.add((IngestModuleAbstractFile) module); break; + default: logger.log(Level.SEVERE, "Unexpected module type: " + module.getType().name()); } @@ -1138,6 +1122,7 @@ public class IngestManager { new PipelineContext(dataSourceTask, processUnalloc); logger.log(Level.INFO, "Queing data source ingest task: " + dataSourceTask); progress.progress("DataSource Ingest" + " " + inputName, processed); + final IngestScheduler.DataSourceScheduler dataSourceScheduler = scheduler.getDataSourceScheduler(); dataSourceScheduler.schedule(dataSourcePipelineContext); progress.progress("DataSource Ingest" + " " + inputName, ++processed); @@ -1148,6 +1133,7 @@ public class IngestManager { = new PipelineContext(fTask, processUnalloc); logger.log(Level.INFO, "Queing file ingest task: " + fTask); progress.progress("File Ingest" + " " + inputName, processed); + final IngestScheduler.FileScheduler fileScheduler = scheduler.getFileScheduler(); fileScheduler.schedule(filepipelineContext); progress.progress("File Ingest" + " " + inputName, ++processed); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleAbstract.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleAbstract.java index d30e57f785..7165640b75 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleAbstract.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleAbstract.java @@ -145,35 +145,38 @@ public abstract class IngestModuleAbstract { */ public void saveAdvancedConfiguration() {} + /** - * Returns a panel that displays the simple (run-time) configuration - * for the given configuration context (such as pipeline instance). - * This is presented to the user before ingest starts and only basic - * settings should be given here. Use the advanced (general) configuration - * panel for more in-depth interfaces. - * The module (or its configuration controller object) is responsible for preserving / saving its configuration state - * In addition, saveSimpleConfiguration() can be used as the trigger. - * + * Returns a panel that displays the simple (run-time) configuration for the + * given configuration context (such as pipeline instance). This is + * presented to the user before ingest starts and only basic settings should + * be given here. Use the advanced (general) configuration panel for more + * in-depth interfaces. The module (or its configuration controller object) + * is responsible for preserving / saving its configuration state In + * addition, saveSimpleConfiguration() can be used as the trigger. + * * @param context the configuration context to use in the panel - * @return JPanel containing basic configuration widgets or null if simple configuration is not available + * @return JPanel containing basic configuration widgets or null if simple + * configuration is not available */ public javax.swing.JPanel getSimpleConfiguration(String context) { return null; } - - /** - * Returns a panel that displays the advanced (run-time) configuration - * for the given configuration context (such as pipeline instance). - * Implements advanced module configuration exposed to the user before ingest starts. - * - * The module (or its configuration controller object) - * is responsible for preserving / saving its configuration state - * In addition, saveAdvancedConfiguration() can be used as the trigger. - * + + /** + * Returns a panel that displays the advanced (run-time) configuration for + * the given configuration context (such as pipeline instance). Implements + * advanced module configuration exposed to the user before ingest starts. + * + * The module (or its configuration controller object) is responsible for + * preserving / saving its configuration state In addition, + * saveAdvancedConfiguration() can be used as the trigger. + * * @param context the configuration context to use in the panel - * @return JPanel containing advanced configuration widgets or null if advanced configuration is not available + * @return JPanel containing advanced configuration widgets or null if + * advanced configuration is not available */ public javax.swing.JPanel getAdvancedConfiguration(String context) { return null; - }; -} + } + } \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleLoader.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleLoader.java index df5eceaadf..6597eadc9d 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleLoader.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestModuleLoader.java @@ -466,11 +466,13 @@ public final class IngestModuleLoader { @SuppressWarnings("unchecked") private void autodiscover() throws IngestModuleLoaderException { + // Use Lookup to find the other NBM modules. We'll later search them for ingest modules Collection moduleInfos = Lookup.getDefault().lookupAll(ModuleInfo.class); logger.log(Level.INFO, "Autodiscovery, found #platform modules: " + moduleInfos.size()); Set urls = getJarPaths(moduleInfos); - + ArrayList reflectionsSet = new ArrayList<>(); + for (final ModuleInfo moduleInfo : moduleInfos) { if (moduleInfo.isEnabled()) { String basePackageName = moduleInfo.getCodeNameBase(); @@ -489,104 +491,115 @@ public final class IngestModuleLoader { cb.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(basePackageName))); cb.setUrls(urls); cb.setScanners(new SubTypesScanner(), new ResourcesScanner()); - Reflections reflections = new Reflections(cb); - - Set fileModules = reflections.getSubTypesOf(IngestModuleAbstractFile.class); - Iterator it = fileModules.iterator(); - while (it.hasNext()) { - logger.log(Level.INFO, "Found file ingest module in: " + basePackageName + ": " + it.next().toString()); - } - - Set dataSourceModules = reflections.getSubTypesOf(IngestModuleDataSource.class); - it = dataSourceModules.iterator(); - while (it.hasNext()) { - logger.log(Level.INFO, "Found DataSource ingest module in: " + basePackageName + ": " + it.next().toString()); - } - - //find out which modules to add - //TODO check which modules to remove (which modules were uninstalled) - boolean modulesChanged = false; - - it = fileModules.iterator(); - while (it.hasNext()) { - boolean exists = false; - Class foundClass = (Class) it.next(); - - for (IngestModuleLoader.XmlPipelineRaw rawP : pipelinesXML) { - if (!rawP.type.equals(IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.FILE_ANALYSIS.toString())) { - continue; //skip - } - - for (IngestModuleLoader.XmlModuleRaw rawM : rawP.modules) { - //logger.log(Level.INFO, "CLASS NAME : " + foundClass.getName()); - if (foundClass.getName().equals(rawM.location)) { - exists = true; - break; - } - } - if (exists == true) { - break; - } - } - - if (exists == false) { - logger.log(Level.INFO, "Discovered a new file module to load: " + foundClass.getName()); - //ADD MODULE - addModuleToRawPipeline(foundClass, IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.FILE_ANALYSIS); - modulesChanged = true; - } - - } - - it = dataSourceModules.iterator(); - while (it.hasNext()) { - boolean exists = false; - Class foundClass = (Class) it.next(); - - for (IngestModuleLoader.XmlPipelineRaw rawP : pipelinesXML) { - if (!rawP.type.equals(IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.DATA_SOURCE_ANALYSIS.toString())) { - continue; //skip - } - - - for (IngestModuleLoader.XmlModuleRaw rawM : rawP.modules) { - //logger.log(Level.INFO, "CLASS NAME : " + foundClass.getName()); - if (foundClass.getName().equals(rawM.location)) { - exists = true; - break; - } - } - if (exists == true) { - break; - } - } - - if (exists == false) { - logger.log(Level.INFO, "Discovered a new DataSource module to load: " + foundClass.getName()); - //ADD MODULE - addModuleToRawPipeline(foundClass, IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.DATA_SOURCE_ANALYSIS); - modulesChanged = true; - } - - } - - if (modulesChanged) { - save(); - pcs.firePropertyChange(IngestModuleLoader.Event.ModulesReloaded.toString(), 0, 1); - } - - /* - //Enumeration resources = moduleClassLoader.getResources(basePackageName); - Enumeration resources = classLoader.getResources(basePackageName); - while (resources.hasMoreElements()) { - System.out.println(resources.nextElement()); - } */ - - } else { - //logger.log(Level.INFO, "Module disabled: " + moduleInfo.getDisplayName() ); + reflectionsSet.add(new Reflections(cb)); } } + + /* This area is used to load the example modules. They are not found via lookup since they + * are in this NBM module. + * Uncomment this section to rum the examples. + */ + /* + ConfigurationBuilder cb = new ConfigurationBuilder(); + cb.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("org.sleuthkit.autopsy.examples"))); + cb.setUrls(urls); + cb.setScanners(new SubTypesScanner(), new ResourcesScanner()); + reflectionsSet.add(new Reflections(cb)); + */ + + for (Reflections reflections : reflectionsSet) { + Set fileModules = reflections.getSubTypesOf(IngestModuleAbstractFile.class); + Iterator it = fileModules.iterator(); + while (it.hasNext()) { + logger.log(Level.INFO, "Found file ingest module in: " + reflections.getClass().getSimpleName() + ": " + it.next().toString()); + } + + Set dataSourceModules = reflections.getSubTypesOf(IngestModuleDataSource.class); + it = dataSourceModules.iterator(); + while (it.hasNext()) { + logger.log(Level.INFO, "Found DataSource ingest module in: " + reflections.getClass().getSimpleName() + ": " + it.next().toString()); + } + + //find out which modules to add + //TODO check which modules to remove (which modules were uninstalled) + boolean modulesChanged = false; + + it = fileModules.iterator(); + while (it.hasNext()) { + boolean exists = false; + Class foundClass = (Class) it.next(); + + for (IngestModuleLoader.XmlPipelineRaw rawP : pipelinesXML) { + if (!rawP.type.equals(IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.FILE_ANALYSIS.toString())) { + continue; //skip + } + + for (IngestModuleLoader.XmlModuleRaw rawM : rawP.modules) { + //logger.log(Level.INFO, "CLASS NAME : " + foundClass.getName()); + if (foundClass.getName().equals(rawM.location)) { + exists = true; + break; + } + } + if (exists == true) { + break; + } + } + + if (exists == false) { + logger.log(Level.INFO, "Discovered a new file module to load: " + foundClass.getName()); + //ADD MODULE + addModuleToRawPipeline(foundClass, IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.FILE_ANALYSIS); + modulesChanged = true; + } + + } + + it = dataSourceModules.iterator(); + while (it.hasNext()) { + boolean exists = false; + Class foundClass = (Class) it.next(); + + for (IngestModuleLoader.XmlPipelineRaw rawP : pipelinesXML) { + if (!rawP.type.equals(IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.DATA_SOURCE_ANALYSIS.toString())) { + continue; //skip + } + + + for (IngestModuleLoader.XmlModuleRaw rawM : rawP.modules) { + //logger.log(Level.INFO, "CLASS NAME : " + foundClass.getName()); + if (foundClass.getName().equals(rawM.location)) { + exists = true; + break; + } + } + if (exists == true) { + break; + } + } + + if (exists == false) { + logger.log(Level.INFO, "Discovered a new DataSource module to load: " + foundClass.getName()); + //ADD MODULE + addModuleToRawPipeline(foundClass, IngestModuleLoader.XmlPipelineRaw.PIPELINE_TYPE.DATA_SOURCE_ANALYSIS); + modulesChanged = true; + } + + } + + if (modulesChanged) { + save(); + pcs.firePropertyChange(IngestModuleLoader.Event.ModulesReloaded.toString(), 0, 1); + } + + /* + //Enumeration resources = moduleClassLoader.getResources(basePackageName); + Enumeration resources = classLoader.getResources(basePackageName); + while (resources.hasMoreElements()) { + System.out.println(resources.nextElement()); + } */ + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 60bb186c0a..e535d645ec 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -105,7 +105,160 @@ public class ReportHTML implements TableReportModule { } out = null; } + + /** + * Generate a file name for the given datatype, by replacing any + * undesirable chars, like /, or spaces + * @param dataType data type for which to generate a file name + */ + private String dataTypeToFileName(String dataType) { + + String fileName = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(dataType); + // replace all ' ' with '_' + fileName = fileName.replaceAll(" ", "_"); + + return fileName; + } + + /** + * Copies a suitable icon for the given data type in the output directory and + * returns the icon file name to use for the given data type. + */ + private String useDataTypeIcon(String dataType) + { + String iconFilePath; + String iconFileName; + InputStream in = null; + OutputStream output = null; + + logger.log(Level.INFO, "useDataTypeIcon: dataType = " + dataType); + + // find the artifact with matching display name + BlackboardArtifact.ARTIFACT_TYPE artifactType = null; + for (ARTIFACT_TYPE v : ARTIFACT_TYPE.values()) { + if (v.getDisplayName().equals(dataType)) { + artifactType = v; + } + } + + if (null != artifactType) + { + // set the icon file name + iconFileName = dataTypeToFileName(artifactType.getDisplayName()) + ".png"; + iconFilePath = path + File.separator + iconFileName; + + // determine the source image to use + switch (artifactType) { + case TSK_WEB_BOOKMARK: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/bookmarks.png"); + break; + case TSK_WEB_COOKIE: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/cookies.png"); + break; + case TSK_WEB_HISTORY: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/history.png"); + break; + case TSK_WEB_DOWNLOAD: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/downloads.png"); + break; + case TSK_RECENT_OBJECT: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/recent.png"); + break; + case TSK_INSTALLED_PROG: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/installed.png"); + break; + case TSK_KEYWORD_HIT: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/keywords.png"); + break; + case TSK_HASHSET_HIT: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/hash.png"); + break; + case TSK_DEVICE_ATTACHED: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/devices.png"); + break; + case TSK_WEB_SEARCH_QUERY: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/search.png"); + break; + case TSK_METADATA_EXIF: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/exif.png"); + break; + case TSK_TAG_FILE: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/userbookmarks.png"); + break; + case TSK_TAG_ARTIFACT: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/userbookmarks.png"); + break; + case TSK_SERVICE_ACCOUNT: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/account-icon-16.png"); + break; + case TSK_CONTACT: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/contact.png"); + break; + case TSK_MESSAGE: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/message.png"); + break; + case TSK_CALLLOG: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/calllog.png"); + break; + case TSK_CALENDAR_ENTRY: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/calendar.png"); + break; + case TSK_SPEED_DIAL_ENTRY: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/speeddialentry.png"); + break; + case TSK_BLUETOOTH_PAIRING: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/bluetooth.png"); + break; + case TSK_GPS_BOOKMARK: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/gpsfav.png"); + break; + case TSK_GPS_LAST_KNOWN_LOCATION: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/gps-lastlocation.png"); + break; + case TSK_GPS_SEARCH: + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/gps-search.png"); + break; + + default: + logger.log(Level.WARNING, "useDataTypeIcon: unhandled artifact type = " + dataType); + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/star.png"); + iconFileName = "star.png"; + iconFilePath = path + File.separator + iconFileName; + break; + } + } + else { // no defined artifact found for this dataType + logger.log(Level.WARNING, "useDataTypeIcon: no artifact found for data type = " + dataType); + in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/star.png"); + iconFileName = "star.png"; + iconFilePath = path + File.separator + iconFileName; + } + + try { + output = new FileOutputStream(iconFilePath); + FileUtil.copy(in, output); + in.close(); + output.close(); + } catch (IOException ex) { + logger.log(Level.SEVERE, "Failed to extract images for HTML report.", ex); + } finally { + if (output != null) { + try { + output.flush(); + output.close(); + } catch (IOException ex) { + } + } if (in != null) { + try { + in.close(); + } catch (IOException ex) { + } + } + } + + return iconFileName; + } /** * Start this report by setting the path, refreshing member variables, * and writing the skeleton for the HTML report. @@ -151,7 +304,7 @@ public class ReportHTML implements TableReportModule { */ @Override public void startDataType(String title) { - String fTitle = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(title); + String fTitle = dataTypeToFileName(title); // Make a new out for this page try { //escape out slashes tha that appear in title @@ -186,7 +339,7 @@ public class ReportHTML implements TableReportModule { * @param comment Comment on the data type, may be the empty string */ public void startDataType(String name, String comment) { - String title = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(name); + String title = dataTypeToFileName(name); try { out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + title + getExtension()), "UTF-8")); } catch (FileNotFoundException ex) { @@ -614,9 +767,10 @@ public class ReportHTML implements TableReportModule { nav.append("
  • Case Summary
  • \n"); for (String dataType : dataTypes.keySet()) { - String dataTypeEsc = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(dataType); - nav.append("
  • ") .append(dataType).append(" (").append(dataTypes.get(dataType)) .append(")
  • \n"); @@ -668,146 +822,7 @@ public class ReportHTML implements TableReportModule { in.close(); output.close(); - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/bookmarks.png"); - output = new FileOutputStream(new File(path + File.separator + "Bookmarks.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/cookies.png"); - output = new FileOutputStream(new File(path + File.separator + "Cookies.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/history.png"); - output = new FileOutputStream(new File(path + File.separator + "Web History.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/downloads.png"); - output = new FileOutputStream(new File(path + File.separator + "Downloads.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/search.png"); - output = new FileOutputStream(new File(path + File.separator + "Web Search Engine Queries.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/recent.png"); - output = new FileOutputStream(new File(path + File.separator + "Recent Documents.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/installed.png"); - output = new FileOutputStream(new File(path + File.separator + "Installed Programs.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/keywords.png"); - output = new FileOutputStream(new File(path + File.separator + "Keyword Hits.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/devices.png"); - output = new FileOutputStream(new File(path + File.separator + "Devices Attached.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/exif.png"); - output = new FileOutputStream(new File(path + File.separator + "EXIF Metadata.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/userbookmarks.png"); - output = new FileOutputStream(new File(path + File.separator + "File Tags.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/userbookmarks.png"); - output = new FileOutputStream(new File(path + File.separator + "Result Tags.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/hash.png"); - output = new FileOutputStream(new File(path + File.separator + "Hashset Hits.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/contact.png"); - output = new FileOutputStream(new File(path + File.separator + "Contacts.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/message.png"); - output = new FileOutputStream(new File(path + File.separator + "Messages.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/calllog.png"); - output = new FileOutputStream(new File(path + File.separator + "Call Logs.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/calendar.png"); - output = new FileOutputStream(new File(path + File.separator + "Calendar Entries.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/speeddialentry.png"); - output = new FileOutputStream(new File(path + File.separator + "Speed Dial Entries.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/bluetooth.png"); - output = new FileOutputStream(new File(path + File.separator + "BlueTooth.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/gpsfav.png"); - output = new FileOutputStream(new File(path + File.separator + "GPS Bookmarks.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/gps-lastlocation.png"); - output = new FileOutputStream(new File(path + File.separator + "GPS Last Location.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/gps-search.png"); - output = new FileOutputStream(new File(path + File.separator + "GPS Search.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/account-icon-16.png"); - output = new FileOutputStream(new File(path + File.separator + "Accounts.png")); - FileUtil.copy(in, output); - in.close(); - output.close(); - - - + } catch (IOException ex) { logger.log(Level.SEVERE, "Failed to extract images for HTML report.", ex); } finally { diff --git a/Core/src/org/sleuthkit/autopsy/report/images/star.png b/Core/src/org/sleuthkit/autopsy/report/images/star.png new file mode 100644 index 0000000000..10169c0617 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/report/images/star.png differ diff --git a/ExifParser/src/org/sleuthkit/autopsy/exifparser/ExifParserFileIngestModule.java b/ExifParser/src/org/sleuthkit/autopsy/exifparser/ExifParserFileIngestModule.java index 663c7b007f..a6fb867052 100644 --- a/ExifParser/src/org/sleuthkit/autopsy/exifparser/ExifParserFileIngestModule.java +++ b/ExifParser/src/org/sleuthkit/autopsy/exifparser/ExifParserFileIngestModule.java @@ -46,6 +46,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; /** @@ -92,6 +93,11 @@ public final class ExifParserFileIngestModule extends IngestModuleAbstractFile { return IngestModuleAbstractFile.ProcessResult.OK; } + // skip known + if (content.getKnown().equals(TskData.FileKnown.KNOWN)) { + return IngestModuleAbstractFile.ProcessResult.OK; + } + //skip unsupported if (! parsableFormat(content)) { return IngestModuleAbstractFile.ProcessResult.OK; diff --git a/KeywordSearch/release/solr/solr/conf/schema.xml b/KeywordSearch/release/solr/solr/conf/schema.xml index ecfb9e15d8..203820992f 100644 --- a/KeywordSearch/release/solr/solr/conf/schema.xml +++ b/KeywordSearch/release/solr/solr/conf/schema.xml @@ -504,37 +504,42 @@ when adding a document. --> + + - - + + + + - - - - - - - - - + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + @@ -545,10 +550,11 @@ - + + - Release - - - C:\Program Files (x86)\Caphyon\Advanced Installer 10.2\bin\x86\AdvancedInstaller.com - - - - - - - - - - - - - - - - - - - Product Code: ${guid1} - - Product Version: ${app.version} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + Release + + + C:\Program Files (x86)\Caphyon\Advanced Installer 10.3\bin\x86\AdvancedInstaller.com + + + + + + + + + + + + + + + + + + + + Product Code: ${guid1} + Product Version: ${app.version} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build.xml b/build.xml index 51bb4f7eef..f1f6586b11 100644 --- a/build.xml +++ b/build.xml @@ -1,271 +1,271 @@ - - - - - - Builds the module suite Autopsy3. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TSK_HOME: ${env.TSK_HOME} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Suite in ${basedir} with clusters ${cluster.path.final}, build cluster ${cluster}, and sorted modules ${modules.sorted} - - - - - - - - - - - - - - - - - - - - - - - - - - - ${app.name} branding - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + Builds the module suite Autopsy3. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TSK_HOME: ${env.TSK_HOME} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Suite in ${basedir} with clusters ${cluster.path.final}, build cluster ${cluster}, and sorted modules ${modules.sorted} + + + + + + + + + + + + + + + + + + + + + + + + + + + ${app.name} branding + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/doxygen/modDev.dox b/docs/doxygen/modDev.dox index 63113891ff..32d95deb72 100644 --- a/docs/doxygen/modDev.dox +++ b/docs/doxygen/modDev.dox @@ -4,8 +4,6 @@ any type of module. Information about specific types of modules should go into the page for that module type. --> - - This page describes the basic concepts and setup that are needed regardless of the module type that you are building. \section mod_dev_setup Basic Setup @@ -66,11 +64,7 @@ You now have a NetBeans module that is using Autopsy as its build platform. Tha There are several optional things in the Properties section. You can add a description and specify the version. You can do all of this later though and it does not need to be done before you start development. A link about the NetBeans versioning scheme can be found here http://wiki.netbeans.org/VersioningPolicy. -Autopsy follows this scheme and we will make a wiki page about it. - -TODO: @@@ Add link to our wiki with Autopsy's versioning scheme - - +Autopsy follows this scheme and a link to the details can be found at http://wiki.sleuthkit.org/index.php?title=Autopsy_3_Module_Versions. \subsection mod_dev_mod_other Other Links diff --git a/docs/doxygen/modIngest.dox b/docs/doxygen/modIngest.dox index 3d8b53c466..272d9218fc 100644 --- a/docs/doxygen/modIngest.dox +++ b/docs/doxygen/modIngest.dox @@ -48,6 +48,7 @@ blackboard and with inbox messages to the user. \section ingest_datasrc Data Source-level Modules To make a data source-level module, make a new Java class either manually or using the NetBeans wizards. Edit the class to extend "org.sleuthkit.autopsy.ingest.IngestModuleDataSource". NetBeans will likely complain that you have not implemented the necessary methods and you can use its "hints" to automatically generate stubs for them. Use the documentation for the org.sleuthkit.autopsy.ingest.IngestModuleDataSource class for details on what each needs to do. +You can also refer to org.sleuthkit.autopsy.examples.SampleDataSourceIngestModule as an example module. Example snippet of an ingest-level module process() method: @@ -87,6 +88,7 @@ public void process(Content dataSource, IngestDataSourceWorkerController control \section ingest_file File-level Modules To make a File-level module, make a new Java class either manually or using the NetBeans wizards. Edit the class to extend "org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile". NetBeans will likely complain that you have not implemented the necessary methods and you can use its "hints" to automatically generate stubs for them. Use the method documentation in the org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile class to fill in the details. +You can also refer to org.sleuthkit.autopsy.examples.SampleFileIngestModule as an example module. Unlike Data Source-level modules, file-level modules are singletons. Only a single instance is created for all files. The same file-level module instance will be used for files in different images and even different cases if new cases are opened. diff --git a/docs/doxygen/modResult.dox b/docs/doxygen/modResult.dox index b2cbae89f8..0daab56fa6 100644 --- a/docs/doxygen/modResult.dox +++ b/docs/doxygen/modResult.dox @@ -1,31 +1,51 @@ /*! \page mod_result_page Developing Result Viewer Modules -NOTE: This has been moved from a package-level description and needs cleanup and updating. +\section result_overview Overview +DataResultViewer modules exist in the upper-right area of the default Autopsy interface, as shown below. -

    Creating a DataResultViewer

    -

    DataResultTopComponent is the high-level window in the DataResult area. The DataResult area is in the upper right of Autopsy and shows a set of nodes (i.e. in table form or thumbnail, by default). You will want to create a new module in this area if you have a new way to display a set of files or nodes. For example, in a graph form or different layout beyond the simple table. +\image html viewer_image.jpg "Module Viewer Areas" -

      -
    1. Create a module from within NetBeans. It must be dependent on these modules: -
        -
      • Case -
      • CoreComponentInterfaces -
      • CoreComponents -
      • DataModel -
      • DialogsAPI (if pop-ups and such are going to be used) -
      • Explorer & Property Sheet API -
      • Lookup -
      • Nodes API -
      • Setting API -
      • UI Utilities API -
      • Utilities API -
      • Window System API -
      +They display a set of files that are passed into the viewer from the tree on the left, keyword searching, or other searches. The main idea is that the same set of files can be viewed in table form, thumbnail form, or any other form that you can think of. Once a file is selected from the DataResult area, it is passed to the DataContent area for display. -
    2. Make a class that extends org.sleuthkit.autopsy.corecomponents.AbstractDataResultViewer and is registered as a service provider for the org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer class by specifying "@ServiceProvider(service = DataResultViewer.class)" or by using layer.xml. This class will extend JPanel.
    3. +\section result_dataflow Data Flow +This section provides some basics on DataResult viewers. DataResult viewers are created as needed. The directory tree on the left creates one when it loads and uses it for the life of the application. The keyword search module creates on each time it performs a keyword search. Data is explicitly passed into it. -
    4. See the previous sections on default actions. (note that this refers to the CoreComponentINterfaces package-level description).
    5. +By default, when a node is selected, it is then passed to the default DataContent viewer (this is done in org.sleuthkit.autopsy.corecomponents.AbstractDataResultViewer). There can be many data content viewers, but only one default one exists. -
    +The org.sleuthkit.autopsy.corecomponents.DataResultViewerTopComponent class is the NetBeans TopComponent that encapsulates the various DataResult viewer modules. It creates tabs for each DataResult viewer module. + +\section result_nb NetBeans Module Configuration +The rest of the document assumes that you have already created your NetBeans module, as outlined in \ref mod_dev_module. + +DataResultViewer modules will have additional NetBeans dependencies. Right click on the module, choose "Properties" -> "Libraries" -> "Module Dependencies". Add "Lookup API" and "Nodes API". + +\section result_mod Module Development + +You will need a class that extends org.sleuthkit.autopsy.corecomponents.AbstractDataResultViewer. You can use NetBeans to make a class, manually extend it, and then let NetBeans complain about missing methods. It will provide default implementations for them if you click on the error messages in the UI. +Refer to the documentation in org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer on what each method should do. Note that AbstractDataResultViewer extends JPanel. + +Autopsy will find your module using the NetBeans Lookup infrastructure. To be found, you will need to register as a service provider for DataResultViewer.class by annotating your class as follows: + +\code +@ServiceProvider(service = DataResultViewer.class) +public class DataResultViewerTable extends AbstractDataResultViewer { +\endcode + +If you get errors about not knowing about ServiceProviders and such, ensure that you configured your NetBeans module to depend on the Nodes and Lookup APIs as outlined in the previous section. + +The current modules in this viewer area heavily use the NetBeans ExplorerManger and Node concepts. You do not need to use ExplorerManager concepts, but you will need to use Node concepts to identify the set of nodes to display and to extract the datamodel objects from each Node object. Refer to \ref content_hints_objects for hints on getting the datamodel objects from the Node. + +\section result_examples Example Modules +You can refer to the org.sleuthkit.autopsy.corecomponents.DataResultViewerTable and org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail modules to follow as examples. + +\section result_hint Hints + +Note that we have made the least number of these types of modules, so some work could be done to make the framework and infrastuture for them better. + +These modules are currently the most challenging to develop because they require the most NetBeans knowledge about Nodes and ExplorerManagers. Make sure you read some of the tutorials (or books) first: +- NetBeans Nodes API Tutorial (https://platform.netbeans.org/tutorials/nbm-nodesapi2.html) +- NetBeans Nodes, Explorer Manager, and Component Palette Tutorial (https://platform.netbeans.org/tutorials/nbm-nodesapi3.html) + +We have plans to change the design a bit in the future so that an ExplorerManager is created for each DataResultViewerTopComponent instance and each individual module does not need to make one. Instead, one will be given to it. */ diff --git a/docs/doxygen/platformConcepts.dox b/docs/doxygen/platformConcepts.dox index c8ae7cef1f..72701c5b5c 100644 --- a/docs/doxygen/platformConcepts.dox +++ b/docs/doxygen/platformConcepts.dox @@ -52,6 +52,7 @@ services are provided: - FileManager: the org.sleuthkit.autopsy.casemodule.services.FileManager service provides an API to access any file in the case. You can access FileManager by calling org.sleuthkit.autopsy.casemodule.services.Services.getFileManager(). Data Source-level Ingest modules and Report modules typically use this service because the other modules are passed in a reference to a specific file to do something with. - org.sleuthkit.autopsy.coreutils.Logger - for adding log messages to central logger - IngestModules also have a class that provides additional services. See \ref ingestmodule_services. +- MessageNotifyUtil.Notify.show() can be used to send messages to the user in the lower right-hand area. \subsection mod_dev_other_utilities Framework Utilities diff --git a/update_versions.py b/update_versions.py index ce9b857117..2883021c9f 100644 --- a/update_versions.py +++ b/update_versions.py @@ -820,18 +820,16 @@ def usage(): return \ """ USAGE: - Run this script to generate a jdiff XML summary for every module - in the current Autopsy source and in a previous source specified - by the given tag. Then, compare the XML files to see which modules - need updated version numbers. If the dry run tag is not given, the - module numbers will be automatically updated. + Compares the API of the current Autopsy source code with a previous + tagged version. By default, it will detect the previous tag from + the NEWS file and will not update the versions in the source code. OPTIONAL FLAGS: - -t --tag The tag name in git. Otherwise the NEWS file in source - will be used to determine the previous tag. + -t --tag Specify a previous tag to compare to. + Otherwise the NEWS file will be used. -d --dir The output directory for the jdiff JavaDocs. If no - directory is given, the default is /javadocs/{module}. + directory is given, the default is jdiff-javadocs/{module}. -s --source The directory containing Autopsy's source code. @@ -904,6 +902,7 @@ def main(): printt("Comparing jdiff outputs...") for module in similar_modules: module.set_ret(compare_xml(module, apiname_tag, apiname_cur)) + print("Refer to the jdiff-javadocs folder for more details") # ------------------------------------------------------------ # 1) Do versioning