mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 02:07:42 +00:00
Merge remote-tracking branch 'upstream/release-4.3.0'
This commit is contained in:
commit
5a5d42575b
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
||||
OpenIDE-Module: org.sleuthkit.autopsy.core/10
|
||||
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties
|
||||
OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml
|
||||
OpenIDE-Module-Implementation-Version: 17
|
||||
OpenIDE-Module-Implementation-Version: 18
|
||||
OpenIDE-Module-Requires: org.openide.windows.WindowManager
|
||||
AutoUpdate-Show-In-Client: true
|
||||
AutoUpdate-Essential-Module: true
|
||||
|
@ -23,5 +23,5 @@ nbm.homepage=http://www.sleuthkit.org/
|
||||
nbm.module.author=Brian Carrier
|
||||
nbm.needs.restart=true
|
||||
source.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1-src.zip!/Source/
|
||||
spec.version.base=10.6
|
||||
spec.version.base=10.7
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
Place Jython modules HERE in their respective folders. Eg. -
|
||||
Do not place user modules here. Place them in the folder at C:\Users\JDoe\AppData\Roaming\Autopsy\python_modules where JDoe is your Windows username. You can also access this folder by launching Autopsy and clicking Tools -> Python Plugins through the menu.
|
||||
|
||||
Place Jython modules HERE in their respective folders. Eg. -
|
||||
InternalPythonModules/
|
||||
- testModule1/
|
||||
- testModule1.py
|
||||
|
@ -87,6 +87,7 @@ public class AddBlackboardArtifactTagAction extends AddTagAction {
|
||||
"AddBlackboardArtifactTagAction.taggingErr"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
@ -141,6 +141,7 @@ public class AddContentTagAction extends AddTagAction {
|
||||
NbBundle.getMessage(this.getClass(), "AddContentTagAction.taggingErr"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
@ -75,6 +75,7 @@ public class DeleteBlackboardArtifactTagAction extends AbstractAction {
|
||||
"DeleteBlackboardArtifactTagAction.tagDelErr"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
@ -73,6 +73,7 @@ public class DeleteContentTagAction extends AbstractAction {
|
||||
NbBundle.getMessage(this.getClass(), "DeleteContentTagAction.tagDelErr"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
@ -39,6 +39,7 @@ import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datasourceprocessors.RawDSProcessor;
|
||||
|
||||
/**
|
||||
* visual component for the first panel of add image wizard. Allows the user to
|
||||
@ -92,7 +93,8 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
|
||||
datasourceProcessorsMap.remove(LocalDiskDSProcessor.getType());
|
||||
}
|
||||
coreDSPTypes.add(LocalFilesDSProcessor.getType());
|
||||
|
||||
coreDSPTypes.add(RawDSProcessor.getType());
|
||||
|
||||
for (String dspType : coreDSPTypes) {
|
||||
typeComboBox.addItem(dspType);
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ GeneralFilter.rawImageDesc.text=Raw Images (*.img, *.dd, *.001, *.aa, *.raw, *.b
|
||||
GeneralFilter.encaseImageDesc.text=Encase Images (*.e01)
|
||||
GeneralFilter.virtualMachineImageDesc.text=Virtual Machines (*.vmdk, *.vhd)
|
||||
GeneralFilter.executableDesc.text=Executables (*.exe)
|
||||
ImageDSProcessor.dsType.text=Image or VM File
|
||||
ImageDSProcessor.dsType.text=Disk Image or VM File
|
||||
ImageDSProcessor.allDesc.text=All Supported Types
|
||||
ImageFilePanel.moduleErr=Module Error
|
||||
ImageFilePanel.moduleErr.msg=A module caused an error listening to ImageFilePanel updates. See log to determine which module. Some data could be incomplete.
|
||||
|
@ -37,16 +37,19 @@ import org.openide.DialogDisplayer;
|
||||
import org.openide.NotifyDescriptor;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.HelpCtx;
|
||||
import org.openide.util.actions.CallableSystemAction;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
|
||||
/**
|
||||
* An action that opens an existing case.
|
||||
*/
|
||||
@ServiceProvider(service = CaseOpenAction.class)
|
||||
public final class CaseOpenAction implements ActionListener {
|
||||
public final class CaseOpenAction extends CallableSystemAction implements ActionListener {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CaseOpenAction.class.getName());
|
||||
private static final String PROP_BASECASE = "LBL_BaseCase_PATH"; //NON-NLS
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final JFileChooser fileChooser = new JFileChooser();
|
||||
private final FileFilter caseMetadataFileFilter;
|
||||
|
||||
@ -140,4 +143,18 @@ public final class CaseOpenAction implements ActionListener {
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performAction() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NbBundle.getMessage(CaseOpenAction.class, "CTL_OpenAction");
|
||||
}
|
||||
|
||||
@Override
|
||||
public HelpCtx getHelpCtx() {
|
||||
return HelpCtx.DEFAULT_HELP;
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import javax.swing.JPanel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
@ -26,9 +28,12 @@ import java.util.UUID;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.openide.util.lookup.ServiceProviders;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.coreutils.DataSourceUtils;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.AutoIngestDataSourceProcessor;
|
||||
|
||||
/**
|
||||
* A image file data source processor that implements the DataSourceProcessor
|
||||
@ -36,16 +41,19 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
* wizard. It also provides a run method overload to allow it to be used
|
||||
* independently of the wizard.
|
||||
*/
|
||||
@ServiceProvider(service = DataSourceProcessor.class)
|
||||
public class ImageDSProcessor implements DataSourceProcessor {
|
||||
@ServiceProviders(value={
|
||||
@ServiceProvider(service=DataSourceProcessor.class),
|
||||
@ServiceProvider(service=AutoIngestDataSourceProcessor.class)}
|
||||
)
|
||||
public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor {
|
||||
|
||||
private final static String DATA_SOURCE_TYPE = NbBundle.getMessage(ImageDSProcessor.class, "ImageDSProcessor.dsType.text");
|
||||
private static final List<String> allExt = new ArrayList<>();
|
||||
private static final GeneralFilter rawFilter = new GeneralFilter(GeneralFilter.RAW_IMAGE_EXTS, GeneralFilter.RAW_IMAGE_DESC);
|
||||
private static final GeneralFilter encaseFilter = new GeneralFilter(GeneralFilter.ENCASE_IMAGE_EXTS, GeneralFilter.ENCASE_IMAGE_DESC);
|
||||
private static final GeneralFilter virtualMachineFilter = new GeneralFilter(GeneralFilter.VIRTUAL_MACHINE_EXTS, GeneralFilter.VIRTUAL_MACHINE_DESC);
|
||||
private static final String allDesc = NbBundle.getMessage(ImageDSProcessor.class, "ImageDSProcessor.allDesc.text");
|
||||
private static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc);
|
||||
private static final String ALL_DESC = NbBundle.getMessage(ImageDSProcessor.class, "ImageDSProcessor.allDesc.text");
|
||||
private static final GeneralFilter allFilter = new GeneralFilter(allExt, ALL_DESC);
|
||||
private static final List<FileFilter> filtersList = new ArrayList<>();
|
||||
private final ImageFilePanel configPanel;
|
||||
private AddImageTask addImageTask;
|
||||
@ -209,6 +217,48 @@ public class ImageDSProcessor implements DataSourceProcessor {
|
||||
setDataSourceOptionsCalled = false;
|
||||
}
|
||||
|
||||
private static boolean isAcceptedByFiler(File file, List<FileFilter> filters) {
|
||||
for (FileFilter filter : filters) {
|
||||
if (filter.accept(file)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException {
|
||||
|
||||
// check file extension for supported types
|
||||
if (!isAcceptedByFiler(dataSourcePath.toFile(), filtersList)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
// verify that the image has a file system that TSK can process
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
if (!DataSourceUtils.imageHasFileSystem(dataSourcePath)) {
|
||||
// image does not have a file system that TSK can process
|
||||
return 0;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new AutoIngestDataSourceProcessorException("Exception inside canProcess() method", ex);
|
||||
}
|
||||
|
||||
// able to process the data source
|
||||
return 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException {
|
||||
this.deviceId = deviceId;
|
||||
this.imagePath = dataSourcePath.toString();
|
||||
this.timeZone = Calendar.getInstance().getTimeZone().getID();
|
||||
this.ignoreFatOrphanFiles = false;
|
||||
setDataSourceOptionsCalled = true;
|
||||
run(deviceId, dataSourcePath.toString(), timeZone, ignoreFatOrphanFiles, progressMonitor, callBack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configuration of the data source processor without using the
|
||||
* selection and configuration panel.
|
||||
@ -230,5 +280,5 @@ public class ImageDSProcessor implements DataSourceProcessor {
|
||||
this.ignoreFatOrphanFiles = ignoreFatOrphanFiles;
|
||||
setDataSourceOptionsCalled = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012 Basis Technology Corp.
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -45,10 +45,10 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
|
||||
|
||||
private final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH"; //NON-NLS
|
||||
private static final Logger logger = Logger.getLogger(ImageFilePanel.class.getName());
|
||||
private JFileChooser fc = new JFileChooser();
|
||||
private final JFileChooser fc = new JFileChooser();
|
||||
|
||||
// Externally supplied name is used to store settings
|
||||
private String contextName;
|
||||
private final String contextName;
|
||||
|
||||
/**
|
||||
* Creates new form ImageFilePanel
|
||||
@ -78,17 +78,17 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
|
||||
|
||||
this.contextName = context;
|
||||
|
||||
createTimeZoneList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns an instance of a ImageFilePanel.
|
||||
* @return instance of the ImageFilePanel
|
||||
*/
|
||||
public static synchronized ImageFilePanel createInstance(String context, List<FileFilter> fileChooserFilters) {
|
||||
|
||||
ImageFilePanel instance = new ImageFilePanel(context, fileChooserFilters);
|
||||
|
||||
instance.postInit();
|
||||
instance.createTimeZoneList();
|
||||
|
||||
return instance;
|
||||
}
|
||||
@ -234,6 +234,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
|
||||
|
||||
/**
|
||||
* Set the path of the image file.
|
||||
* @param s path of the image file
|
||||
*/
|
||||
public void setContentPath(String s) {
|
||||
pathTextField.setText(s);
|
||||
@ -242,7 +243,6 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
|
||||
public String getTimeZone() {
|
||||
String tz = timeZoneComboBox.getSelectedItem().toString();
|
||||
return tz.substring(tz.indexOf(")") + 2).trim();
|
||||
|
||||
}
|
||||
|
||||
public boolean getNoFatOrphans() {
|
||||
|
@ -18,14 +18,19 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Calendar;
|
||||
import java.util.UUID;
|
||||
import javax.swing.JPanel;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.openide.util.lookup.ServiceProviders;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.coreutils.DriveUtils;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.AutoIngestDataSourceProcessor;
|
||||
|
||||
/**
|
||||
* A local drive data source processor that implements the DataSourceProcessor
|
||||
@ -33,8 +38,11 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
* wizard. It also provides a run method overload to allow it to be used
|
||||
* independently of the wizard.
|
||||
*/
|
||||
@ServiceProvider(service = DataSourceProcessor.class)
|
||||
public class LocalDiskDSProcessor implements DataSourceProcessor {
|
||||
@ServiceProviders(value={
|
||||
@ServiceProvider(service=DataSourceProcessor.class),
|
||||
@ServiceProvider(service=AutoIngestDataSourceProcessor.class)}
|
||||
)
|
||||
public class LocalDiskDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor {
|
||||
|
||||
private static final String DATA_SOURCE_TYPE = NbBundle.getMessage(LocalDiskDSProcessor.class, "LocalDiskDSProcessor.dsType.text");
|
||||
private final LocalDiskPanel configPanel;
|
||||
@ -188,6 +196,37 @@ public class LocalDiskDSProcessor implements DataSourceProcessor {
|
||||
setDataSourceOptionsCalled = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException {
|
||||
|
||||
// verify that the data source is not a file or a directory
|
||||
File file = dataSourcePath.toFile();
|
||||
// ELTODO this needs to be tested more. should I keep isDirectory or just test for isFile?
|
||||
if (file.isFile() || file.isDirectory()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check whether data source is an existing disk or partition
|
||||
// ELTODO this needs to be tested more. do these methods actually work correctly?
|
||||
// or should I use PlatformUtil.getPhysicalDrives() and PlatformUtil.getPartitions() instead?
|
||||
String path = dataSourcePath.toString();
|
||||
if ( (DriveUtils.isPhysicalDrive(path) || DriveUtils.isPartition(path)) && DriveUtils.driveExists(path) ) {
|
||||
return 90;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException {
|
||||
this.deviceId = deviceId;
|
||||
this.drivePath = dataSourcePath.toString();
|
||||
this.timeZone = Calendar.getInstance().getTimeZone().getID();
|
||||
this.ignoreFatOrphanFiles = false;
|
||||
setDataSourceOptionsCalled = true;
|
||||
run(deviceId, drivePath, timeZone, ignoreFatOrphanFiles, progressMonitor, callBack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configuration of the data source processor without using the
|
||||
* configuration panel.
|
||||
@ -209,5 +248,5 @@ public class LocalDiskDSProcessor implements DataSourceProcessor {
|
||||
this.ignoreFatOrphanFiles = ignoreFatOrphanFiles;
|
||||
setDataSourceOptionsCalled = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012 Basis Technology Corp.
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -53,6 +53,7 @@ final class LocalDiskPanel extends JPanel {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LocalDiskPanel.class.getName());
|
||||
private static LocalDiskPanel instance;
|
||||
private static final long serialVersionUID = 1L;
|
||||
private List<LocalDisk> disks;
|
||||
private LocalDiskModel model;
|
||||
private boolean enableNext = false;
|
||||
@ -66,7 +67,6 @@ final class LocalDiskPanel extends JPanel {
|
||||
customInit();
|
||||
|
||||
createTimeZoneList();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -185,7 +185,6 @@ final class LocalDiskPanel extends JPanel {
|
||||
*
|
||||
* @return String selected disk path
|
||||
*/
|
||||
//@Override
|
||||
public String getContentPaths() {
|
||||
if (disks.size() > 0) {
|
||||
LocalDisk selected = (LocalDisk) diskComboBox.getSelectedItem();
|
||||
@ -198,7 +197,6 @@ final class LocalDiskPanel extends JPanel {
|
||||
/**
|
||||
* Set the selected disk.
|
||||
*/
|
||||
// @Override
|
||||
public void setContentPath(String s) {
|
||||
for (int i = 0; i < disks.size(); i++) {
|
||||
if (disks.get(i).getPath().equals(s)) {
|
||||
@ -223,25 +221,20 @@ final class LocalDiskPanel extends JPanel {
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
//@Override
|
||||
public boolean validatePanel() {
|
||||
return enableNext;
|
||||
}
|
||||
|
||||
//@Override
|
||||
public void reset() {
|
||||
//nothing to reset
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the focus to the diskComboBox and refreshes the list of disks.
|
||||
*/
|
||||
// @Override
|
||||
public void select() {
|
||||
diskComboBox.requestFocusInWindow();
|
||||
model.loadDisks();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -293,8 +286,8 @@ final class LocalDiskPanel extends JPanel {
|
||||
List<LocalDisk> partitions = new ArrayList<>();
|
||||
|
||||
//private String SELECT = "Select a local disk:";
|
||||
private String LOADING = NbBundle.getMessage(this.getClass(), "LocalDiskPanel.localDiskModel.loading.msg");
|
||||
private String NO_DRIVES = NbBundle.getMessage(this.getClass(), "LocalDiskPanel.localDiskModel.nodrives.msg");
|
||||
private final String LOADING = NbBundle.getMessage(this.getClass(), "LocalDiskPanel.localDiskModel.loading.msg");
|
||||
private final String NO_DRIVES = NbBundle.getMessage(this.getClass(), "LocalDiskPanel.localDiskModel.nodrives.msg");
|
||||
|
||||
LocalDiskThread worker = null;
|
||||
|
||||
@ -415,7 +408,7 @@ final class LocalDiskPanel extends JPanel {
|
||||
|
||||
class LocalDiskThread extends SwingWorker<Object, Void> {
|
||||
|
||||
private Logger logger = Logger.getLogger(LocalDiskThread.class.getName());
|
||||
private final Logger logger = Logger.getLogger(LocalDiskThread.class.getName());
|
||||
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2016 Basis Technology Corp.
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,15 +18,18 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.swing.JPanel;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.openide.util.lookup.ServiceProviders;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.AutoIngestDataSourceProcessor;
|
||||
|
||||
/**
|
||||
* A local/logical files and/or directories data source processor that
|
||||
@ -34,8 +37,11 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
* integration with the add data source wizard. It also provides a run method
|
||||
* overload to allow it to be used independently of the wizard.
|
||||
*/
|
||||
@ServiceProvider(service = DataSourceProcessor.class)
|
||||
public class LocalFilesDSProcessor implements DataSourceProcessor {
|
||||
@ServiceProviders(value={
|
||||
@ServiceProvider(service=DataSourceProcessor.class),
|
||||
@ServiceProvider(service=AutoIngestDataSourceProcessor.class)}
|
||||
)
|
||||
public class LocalFilesDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor {
|
||||
|
||||
private static final String DATA_SOURCE_TYPE = NbBundle.getMessage(LocalFilesDSProcessor.class, "LocalFilesDSProcessor.dsType");
|
||||
private final LocalFilesPanel configPanel;
|
||||
@ -122,7 +128,7 @@ public class LocalFilesDSProcessor implements DataSourceProcessor {
|
||||
@Override
|
||||
public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
||||
if (!setDataSourceOptionsCalled) {
|
||||
localFilePaths = Arrays.asList(configPanel.getContentPaths().split(LocalFilesPanel.FILES_SEP));
|
||||
localFilePaths = configPanel.getContentPaths();
|
||||
}
|
||||
run(UUID.randomUUID().toString(), configPanel.getFileSetName(), localFilePaths, progressMonitor, callback);
|
||||
}
|
||||
@ -179,6 +185,20 @@ public class LocalFilesDSProcessor implements DataSourceProcessor {
|
||||
setDataSourceOptionsCalled = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException {
|
||||
// Local files DSP can process any file by simply adding it as a logical file.
|
||||
// It should return lowest possible non-zero confidence level and be treated
|
||||
// as the "option of last resort" for auto ingest purposes
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException {
|
||||
this.localFilePaths = Arrays.asList(new String[]{dataSourcePath.toString()});
|
||||
run(deviceId, deviceId, this.localFilePaths, progressMonitor, callBack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configuration of the data source processor without using the
|
||||
* configuration panel. The data source processor will assign a UUID to the
|
||||
@ -192,9 +212,12 @@ public class LocalFilesDSProcessor implements DataSourceProcessor {
|
||||
*/
|
||||
@Deprecated
|
||||
public void setDataSourceOptions(String paths) {
|
||||
//LocalFilesPanel.FILES_SEP is currently ","
|
||||
this.localFilePaths = Arrays.asList(paths.split(LocalFilesPanel.FILES_SEP));
|
||||
// The LocalFilesPanel used to separate file paths with a comma and pass
|
||||
// them as a string, but because file names are allowed to contain
|
||||
// commas, this approach was buggy and replaced. We now pass a list of
|
||||
// String paths.
|
||||
this.localFilePaths = Arrays.asList(paths.split(","));
|
||||
setDataSourceOptionsCalled = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 Basis Technology Corp.
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,9 +18,8 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import java.awt.Dialog;
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
@ -32,9 +31,6 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JOptionPane;
|
||||
import org.openide.DialogDescriptor;
|
||||
import org.openide.DialogDisplayer;
|
||||
import org.openide.NotifyDescriptor;
|
||||
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.PathValidator;
|
||||
@ -42,12 +38,12 @@ import org.sleuthkit.autopsy.coreutils.PathValidator;
|
||||
/**
|
||||
* Add input wizard subpanel for adding local files / dirs to the case
|
||||
*/
|
||||
class LocalFilesPanel extends JPanel {
|
||||
final class LocalFilesPanel extends JPanel {
|
||||
|
||||
private Set<File> currentFiles = new TreeSet<File>(); //keep currents in a set to disallow duplicates per add
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final Set<File> currentFiles = new TreeSet<>(); //keep currents in a set to disallow duplicates per add
|
||||
private boolean enableNext = false;
|
||||
private static LocalFilesPanel instance;
|
||||
public static final String FILES_SEP = ",";
|
||||
private static final Logger logger = Logger.getLogger(LocalFilesPanel.class.getName());
|
||||
private String displayName = "";
|
||||
|
||||
@ -73,38 +69,24 @@ class LocalFilesPanel extends JPanel {
|
||||
this.displayNameLabel.setText(NbBundle.getMessage(this.getClass(), "LocalFilesPanel.displayNameLabel.text"));
|
||||
}
|
||||
|
||||
//@Override
|
||||
public String getContentPaths() {
|
||||
//TODO consider interface change to return list of paths instead
|
||||
|
||||
public List<String> getContentPaths() {
|
||||
List<String> pathsList = new ArrayList<>();
|
||||
if (currentFiles == null) {
|
||||
return "";
|
||||
return pathsList;
|
||||
}
|
||||
StringBuilder b = new StringBuilder();
|
||||
for (File f : currentFiles) {
|
||||
b.append(f.getAbsolutePath());
|
||||
b.append(FILES_SEP);
|
||||
pathsList.add(f.getAbsolutePath());
|
||||
}
|
||||
return b.toString();
|
||||
return pathsList;
|
||||
}
|
||||
|
||||
//@Override
|
||||
public void setContentPath(String s) {
|
||||
//for the local file panel we don't need to restore the last paths used
|
||||
//when the wizard restarts
|
||||
}
|
||||
|
||||
//@Override
|
||||
public String getContentType() {
|
||||
return NbBundle.getMessage(this.getClass(), "LocalFilesPanel.contentType.text");
|
||||
}
|
||||
|
||||
//@Override
|
||||
public boolean validatePanel() {
|
||||
|
||||
// display warning if there is one (but don't disable "next" button)
|
||||
warnIfPathIsInvalid(getContentPaths());
|
||||
|
||||
return enableNext;
|
||||
}
|
||||
|
||||
@ -112,13 +94,11 @@ class LocalFilesPanel extends JPanel {
|
||||
* Validates path to selected data source and displays warning if it is
|
||||
* invalid.
|
||||
*
|
||||
* @param path Absolute path to the selected data source
|
||||
* @param paths Absolute paths to the selected data source
|
||||
*/
|
||||
private void warnIfPathIsInvalid(String path) {
|
||||
private void warnIfPathIsInvalid(List<String> pathsList) {
|
||||
errorLabel.setVisible(false);
|
||||
|
||||
// Path variable for "Local files" module is a coma separated string containg multiple paths
|
||||
List<String> pathsList = Arrays.asList(path.split(","));
|
||||
CaseType currentCaseType = Case.getCurrentCase().getCaseType();
|
||||
|
||||
for (String currentPath : pathsList) {
|
||||
@ -130,12 +110,10 @@ class LocalFilesPanel extends JPanel {
|
||||
}
|
||||
}
|
||||
|
||||
//@Override
|
||||
public void select() {
|
||||
reset();
|
||||
}
|
||||
|
||||
//@Override
|
||||
public void reset() {
|
||||
currentFiles.clear();
|
||||
selectedPaths.setText("");
|
||||
@ -281,14 +259,9 @@ class LocalFilesPanel extends JPanel {
|
||||
}
|
||||
this.selectedPaths.setText(allPaths.toString());
|
||||
this.selectedPaths.setToolTipText(allPaths.toString());
|
||||
|
||||
}
|
||||
|
||||
if (!currentFiles.isEmpty()) {
|
||||
enableNext = true;
|
||||
} else {
|
||||
enableNext = false;
|
||||
}
|
||||
enableNext = !currentFiles.isEmpty();
|
||||
|
||||
try {
|
||||
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
|
||||
|
@ -59,12 +59,10 @@ public class StartupWindowProvider implements StartupWindowInterface {
|
||||
= Lookup.getDefault().lookupAll(StartupWindowInterface.class);
|
||||
|
||||
int windowsCount = startupWindows.size();
|
||||
if (windowsCount > 2) {
|
||||
logger.log(Level.WARNING, "More than 2 (" + windowsCount + ") start up windows discovered, will use the first custom one"); //NON-NLS
|
||||
} else if (windowsCount == 1) {
|
||||
if (windowsCount == 1) {
|
||||
startupWindowToUse = startupWindows.iterator().next();
|
||||
logger.log(Level.INFO, "Will use the default startup window: " + startupWindowToUse.toString()); //NON-NLS
|
||||
} else {
|
||||
} else if (windowsCount == 2) {
|
||||
//pick the non default one
|
||||
Iterator<? extends StartupWindowInterface> it = startupWindows.iterator();
|
||||
while (it.hasNext()) {
|
||||
@ -73,17 +71,25 @@ public class StartupWindowProvider implements StartupWindowInterface {
|
||||
startupWindowToUse = window;
|
||||
logger.log(Level.INFO, "Will use the custom startup window: " + startupWindowToUse.toString()); //NON-NLS
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (startupWindowToUse == null) {
|
||||
logger.log(Level.SEVERE, "Unexpected error, no custom startup window found, using the default"); //NON-NLS
|
||||
startupWindowToUse = new org.sleuthkit.autopsy.casemodule.StartupWindow();
|
||||
} else {
|
||||
// select first non-Autopsy start up window
|
||||
Iterator<? extends StartupWindowInterface> it = startupWindows.iterator();
|
||||
while (it.hasNext()) {
|
||||
StartupWindowInterface window = it.next();
|
||||
if (!window.getClass().getCanonicalName().startsWith("org.sleuthkit.autopsy")) {
|
||||
startupWindowToUse = window;
|
||||
logger.log(Level.INFO, "Will use the custom startup window: " + startupWindowToUse.toString()); //NON-NLS
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (startupWindowToUse == null) {
|
||||
logger.log(Level.SEVERE, "Unexpected error, no startup window chosen, using the default"); //NON-NLS
|
||||
startupWindowToUse = new org.sleuthkit.autopsy.casemodule.StartupWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ abstract class TagAddedEvent<T extends Tag> extends AutopsyEvent implements Seri
|
||||
private transient T tag;
|
||||
|
||||
/**
|
||||
* The id of the tag that was added. This will bu used to re-load the
|
||||
* The id of the tag that was added. This will be used to re-load the
|
||||
* transient tag from the database.
|
||||
*/
|
||||
private final Long tagID;
|
||||
|
@ -248,7 +248,7 @@ public class TagsManager implements Closeable {
|
||||
try {
|
||||
Case.getCurrentCase().notifyContentTagAdded(tag);
|
||||
} catch (IllegalStateException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Added a tag to a closed case", ex);
|
||||
throw new TskCoreException("Added a tag to a closed case", ex);
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
@ -266,7 +266,7 @@ public class TagsManager implements Closeable {
|
||||
try {
|
||||
Case.getCurrentCase().notifyContentTagDeleted(tag);
|
||||
} catch (IllegalStateException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Deleted a tag from a closed case", ex);
|
||||
throw new TskCoreException("Deleted a tag from a closed case", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -378,7 +378,7 @@ public class TagsManager implements Closeable {
|
||||
try {
|
||||
Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(tag);
|
||||
} catch (IllegalStateException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Added a tag to a closed case", ex);
|
||||
throw new TskCoreException("Added a tag to a closed case", ex);
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
@ -396,7 +396,7 @@ public class TagsManager implements Closeable {
|
||||
try {
|
||||
Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag);
|
||||
} catch (IllegalStateException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Deleted a tag from a closed case", ex);
|
||||
throw new TskCoreException("Deleted a tag from a closed case", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,12 +64,54 @@ public class Installer extends ModuleInstall {
|
||||
//Note: if shipping with a different CRT version, this will only print a warning
|
||||
//and try to use linker mechanism to find the correct versions of libs.
|
||||
//We should update this if we officially switch to a new version of CRT/compiler
|
||||
System.loadLibrary("msvcr100"); //NON-NLS
|
||||
System.loadLibrary("msvcp100"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-console-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-datetime-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-debug-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-errorhandling-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-file-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-file-l1-2-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-file-l2-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-handle-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-heap-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-interlocked-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-libraryloader-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-localization-l1-2-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-memory-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-namedpipe-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-processenvironment-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-processthreads-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-processthreads-l1-1-1"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-profile-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-rtlsupport-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-string-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-synch-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-synch-l1-2-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-sysinfo-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-timezone-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-core-util-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-conio-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-convert-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-environment-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-filesystem-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-heap-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-locale-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-math-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-multibyte-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-private-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-process-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-runtime-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-stdio-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-string-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-time-l1-1-0"); //NON-NLS
|
||||
System.loadLibrary("api-ms-win-crt-utility-l1-1-0"); //NON-NLS
|
||||
|
||||
logger.log(Level.INFO, "MSVCR100 and MSVCP100 libraries loaded"); //NON-NLS
|
||||
System.loadLibrary("ucrtbase"); //NON-NLS
|
||||
System.loadLibrary("vcruntime140"); //NON-NLS
|
||||
System.loadLibrary("msvcp140"); //NON-NLS
|
||||
|
||||
logger.log(Level.INFO, "Visual C Runtime libraries loaded"); //NON-NLS
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
logger.log(Level.SEVERE, "Error loading MSVCR100 and MSVCP100 libraries, ", e); //NON-NLS
|
||||
logger.log(Level.SEVERE, "Error loading Visual C Runtime libraries, ", e); //NON-NLS
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -38,7 +38,7 @@ public class RuntimeProperties {
|
||||
*
|
||||
* @param coreComponentsActive True or false.
|
||||
*/
|
||||
public static void setCoreComponentsActive(boolean coreComponentsActive) {
|
||||
public synchronized static void setCoreComponentsActive(boolean coreComponentsActive) {
|
||||
if (!coreComponentsActiveSet) {
|
||||
RuntimeProperties.coreComponentsActive = coreComponentsActive;
|
||||
coreComponentsActiveSet = true;
|
||||
@ -56,7 +56,7 @@ public class RuntimeProperties {
|
||||
*
|
||||
* @return True or false.
|
||||
*/
|
||||
public static boolean coreComponentsAreActive() {
|
||||
public synchronized static boolean coreComponentsAreActive() {
|
||||
return coreComponentsActive;
|
||||
}
|
||||
|
||||
|
@ -40,11 +40,13 @@ import org.sleuthkit.datamodel.TskData.DbType;
|
||||
*/
|
||||
public final class UserPreferences {
|
||||
|
||||
private static final boolean isWindowsOS = PlatformUtil.isWindowsOS();
|
||||
private static final boolean IS_WINDOWS_OS = PlatformUtil.isWindowsOS();
|
||||
private static final Preferences preferences = NbPreferences.forModule(UserPreferences.class);
|
||||
public static final String KEEP_PREFERRED_VIEWER = "KeepPreferredViewer"; // NON-NLS
|
||||
public static final String HIDE_KNOWN_FILES_IN_DATA_SOURCES_TREE = "HideKnownFilesInDataSourcesTree"; //NON-NLS
|
||||
public static final String HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE = "HideKnownFilesInDataSourcesTree"; //NON-NLS
|
||||
public static final String HIDE_KNOWN_FILES_IN_VIEWS_TREE = "HideKnownFilesInViewsTree"; //NON-NLS
|
||||
public static final String HIDE_SLACK_FILES_IN_DATA_SRCS_TREE = "HideSlackFilesInDataSourcesTree"; //NON-NLS
|
||||
public static final String HIDE_SLACK_FILES_IN_VIEWS_TREE = "HideSlackFilesInViewsTree"; //NON-NLS
|
||||
public static final String DISPLAY_TIMES_IN_LOCAL_TIME = "DisplayTimesInLocalTime"; //NON-NLS
|
||||
public static final String NUMBER_OF_FILE_INGEST_THREADS = "NumberOfFileIngestThreads"; //NON-NLS
|
||||
public static final String IS_MULTI_USER_MODE_ENABLED = "IsMultiUserModeEnabled"; //NON-NLS
|
||||
@ -109,11 +111,11 @@ public final class UserPreferences {
|
||||
}
|
||||
|
||||
public static boolean hideKnownFilesInDataSourcesTree() {
|
||||
return preferences.getBoolean(HIDE_KNOWN_FILES_IN_DATA_SOURCES_TREE, false);
|
||||
return preferences.getBoolean(HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE, false);
|
||||
}
|
||||
|
||||
public static void setHideKnownFilesInDataSourcesTree(boolean value) {
|
||||
preferences.putBoolean(HIDE_KNOWN_FILES_IN_DATA_SOURCES_TREE, value);
|
||||
preferences.putBoolean(HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE, value);
|
||||
}
|
||||
|
||||
public static boolean hideKnownFilesInViewsTree() {
|
||||
@ -124,6 +126,22 @@ public final class UserPreferences {
|
||||
preferences.putBoolean(HIDE_KNOWN_FILES_IN_VIEWS_TREE, value);
|
||||
}
|
||||
|
||||
public static boolean hideSlackFilesInDataSourcesTree() {
|
||||
return preferences.getBoolean(HIDE_SLACK_FILES_IN_DATA_SRCS_TREE, true);
|
||||
}
|
||||
|
||||
public static void setHideSlackFilesInDataSourcesTree(boolean value) {
|
||||
preferences.putBoolean(HIDE_SLACK_FILES_IN_DATA_SRCS_TREE, value);
|
||||
}
|
||||
|
||||
public static boolean hideSlackFilesInViewsTree() {
|
||||
return preferences.getBoolean(HIDE_SLACK_FILES_IN_VIEWS_TREE, true);
|
||||
}
|
||||
|
||||
public static void setHideSlackFilesInViewsTree(boolean value) {
|
||||
preferences.putBoolean(HIDE_SLACK_FILES_IN_VIEWS_TREE, value);
|
||||
}
|
||||
|
||||
public static boolean displayTimesInLocalTime() {
|
||||
return preferences.getBoolean(DISPLAY_TIMES_IN_LOCAL_TIME, true);
|
||||
}
|
||||
@ -180,7 +198,7 @@ public final class UserPreferences {
|
||||
}
|
||||
|
||||
public static boolean getIsMultiUserModeEnabled() {
|
||||
if (!isWindowsOS) {
|
||||
if (!IS_WINDOWS_OS) {
|
||||
return false;
|
||||
}
|
||||
return preferences.getBoolean(IS_MULTI_USER_MODE_ENABLED, false);
|
||||
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.corecomponentinterfaces;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Interface implemented by DataSourceProcessors in order to be supported by
|
||||
* automated ingest capability.
|
||||
*
|
||||
* @author elivis
|
||||
*/
|
||||
public interface AutoIngestDataSourceProcessor extends DataSourceProcessor {
|
||||
|
||||
/**
|
||||
* Indicates whether the DataSourceProcessor is capable of processing the
|
||||
* data source. Returns a confidence value. Method can throw an exception
|
||||
* for a system level problem. The exception should not be thrown for an issue
|
||||
* related to bad input data.
|
||||
*
|
||||
* @param dataSourcePath Path to the data source.
|
||||
*
|
||||
* @return Confidence value. Values between 0 and 100 are recommended. Zero
|
||||
* or less means the data source is not supported by the
|
||||
* DataSourceProcessor. Value of 100 indicates high certainty in
|
||||
* being able to process the data source.
|
||||
*
|
||||
* @throws
|
||||
* org.sleuthkit.autopsy.corecomponentinterfaces.AutomatedIngestDataSourceProcessor.AutomatedIngestDataSourceProcessorException
|
||||
*/
|
||||
int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException;
|
||||
|
||||
/**
|
||||
* Adds a data source to the case database using a background task in a
|
||||
* separate thread by calling DataSourceProcessor.run() method. Returns as
|
||||
* soon as the background task is started. The background task uses a
|
||||
* callback object to signal task completion and return results. Method can
|
||||
* throw an exception for a system level problem. The exception should not
|
||||
* be thrown for an issue related to bad input data.
|
||||
*
|
||||
* @param deviceId An ASCII-printable identifier for the device
|
||||
* associated with the data source that is intended
|
||||
* to be unique across multiple cases (e.g., a UUID).
|
||||
* @param dataSourcePath Path to the data source.
|
||||
* @param progressMonitor Progress monitor that will be used by the
|
||||
* background task to report progress.
|
||||
* @param callBack Callback that will be used by the background task
|
||||
* to return results.
|
||||
*
|
||||
* @throws
|
||||
* org.sleuthkit.autopsy.corecomponentinterfaces.AutomatedIngestDataSourceProcessor.AutomatedIngestDataSourceProcessorException
|
||||
*/
|
||||
void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException;
|
||||
|
||||
/**
|
||||
* A custom exception for the use of AutomatedIngestDataSourceProcessor.
|
||||
*/
|
||||
public class AutoIngestDataSourceProcessorException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public AutoIngestDataSourceProcessorException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public AutoIngestDataSourceProcessorException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
}
|
@ -22,12 +22,12 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jScrollPane1" alignment="1" pref="657" max="32767" attributes="0"/>
|
||||
<Component id="jScrollPane1" alignment="1" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jScrollPane1" alignment="0" pref="402" max="32767" attributes="0"/>
|
||||
<Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
@ -49,47 +49,69 @@
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="keepCurrentViewerRB" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="useBestViewerRB" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="dataSourcesHideKnownCB" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="viewsHideKnownCB" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
||||
<Component id="numberOfFileIngestThreadsComboBox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="restartRequiredLabel" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jLabelTimeDisplay" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jLabelNumThreads" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jLabelSetProcessTimeOut" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="useLocalTimeRB" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="useGMTTimeRB" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="jCheckBoxEnableProcTimeout" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jFormattedTextFieldProcTimeOutHrs" min="-2" pref="27" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jLabelProcessTimeOutUnits" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="213" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jLabelHideKnownFiles" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jLabelTimeDisplay" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jLabelSelectFile" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="useLocalTimeRB" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="useGMTTimeRB" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="keepCurrentViewerRB" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="useBestViewerRB" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="dataSourcesHideKnownCB" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="viewsHideKnownCB" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Component id="jLabelSelectFile" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jLabelNumThreads" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="395" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jLabelHideSlackFiles" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
||||
<Component id="jCheckBoxEnableProcTimeout" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jFormattedTextFieldProcTimeOutHrs" min="-2" pref="27" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jLabelProcessTimeOutUnits" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="dataSourcesHideSlackCB" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="viewsHideSlackCB" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Component id="jLabelSetProcessTimeOut" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="213" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@ -108,7 +130,13 @@
|
||||
<Component id="dataSourcesHideKnownCB" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="viewsHideKnownCB" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jLabelHideSlackFiles" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="dataSourcesHideSlackCB" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="viewsHideSlackCB" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jLabelTimeDisplay" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="useLocalTimeRB" min="-2" max="-2" attributes="0"/>
|
||||
@ -131,7 +159,7 @@
|
||||
<Component id="jLabelProcessTimeOutUnits" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<EmptySpace pref="49" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@ -303,6 +331,33 @@
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JFormattedTextField(NumberFormat.getIntegerInstance());"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="dataSourcesHideSlackCB">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.dataSourcesHideSlackCB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="dataSourcesHideSlackCBActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="viewsHideSlackCB">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.viewsHideSlackCB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="viewsHideSlackCBActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabelHideSlackFiles">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelHideSlackFiles.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
|
@ -101,6 +101,8 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
useBestViewerRB.setSelected(!keepPreferredViewer);
|
||||
dataSourcesHideKnownCB.setSelected(UserPreferences.hideKnownFilesInDataSourcesTree());
|
||||
viewsHideKnownCB.setSelected(UserPreferences.hideKnownFilesInViewsTree());
|
||||
dataSourcesHideSlackCB.setSelected(UserPreferences.hideSlackFilesInDataSourcesTree());
|
||||
viewsHideSlackCB.setSelected(UserPreferences.hideSlackFilesInViewsTree());
|
||||
boolean useLocalTime = UserPreferences.displayTimesInLocalTime();
|
||||
useLocalTimeRB.setSelected(useLocalTime);
|
||||
useGMTTimeRB.setSelected(!useLocalTime);
|
||||
@ -124,6 +126,8 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
UserPreferences.setKeepPreferredContentViewer(keepCurrentViewerRB.isSelected());
|
||||
UserPreferences.setHideKnownFilesInDataSourcesTree(dataSourcesHideKnownCB.isSelected());
|
||||
UserPreferences.setHideKnownFilesInViewsTree(viewsHideKnownCB.isSelected());
|
||||
UserPreferences.setHideSlackFilesInDataSourcesTree(dataSourcesHideSlackCB.isSelected());
|
||||
UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCB.isSelected());
|
||||
UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRB.isSelected());
|
||||
UserPreferences.setNumberOfFileIngestThreads((Integer) numberOfFileIngestThreadsComboBox.getSelectedItem());
|
||||
|
||||
@ -167,6 +171,9 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
jCheckBoxEnableProcTimeout = new javax.swing.JCheckBox();
|
||||
jLabelProcessTimeOutUnits = new javax.swing.JLabel();
|
||||
jFormattedTextFieldProcTimeOutHrs = new JFormattedTextField(NumberFormat.getIntegerInstance());
|
||||
dataSourcesHideSlackCB = new javax.swing.JCheckBox();
|
||||
viewsHideSlackCB = new javax.swing.JCheckBox();
|
||||
jLabelHideSlackFiles = new javax.swing.JLabel();
|
||||
|
||||
jScrollPane1.setBorder(null);
|
||||
|
||||
@ -253,6 +260,22 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideSlackCB.text")); // NOI18N
|
||||
dataSourcesHideSlackCB.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
dataSourcesHideSlackCBActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(viewsHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideSlackCB.text")); // NOI18N
|
||||
viewsHideSlackCB.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
viewsHideSlackCBActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jLabelHideSlackFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideSlackFiles.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
|
||||
jPanel1.setLayout(jPanel1Layout);
|
||||
jPanel1Layout.setHorizontalGroup(
|
||||
@ -260,38 +283,52 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(keepCurrentViewerRB)
|
||||
.addComponent(useBestViewerRB)
|
||||
.addComponent(dataSourcesHideKnownCB)
|
||||
.addComponent(viewsHideKnownCB)
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addComponent(numberOfFileIngestThreadsComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(restartRequiredLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
|
||||
.addComponent(restartRequiredLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jLabelTimeDisplay)
|
||||
.addComponent(jLabelNumThreads)
|
||||
.addComponent(jLabelSetProcessTimeOut)
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(useLocalTimeRB)
|
||||
.addComponent(useGMTTimeRB)
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addComponent(jCheckBoxEnableProcTimeout)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jFormattedTextFieldProcTimeOutHrs, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jLabelProcessTimeOutUnits)))))
|
||||
.addGap(213, 213, 213)))
|
||||
.addContainerGap())
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jLabelHideKnownFiles)
|
||||
.addComponent(jLabelTimeDisplay)
|
||||
.addComponent(jLabelSelectFile)
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(useLocalTimeRB)
|
||||
.addComponent(useGMTTimeRB)))
|
||||
.addComponent(jLabelSelectFile)
|
||||
.addComponent(jLabelNumThreads)
|
||||
.addComponent(keepCurrentViewerRB)
|
||||
.addComponent(useBestViewerRB)
|
||||
.addComponent(dataSourcesHideKnownCB)
|
||||
.addComponent(viewsHideKnownCB))))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jLabelHideSlackFiles)
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addComponent(jCheckBoxEnableProcTimeout)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jFormattedTextFieldProcTimeOutHrs, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jLabelProcessTimeOutUnits))
|
||||
.addComponent(jLabelSetProcessTimeOut))
|
||||
.addGap(213, 213, 213)))
|
||||
.addContainerGap())
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(dataSourcesHideSlackCB)
|
||||
.addComponent(viewsHideSlackCB))))
|
||||
.addGap(0, 0, Short.MAX_VALUE))))
|
||||
);
|
||||
jPanel1Layout.setVerticalGroup(
|
||||
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
@ -308,7 +345,13 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
.addComponent(dataSourcesHideKnownCB)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(viewsHideKnownCB)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jLabelHideSlackFiles)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(dataSourcesHideSlackCB)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(viewsHideSlackCB)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jLabelTimeDisplay)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(useLocalTimeRB)
|
||||
@ -328,7 +371,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(jFormattedTextFieldProcTimeOutHrs, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(jLabelProcessTimeOutUnits)))
|
||||
.addContainerGap())
|
||||
.addContainerGap(49, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
jScrollPane1.setViewportView(jPanel1);
|
||||
@ -337,11 +380,11 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 657, Short.MAX_VALUE)
|
||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 402, Short.MAX_VALUE)
|
||||
.addComponent(jScrollPane1)
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
@ -382,13 +425,23 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||
}//GEN-LAST:event_jFormattedTextFieldProcTimeOutHrsActionPerformed
|
||||
|
||||
private void dataSourcesHideSlackCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSourcesHideSlackCBActionPerformed
|
||||
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||
}//GEN-LAST:event_dataSourcesHideSlackCBActionPerformed
|
||||
|
||||
private void viewsHideSlackCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewsHideSlackCBActionPerformed
|
||||
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||
}//GEN-LAST:event_viewsHideSlackCBActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.ButtonGroup buttonGroup1;
|
||||
private javax.swing.ButtonGroup buttonGroup3;
|
||||
private javax.swing.JCheckBox dataSourcesHideKnownCB;
|
||||
private javax.swing.JCheckBox dataSourcesHideSlackCB;
|
||||
private javax.swing.JCheckBox jCheckBoxEnableProcTimeout;
|
||||
private javax.swing.JFormattedTextField jFormattedTextFieldProcTimeOutHrs;
|
||||
private javax.swing.JLabel jLabelHideKnownFiles;
|
||||
private javax.swing.JLabel jLabelHideSlackFiles;
|
||||
private javax.swing.JLabel jLabelNumThreads;
|
||||
private javax.swing.JLabel jLabelProcessTimeOutUnits;
|
||||
private javax.swing.JLabel jLabelSelectFile;
|
||||
@ -403,5 +456,6 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
private javax.swing.JRadioButton useGMTTimeRB;
|
||||
private javax.swing.JRadioButton useLocalTimeRB;
|
||||
private javax.swing.JCheckBox viewsHideKnownCB;
|
||||
private javax.swing.JCheckBox viewsHideSlackCB;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ Format_OperatingSystem_Value={0} version {1} running on {2}
|
||||
LBL_Copyright=<div style\="font-size\: 12pt; font-family\: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif; ">Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools. <br><ul><li>General Information: <a style\="color\: \#1E2A60;" href\="http\://www.sleuthkit.org">http\://www.sleuthkit.org</a>.</li><li>Training: <a style\="color\: \#1E2A60;" href\="http://www.basistech.com/autopsy-training">http://www.basistech.com/autopsy-training</a></li><li>Commercial Support: <a style\="color\: \#1E2A60;" href\="http://www.basistech.com/digital-forensics/autopsy/support/">http://www.basistech.com/digital-forensics/autopsy/support/</a></li></ul>Copyright © 2003-2016. </div>
|
||||
URL_ON_IMG=http://www.sleuthkit.org/
|
||||
|
||||
URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.1/
|
||||
URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.3/
|
||||
|
||||
FILE_FOR_LOCAL_HELP=file:///
|
||||
INDEX_FOR_LOCAL_HELP=/docs/index.html
|
||||
@ -197,3 +197,6 @@ MultiUserSettingsPanel.lbTestSolrWarning.text=
|
||||
MultiUserSettingsPanel.lbTestDbWarning.text=
|
||||
MultiUserSettingsPanel.KeywordSearchNull=Cannot find keyword search service
|
||||
MultiUserSettingsPanel.InvalidPortNumber=Invalid port number
|
||||
AutopsyOptionsPanel.jLabelHideSlackFiles.text=Hide slack files in the:
|
||||
AutopsyOptionsPanel.dataSourcesHideSlackCB.text=Data Sources area (the directory hierarchy)
|
||||
AutopsyOptionsPanel.viewsHideSlackCB.text=Views area
|
||||
|
@ -1,15 +1,15 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2014 Basis Technology Corp.
|
||||
*
|
||||
* Copyright 2013-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -18,22 +18,32 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.corecomponents;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.dnd.DnDConstants;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.swing.Action;
|
||||
import java.util.TreeMap;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.TableColumnModelEvent;
|
||||
import javax.swing.event.TableColumnModelListener;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import org.netbeans.swing.outline.DefaultOutlineCellRenderer;
|
||||
import org.netbeans.swing.outline.DefaultOutlineModel;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.explorer.view.OutlineView;
|
||||
@ -46,28 +56,43 @@ import org.openide.nodes.NodeEvent;
|
||||
import org.openide.nodes.NodeListener;
|
||||
import org.openide.nodes.NodeMemberEvent;
|
||||
import org.openide.nodes.NodeReorderEvent;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbPreferences;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
|
||||
|
||||
/**
|
||||
* DataResult sortable table viewer
|
||||
*/
|
||||
// @@@ Restore implementation of DataResultViewerTable as a DataResultViewer
|
||||
// service provider when DataResultViewers can be made compatible with node
|
||||
// @@@ Restore implementation of DataResultViewerTable as a DataResultViewer
|
||||
// service provider when DataResultViewers can be made compatible with node
|
||||
// multiple selection actions.
|
||||
//@ServiceProvider(service = DataResultViewer.class)
|
||||
public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
|
||||
private String firstColumnLabel = NbBundle.getMessage(DataResultViewerTable.class, "DataResultViewerTable.firstColLbl");
|
||||
private Set<Property<?>> propertiesAcc = new LinkedHashSet<>();
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String firstColumnLabel = NbBundle.getMessage(DataResultViewerTable.class, "DataResultViewerTable.firstColLbl");
|
||||
/* The properties map maps
|
||||
* key: stored value of column index -> value: property at that index
|
||||
* We move around stored values instead of directly using the column indices
|
||||
* in order to not override settings for a column that may not appear in the
|
||||
* current table view due to its collection of its children's properties.
|
||||
*/
|
||||
private final Map<Integer, Property<?>> propertiesMap = new TreeMap<>();
|
||||
private final DummyNodeListener dummyNodeListener = new DummyNodeListener();
|
||||
private static final String DUMMY_NODE_DISPLAY_NAME = NbBundle.getMessage(DataResultViewerTable.class, "DataResultViewerTable.dummyNodeDisplayName");
|
||||
private static final Color TAGGED_COLOR = new Color(200, 210, 220);
|
||||
private Node currentRoot;
|
||||
// When a column in the table is moved, these two variables keep track of where
|
||||
// the column started and where it ended up.
|
||||
private int startColumnIndex = -1;
|
||||
private int endColumnIndex = -1;
|
||||
|
||||
/**
|
||||
* Creates a DataResultViewerTable object that is compatible with node
|
||||
* multiple selection actions.
|
||||
*
|
||||
* @param explorerManager allow for explorer manager sharing
|
||||
*/
|
||||
public DataResultViewerTable(ExplorerManager explorerManager) {
|
||||
super(explorerManager);
|
||||
@ -94,34 +119,97 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
ov.getOutline().setRootVisible(false);
|
||||
ov.getOutline().setDragEnabled(false);
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* The following lines of code were added for this feature.
|
||||
*/
|
||||
// ov.getOutline().getColumnModel().addColumnModelListener(new TableColumnModelListener() {
|
||||
// @Override
|
||||
// public void columnAdded(TableColumnModelEvent e) {}
|
||||
// @Override
|
||||
// public void columnRemoved(TableColumnModelEvent e) {}
|
||||
// @Override
|
||||
// public void columnMarginChanged(ChangeEvent e) {}
|
||||
// @Override
|
||||
// public void columnSelectionChanged(ListSelectionEvent e) {}
|
||||
//
|
||||
// @Override
|
||||
// public void columnMoved(TableColumnModelEvent e) {
|
||||
// // change the order of the column in the array/hashset
|
||||
// List<Node.Property<?>> props = new ArrayList<>(propertiesAcc);
|
||||
// Node.Property<?> prop = props.remove(e.getFromIndex());
|
||||
// props.add(e.getToIndex(), prop);
|
||||
//
|
||||
// propertiesAcc.clear();
|
||||
// for (int j = 0; j < props.size(); ++j) {
|
||||
// propertiesAcc.add(props.get(j));
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// add a listener so that when columns are moved, the new order is stored
|
||||
ov.getOutline().getColumnModel().addColumnModelListener(new TableColumnModelListener() {
|
||||
@Override
|
||||
public void columnAdded(TableColumnModelEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void columnRemoved(TableColumnModelEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void columnMarginChanged(ChangeEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void columnSelectionChanged(ListSelectionEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void columnMoved(TableColumnModelEvent e) {
|
||||
int fromIndex = e.getFromIndex();
|
||||
int toIndex = e.getToIndex();
|
||||
if (fromIndex == toIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Because a column may be dragged to several different positions before
|
||||
* the mouse is released (thus causing multiple TableColumnModelEvents to
|
||||
* be fired), we want to keep track of the starting column index in this
|
||||
* potential series of movements. Therefore we only keep track of the
|
||||
* original fromIndex in startColumnIndex, but we always update
|
||||
* endColumnIndex to know the final position of the moved column.
|
||||
* See the MouseListener mouseReleased method.
|
||||
*/
|
||||
if (startColumnIndex == -1) {
|
||||
startColumnIndex = fromIndex;
|
||||
}
|
||||
endColumnIndex = toIndex;
|
||||
|
||||
// This array contains the keys of propertiesMap in order
|
||||
int[] indicesList = new int[propertiesMap.size()];
|
||||
int pos = 0;
|
||||
for (int key : propertiesMap.keySet()) {
|
||||
indicesList[pos++] = key;
|
||||
}
|
||||
int leftIndex = Math.min(fromIndex, toIndex);
|
||||
int rightIndex = Math.max(fromIndex, toIndex);
|
||||
// Now we can copy the range of keys that have been affected by
|
||||
// the column movement
|
||||
int[] range = Arrays.copyOfRange(indicesList, leftIndex, rightIndex + 1);
|
||||
int rangeSize = range.length;
|
||||
|
||||
// column moved right, shift all properties left, put in moved
|
||||
// property at the rightmost index
|
||||
if (fromIndex < toIndex) {
|
||||
Property<?> movedProp = propertiesMap.get(range[0]);
|
||||
for (int i = 0; i < rangeSize - 1; i++) {
|
||||
propertiesMap.put(range[i], propertiesMap.get(range[i + 1]));
|
||||
}
|
||||
propertiesMap.put(range[rangeSize - 1], movedProp);
|
||||
}
|
||||
// column moved left, shift all properties right, put in moved
|
||||
// property at the leftmost index
|
||||
else {
|
||||
Property<?> movedProp = propertiesMap.get(range[rangeSize - 1]);
|
||||
for (int i = rangeSize - 1; i > 0; i--) {
|
||||
propertiesMap.put(range[i], propertiesMap.get(range[i - 1]));
|
||||
}
|
||||
propertiesMap.put(range[0], movedProp);
|
||||
}
|
||||
|
||||
storeState();
|
||||
}
|
||||
});
|
||||
|
||||
// add a listener to move columns back if user tries to move the first column out of place
|
||||
ov.getOutline().getTableHeader().addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
/* If the startColumnIndex is not -1 (which is the reset value), that
|
||||
* means columns have been moved around. We then check to see if either
|
||||
* the starting or end position is 0 (the first column), and then swap
|
||||
* them back if that is the case because we don't want to allow movement
|
||||
* of the first column. We then reset startColumnIndex to -1, the reset
|
||||
* value.
|
||||
* We check if startColumnIndex is at reset or not because it is
|
||||
* possible for the mouse to be released and a MouseEvent to be fired
|
||||
* without having moved any columns.
|
||||
*/
|
||||
if (startColumnIndex != -1 && (startColumnIndex == 0 || endColumnIndex == 0)) {
|
||||
ov.getOutline().moveColumn(endColumnIndex, startColumnIndex);
|
||||
}
|
||||
startColumnIndex = -1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -175,68 +263,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
private javax.swing.JScrollPane tableScrollPanel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
/**
|
||||
* Gets regular Bean property set properties from first child of Node.
|
||||
*
|
||||
* @param parent Node with at least one child to get properties from
|
||||
*
|
||||
* @return Properties,
|
||||
*/
|
||||
private Node.Property<?>[] getChildPropertyHeaders(Node parent) {
|
||||
Node firstChild = parent.getChildren().getNodeAt(0);
|
||||
|
||||
if (firstChild == null) {
|
||||
throw new IllegalArgumentException(
|
||||
NbBundle.getMessage(this.getClass(), "DataResultViewerTable.illegalArgExc.noChildFromParent"));
|
||||
} else {
|
||||
for (PropertySet ps : firstChild.getPropertySets()) {
|
||||
if (ps.getName().equals(Sheet.PROPERTIES)) {
|
||||
return ps.getProperties();
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
NbBundle.getMessage(this.getClass(), "DataResultViewerTable.illegalArgExc.childWithoutPropertySet"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets regular Bean property set properties from all first children and,
|
||||
* recursively, subchildren of Node. Note: won't work out the box for lazy
|
||||
* load - you need to set all children props for the parent by hand
|
||||
*
|
||||
* @param parent Node with at least one child to get properties from
|
||||
*
|
||||
* @return Properties,
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private Node.Property[] getAllChildPropertyHeaders(Node parent) {
|
||||
Node firstChild = parent.getChildren().getNodeAt(0);
|
||||
|
||||
Property[] properties = null;
|
||||
|
||||
if (firstChild == null) {
|
||||
throw new IllegalArgumentException(
|
||||
NbBundle.getMessage(this.getClass(), "DataResultViewerTable.illegalArgExc.noChildFromParent"));
|
||||
} else {
|
||||
Set<Property> allProperties = new LinkedHashSet<>();
|
||||
while (firstChild != null) {
|
||||
for (PropertySet ps : firstChild.getPropertySets()) {
|
||||
final Property[] props = ps.getProperties();
|
||||
final int propsNum = props.length;
|
||||
for (int i = 0; i < propsNum; ++i) {
|
||||
allProperties.add(props[i]);
|
||||
}
|
||||
}
|
||||
firstChild = firstChild.getChildren().getNodeAt(0);
|
||||
}
|
||||
|
||||
properties = allProperties.toArray(new Property<?>[0]);
|
||||
}
|
||||
return properties;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets regular Bean property set properties from all children and,
|
||||
* recursively, subchildren of Node. Note: won't work out the box for lazy
|
||||
@ -246,7 +272,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
* @param rows max number of rows to retrieve properties for (can be used
|
||||
* for memory optimization)
|
||||
*/
|
||||
private void getAllChildPropertyHeadersRec(Node parent, int rows) {
|
||||
private void getAllChildPropertyHeadersRec(Node parent, int rows, Set<Property<?>> propertiesAcc) {
|
||||
Children children = parent.getChildren();
|
||||
int childCount = 0;
|
||||
for (Node child : children.getNodes()) {
|
||||
@ -260,7 +286,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
propertiesAcc.add(props[j]);
|
||||
}
|
||||
}
|
||||
getAllChildPropertyHeadersRec(child, rows);
|
||||
getAllChildPropertyHeadersRec(child, rows, propertiesAcc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,11 +303,17 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
*/
|
||||
@Override
|
||||
public void setNode(Node selectedNode) {
|
||||
final OutlineView ov = ((OutlineView) this.tableScrollPanel);
|
||||
/* The quick filter must be reset because when determining column width,
|
||||
* ETable.getRowCount is called, and the documentation states that quick
|
||||
* filters must be unset for the method to work
|
||||
* "If the quick-filter is applied the number of rows do not match the number of rows in the model."
|
||||
*/
|
||||
ov.getOutline().unsetQuickFilter();
|
||||
// change the cursor to "waiting cursor" for this operation
|
||||
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
try {
|
||||
boolean hasChildren = false;
|
||||
|
||||
if (selectedNode != null) {
|
||||
// @@@ This just did a DB round trip to get the count and the results were not saved...
|
||||
hasChildren = selectedNode.getChildren().getNodesCount() > 0;
|
||||
@ -299,7 +331,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
root.addNodeListener(dummyNodeListener);
|
||||
setupTable(root);
|
||||
} else {
|
||||
final OutlineView ov = ((OutlineView) this.tableScrollPanel);
|
||||
Node emptyNode = new AbstractNode(Children.LEAF);
|
||||
em.setRootContext(emptyNode); // make empty node
|
||||
ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||
@ -319,37 +350,24 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
private void setupTable(final Node root) {
|
||||
|
||||
em.setRootContext(root);
|
||||
|
||||
final OutlineView ov = ((OutlineView) this.tableScrollPanel);
|
||||
|
||||
if (ov == null) {
|
||||
return;
|
||||
}
|
||||
currentRoot = root;
|
||||
List<Node.Property<?>> props = loadState();
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* The next three lines of code replaced the three lines of code that
|
||||
* follow
|
||||
*/
|
||||
// storeState();
|
||||
// set the new root as current
|
||||
// currentRoot = root;
|
||||
// List<Node.Property<?>> props = loadState();
|
||||
propertiesAcc.clear();
|
||||
DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100);
|
||||
List<Node.Property<?>> props = new ArrayList<>(propertiesAcc);
|
||||
|
||||
/*
|
||||
/**
|
||||
* OutlineView makes the first column be the result of
|
||||
* node.getDisplayName with the icon. This duplicates our first column,
|
||||
* which is the file name, etc. So, pop that property off the list, but
|
||||
* use its display name as the header for the column so that the header
|
||||
* can change depending on the type of data being displayed.
|
||||
*
|
||||
* NOTE: This assumes that the first property is always the one tha
|
||||
* duplicates getDisplayName(). This seems like a big assumption and
|
||||
* could be made more robust.
|
||||
* NOTE: This assumes that the first property is always the one that
|
||||
* duplicates getDisplayName(). The current implementation does not
|
||||
* allow the first property column to be moved.
|
||||
*/
|
||||
if (props.size() > 0) {
|
||||
Node.Property<?> prop = props.remove(0);
|
||||
@ -372,142 +390,176 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
ov.setPropertyColumns(propStrings);
|
||||
|
||||
// show the horizontal scroll panel and show all the content & header
|
||||
int totalColumns = props.size();
|
||||
|
||||
//int scrollWidth = ttv.getWidth();
|
||||
int margin = 4;
|
||||
int startColumn = 1;
|
||||
|
||||
// If there is only one column (which was removed from props above)
|
||||
// Just let the table resize itself.
|
||||
ov.getOutline().setAutoResizeMode((props.size() > 0) ? JTable.AUTO_RESIZE_OFF : JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||
|
||||
// get first 100 rows values for the table
|
||||
Object[][] content;
|
||||
content = getRowValues(root, 100);
|
||||
|
||||
if (content != null) {
|
||||
// get the fontmetrics
|
||||
if (root.getChildren().getNodesCount() != 0) {
|
||||
final Graphics graphics = ov.getGraphics();
|
||||
if (graphics != null) {
|
||||
final FontMetrics metrics = graphics.getFontMetrics();
|
||||
|
||||
// for the "Name" column
|
||||
int nodeColWidth = Math.min(getMaxColumnWidth(0, metrics, margin, 40, firstColumnLabel, content), 250); // Note: 40 is the width of the icon + node lines. Change this value if those values change!
|
||||
ov.getOutline().getColumnModel().getColumn(0).setPreferredWidth(nodeColWidth);
|
||||
int margin = 4;
|
||||
int padding = 8;
|
||||
|
||||
// get the max for each other column
|
||||
for (int colIndex = startColumn; colIndex <= totalColumns; colIndex++) {
|
||||
int colWidth = Math.min(getMaxColumnWidth(colIndex, metrics, margin, 8, props, content), 350);
|
||||
ov.getOutline().getColumnModel().getColumn(colIndex).setPreferredWidth(colWidth);
|
||||
for (int column = 0; column < ov.getOutline().getModel().getColumnCount(); column++) {
|
||||
int firstColumnPadding = (column == 0) ? 32 : 0;
|
||||
int columnWidthLimit = (column == 0) ? 350 : 300;
|
||||
int valuesWidth = 0;
|
||||
|
||||
// find the maximum width needed to fit the values for the first 100 rows, at most
|
||||
for (int row = 0; row < Math.min(100, ov.getOutline().getRowCount()); row++) {
|
||||
TableCellRenderer renderer = ov.getOutline().getCellRenderer(row, column);
|
||||
Component comp = ov.getOutline().prepareRenderer(renderer, row, column);
|
||||
valuesWidth = Math.max(comp.getPreferredSize().width, valuesWidth);
|
||||
}
|
||||
|
||||
int headerWidth = metrics.stringWidth(ov.getOutline().getColumnName(column));
|
||||
valuesWidth += firstColumnPadding; // add extra padding for first column
|
||||
|
||||
int columnWidth = Math.max(valuesWidth, headerWidth);
|
||||
columnWidth += 2 * margin + padding; // add margin and regular padding
|
||||
columnWidth = Math.min(columnWidth, columnWidthLimit);
|
||||
|
||||
ov.getOutline().getColumnModel().getColumn(column).setPreferredWidth(columnWidth);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// if there's no content just auto resize all columns
|
||||
if (content.length <= 0) {
|
||||
// turn on the auto resize
|
||||
ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||
ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||
}
|
||||
|
||||
/**
|
||||
* This custom renderer extends the renderer that was already being
|
||||
* used by the outline table. This renderer colors a row if the
|
||||
* tags property of the node is not empty.
|
||||
*/
|
||||
class ColorTagCustomRenderer extends DefaultOutlineCellRenderer {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(JTable table,
|
||||
Object value, boolean isSelected, boolean hasFocus, int row, int col) {
|
||||
|
||||
Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
|
||||
// only override the color if a node is not selected
|
||||
if (!isSelected) {
|
||||
Node node = currentRoot.getChildren().getNodeAt(table.convertRowIndexToModel(row));
|
||||
boolean tagFound = false;
|
||||
if (node != null) {
|
||||
Node.PropertySet[] propSets = node.getPropertySets();
|
||||
if (propSets.length != 0) {
|
||||
// currently, a node has only one property set, named Sheet.PROPERTIES ("properties")
|
||||
Node.Property<?>[] props = propSets[0].getProperties();
|
||||
for (Property<?> prop : props) {
|
||||
if (prop.getName().equals("Tags")) {
|
||||
try {
|
||||
tagFound = !prop.getValue().equals("");
|
||||
} catch (IllegalAccessException | InvocationTargetException ignore) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//if the node does have associated tags, set its background color
|
||||
if (tagFound) {
|
||||
component.setBackground(TAGGED_COLOR);
|
||||
}
|
||||
}
|
||||
return component;
|
||||
}
|
||||
}
|
||||
ov.getOutline().setDefaultRenderer(Object.class, new ColorTagCustomRenderer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the current column order into a preference file.
|
||||
*/
|
||||
private synchronized void storeState() {
|
||||
if (currentRoot == null || propertiesMap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TableFilterNode tfn;
|
||||
if (currentRoot instanceof TableFilterNode) {
|
||||
tfn = (TableFilterNode) currentRoot;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the current order of the columns into settings
|
||||
for (Map.Entry<Integer, Property<?>> entry : propertiesMap.entrySet()) {
|
||||
Property<?> prop = entry.getValue();
|
||||
int storeValue = entry.getKey();
|
||||
NbPreferences.forModule(this.getClass()).put(getColumnPreferenceKey(prop, tfn.getColumnOrderKey()), String.valueOf(storeValue));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* The following three methods were added for this feature
|
||||
/**
|
||||
* Loads the stored column order from the preference file.
|
||||
*
|
||||
* @return a List<Node.Property<?>> of the preferences in order
|
||||
*/
|
||||
// Store the state of current root Node.
|
||||
// private void storeState() {
|
||||
// if(currentRoot == null || propertiesAcc.isEmpty())
|
||||
// return;
|
||||
//
|
||||
// TableFilterNode tfn;
|
||||
// if(currentRoot instanceof TableFilterNode)
|
||||
// tfn = (TableFilterNode) currentRoot;
|
||||
// else
|
||||
// return;
|
||||
//
|
||||
// List<Node.Property<?>> props = new ArrayList<>(propertiesAcc);
|
||||
// for (int i = 0; i < props.size(); i++) {
|
||||
// Property<?> prop = props.get(i);
|
||||
// NbPreferences.forModule(this.getClass()).put(getUniqueColName(prop, tfn.getItemType()), String.valueOf(i));
|
||||
// }
|
||||
// }
|
||||
// Load the state of current root Node if exists.
|
||||
// private List<Node.Property<?>> loadState() {
|
||||
// propertiesAcc.clear();
|
||||
// this.getAllChildPropertyHeadersRec(currentRoot, 100);
|
||||
// List<Node.Property<?>> props = new ArrayList<>(propertiesAcc);
|
||||
//
|
||||
// // If node is not table filter node, use default order for columns
|
||||
// TableFilterNode tfn;
|
||||
// if (currentRoot instanceof TableFilterNode) {
|
||||
// tfn = (TableFilterNode) currentRoot;
|
||||
// } else {
|
||||
// Logger.getLogger(DataResultViewerTable.class.getName()).log(Level.INFO,
|
||||
// "Node {0} is not TableFilterNode, columns are going to be in default order", currentRoot.getName());
|
||||
// return props;
|
||||
// }
|
||||
//
|
||||
// List<Node.Property<?>> orderedProps = new ArrayList<>(propertiesAcc);
|
||||
// for (Property<?> prop : props) {
|
||||
// Integer value = Integer.valueOf(NbPreferences.forModule(this.getClass()).get(getUniqueColName(prop, tfn.getItemType()), "-1"));
|
||||
// if (value >= 0) {
|
||||
// /**
|
||||
// * The original contents of orderedProps do not matter when
|
||||
// * setting the new ordered values. The reason we copy
|
||||
// * propertiesAcc into it first is to give it the currect size so
|
||||
// * we can set() in any index.
|
||||
// */
|
||||
// orderedProps.set(value, prop);
|
||||
// }
|
||||
// }
|
||||
// propertiesAcc.clear();
|
||||
// for (Property<?> prop : orderedProps) {
|
||||
// propertiesAcc.add(prop);
|
||||
// }
|
||||
// return orderedProps;
|
||||
// }
|
||||
//
|
||||
// // Get unique name for node and it's property.
|
||||
// private String getUniqueColName(Property<?> prop, String type) {
|
||||
// return Case.getCurrentCase().getName() + "." + type + "."
|
||||
// + prop.getName().replaceAll("[^a-zA-Z0-9_]", "") + ".columnOrder";
|
||||
// }
|
||||
private synchronized List<Node.Property<?>> loadState() {
|
||||
// This is a set because we add properties of up to 100 child nodes, and we want unique properties
|
||||
Set<Property<?>> propertiesAcc = new LinkedHashSet<>();
|
||||
this.getAllChildPropertyHeadersRec(currentRoot, 100, propertiesAcc);
|
||||
|
||||
// Populate a two-dimensional array with rows of property values for up
|
||||
// to maxRows children of the node passed in.
|
||||
private static Object[][] getRowValues(Node node, int maxRows) {
|
||||
int numRows = Math.min(maxRows, node.getChildren().getNodesCount());
|
||||
Object[][] rowValues = new Object[numRows][];
|
||||
int rowCount = 0;
|
||||
for (Node child : node.getChildren().getNodes()) {
|
||||
if (rowCount >= maxRows) {
|
||||
break;
|
||||
}
|
||||
// BC: I got this once, I think it was because the table
|
||||
// refreshed while we were in this method
|
||||
// could be better synchronized. Or it was from
|
||||
// the lazy nodes updating... Didn't have time
|
||||
// to fully debug it.
|
||||
if (rowCount > numRows) {
|
||||
break;
|
||||
}
|
||||
PropertySet[] propertySets = child.getPropertySets();
|
||||
if (propertySets.length > 0) {
|
||||
Property<?>[] properties = propertySets[0].getProperties();
|
||||
rowValues[rowCount] = new Object[properties.length];
|
||||
for (int j = 0; j < properties.length; ++j) {
|
||||
try {
|
||||
rowValues[rowCount][j] = properties[j].getValue();
|
||||
} catch (IllegalAccessException | InvocationTargetException ignore) {
|
||||
rowValues[rowCount][j] = "n/a"; //NON-NLS
|
||||
}
|
||||
}
|
||||
}
|
||||
++rowCount;
|
||||
List<Node.Property<?>> props = new ArrayList<>(propertiesAcc);
|
||||
|
||||
// If node is not table filter node, use default order for columns
|
||||
TableFilterNode tfn;
|
||||
if (currentRoot instanceof TableFilterNode) {
|
||||
tfn = (TableFilterNode) currentRoot;
|
||||
} else {
|
||||
// The node is not a TableFilterNode, columns are going to be in default order
|
||||
return props;
|
||||
}
|
||||
return rowValues;
|
||||
|
||||
propertiesMap.clear();
|
||||
/*
|
||||
* We load column index values into the properties map. If a property's
|
||||
* index is outside the range of the number of properties or the index
|
||||
* has already appeared as the position of another property, we put that
|
||||
* property at the end.
|
||||
*/
|
||||
int offset = props.size();
|
||||
boolean noPreviousSettings = true;
|
||||
for (Property<?> prop : props) {
|
||||
Integer value = Integer.valueOf(NbPreferences.forModule(this.getClass()).get(getColumnPreferenceKey(prop, tfn.getColumnOrderKey()), "-1"));
|
||||
if (value >= 0 && value < offset && !propertiesMap.containsKey(value)) {
|
||||
propertiesMap.put(value, prop);
|
||||
noPreviousSettings = false;
|
||||
} else {
|
||||
propertiesMap.put(offset, prop);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
// If none of the properties had previous settings, we should decrement
|
||||
// each value by the number of properties to make the values 0-indexed.
|
||||
if (noPreviousSettings) {
|
||||
Integer[] keys = propertiesMap.keySet().toArray(new Integer[propertiesMap.keySet().size()]);
|
||||
for (int key : keys) {
|
||||
propertiesMap.put(key - props.size(), propertiesMap.get(key));
|
||||
propertiesMap.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<>(propertiesMap.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a key for the current node and a property of its child nodes to
|
||||
* store the column position into a preference file.
|
||||
*
|
||||
* @param prop Property of the column
|
||||
* @param type The type of the current node
|
||||
* @return A generated key for the preference file
|
||||
*/
|
||||
private String getColumnPreferenceKey(Property<?> prop, String type) {
|
||||
return type.replaceAll("[^a-zA-Z0-9_]", "") + "."
|
||||
+ prop.getName().replaceAll("[^a-zA-Z0-9_]", "") + ".column";
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -520,63 +572,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
return new DataResultViewerTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the max width of the column from the given index, header, and table.
|
||||
*
|
||||
* @param index the index of the column on the table / header
|
||||
* @param metrics the font metrics that this component use
|
||||
* @param margin the left/right margin of the column
|
||||
* @param padding the left/right padding of the column
|
||||
* @param header the property headers of the table
|
||||
* @param table the object table
|
||||
*
|
||||
* @return max the maximum width of the column
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private int getMaxColumnWidth(int index, FontMetrics metrics, int margin, int padding, List<Node.Property<?>> header, Object[][] table) {
|
||||
// set the tree (the node / names column) width
|
||||
String headerName = header.get(index - 1).getDisplayName();
|
||||
|
||||
return getMaxColumnWidth(index, metrics, margin, padding, headerName, table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the max width of the column from the given index, header, and table.
|
||||
*
|
||||
* @param index the index of the column on the table / header
|
||||
* @param metrics the font metrics that this component use
|
||||
* @param margin the left/right margin of the column
|
||||
* @param padding the left/right padding of the column
|
||||
* @param header the column header for the comparison
|
||||
* @param table the object table
|
||||
*
|
||||
* @return max the maximum width of the column
|
||||
*/
|
||||
private synchronized int getMaxColumnWidth(int index, FontMetrics metrics, int margin, int padding, String header, Object[][] table) {
|
||||
// set the tree (the node / names column) width
|
||||
String headerName = header;
|
||||
int headerWidth = metrics.stringWidth(headerName); // length of the header
|
||||
int colWidth = 0;
|
||||
|
||||
// Get maximum width of column data
|
||||
for (int i = 0; i < table.length; i++) {
|
||||
if (table[i] == null || index >= table[i].length) {
|
||||
continue;
|
||||
}
|
||||
String test = table[i][index].toString();
|
||||
colWidth = Math.max(colWidth, metrics.stringWidth(test));
|
||||
}
|
||||
|
||||
colWidth += padding; // add the padding on the most left gap
|
||||
headerWidth += 8; // add the padding to the header (change this value if the header padding value is changed)
|
||||
|
||||
// Set the width
|
||||
int width = Math.max(headerWidth, colWidth);
|
||||
width += 2 * margin; // Add margin
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearComponent() {
|
||||
this.tableScrollPanel.removeAll();
|
||||
@ -601,11 +596,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
setupTable(nme.getNode());
|
||||
} else {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setupTable(nme.getNode());
|
||||
}
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
setupTable(nme.getNode());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -25,10 +25,13 @@ import org.openide.util.NbBundle;
|
||||
/**
|
||||
* A filter node that creates at most one layer of child nodes for the node it
|
||||
* wraps. It is designed to be used for nodes displayed in Autopsy table views.
|
||||
* This ensures that the table view for the node will not recursively display
|
||||
* child nodes and display only the first layer of child nodes.
|
||||
*/
|
||||
public class TableFilterNode extends FilterNode {
|
||||
|
||||
private final boolean createChildren;
|
||||
private String columnOrderKey = "NONE";
|
||||
|
||||
/**
|
||||
* Constructs a filter node that creates at most one layer of child nodes
|
||||
@ -38,12 +41,29 @@ public class TableFilterNode extends FilterNode {
|
||||
* @param wrappedNode The node to wrap in the filter node.
|
||||
* @param createChildren True if a children (child factory) object should be
|
||||
* created for the wrapped node.
|
||||
* The constructor should include column order key. (See getColumnOrderKey)
|
||||
*/
|
||||
public TableFilterNode(Node wrappedNode, boolean createChildren) {
|
||||
super(wrappedNode, TableFilterChildren.createInstance(wrappedNode, createChildren));
|
||||
this.createChildren = createChildren;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a filter node that has information about the node's type.
|
||||
*
|
||||
* @param wrappedNode The node to wrap in the filter node.
|
||||
* @param createChildren True if a children (child factory) object should be
|
||||
* created for the wrapped node.
|
||||
* @param columnOrderKey A key that represents the type of the original
|
||||
* wrapped node and what is being displayed under that
|
||||
* node.
|
||||
*/
|
||||
public TableFilterNode(Node wrappedNode, boolean createChildren, String columnOrderKey) {
|
||||
super(wrappedNode, TableFilterChildren.createInstance(wrappedNode, createChildren));
|
||||
this.createChildren = createChildren;
|
||||
this.columnOrderKey = columnOrderKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a display name for the wrapped node, for use in the first column
|
||||
* of an Autopsy table view.
|
||||
@ -59,4 +79,14 @@ public class TableFilterNode extends FilterNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the column order key, which allows custom column ordering to be
|
||||
* written into a properties file and be reloaded for future use in
|
||||
* a table with the same root node or for different cases. This is
|
||||
* done by DataResultViewerTable. The key should represent what
|
||||
* kinds of items the table is showing.
|
||||
*/
|
||||
String getColumnOrderKey() {
|
||||
return columnOrderKey;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2015 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.coreutils;
|
||||
|
||||
import org.sleuthkit.datamodel.SleuthkitJNI;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Utility methods for working with data sources.
|
||||
*/
|
||||
public class DataSourceUtils {
|
||||
|
||||
/**
|
||||
* Calls TSK to determine whether a
|
||||
* potential data source has a file system.
|
||||
*
|
||||
* @param dataSourcePath The path to the data source.
|
||||
*
|
||||
* @return True or false.
|
||||
*
|
||||
* @throws IOException if an error occurs while trying to determine if the
|
||||
* data source has a file system.
|
||||
*/
|
||||
public static boolean imageHasFileSystem(Path dataSourcePath) throws IOException {
|
||||
return SleuthkitJNI.isImageSupported(dataSourcePath.toString());
|
||||
}
|
||||
}
|
@ -56,7 +56,7 @@ public class DriveUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not a drive exists by eading the first byte and
|
||||
* Determines whether or not a drive exists by reading the first byte and
|
||||
* checking if it is a -1.
|
||||
*
|
||||
* @param path The path to test.
|
||||
|
@ -1,15 +1,15 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2014 Basis Technology Corp.
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -20,17 +20,24 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.openide.nodes.Children;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
@ -103,9 +110,23 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||
removeListeners();
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())) {
|
||||
ContentTagAddedEvent event = (ContentTagAddedEvent) evt;
|
||||
if (event.getAddedTag().getContent().equals(content)) {
|
||||
updateSheet();
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) {
|
||||
ContentTagDeletedEvent event = (ContentTagDeletedEvent) evt;
|
||||
if (event.getDeletedTagInfo().getContentID() == content.getId()) {
|
||||
updateSheet();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void updateSheet() {
|
||||
this.setSheet(createSheet());
|
||||
}
|
||||
|
||||
// Note: this order matters for the search result, changed it if the order of property headers on the "KeywordSearchNode"changed
|
||||
public static enum AbstractFilePropertyType {
|
||||
|
||||
@ -278,6 +299,24 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
||||
map.put(AbstractFilePropertyType.MIMETYPE.toString(), content.getMIMEType() == null ? "" : content.getMIMEType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by subclasses of AbstractAbstractFileNode to add the tags property
|
||||
* to their sheets.
|
||||
* @param ss the modifiable Sheet.Set returned by Sheet.get(Sheet.PROPERTIES)
|
||||
*/
|
||||
protected void addTagProperty(Sheet.Set ss) {
|
||||
final String NO_DESCR = NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.addFileProperty.desc");
|
||||
List<ContentTag> tags;
|
||||
try {
|
||||
tags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(content);
|
||||
} catch (TskCoreException ex) {
|
||||
tags = new ArrayList<>();
|
||||
LOGGER.log(Level.SEVERE, "Failed to get tags for content " + content.getName(), ex);
|
||||
}
|
||||
ss.put(new NodeProperty<>("Tags", NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.addFileProperty.tags.displayName"),
|
||||
NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", "))));
|
||||
}
|
||||
|
||||
static String getContentDisplayName(AbstractFile file) {
|
||||
String name = file.getName();
|
||||
switch (name) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2014 Basis Technology Corp.
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -22,8 +22,7 @@ import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children.Keys;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.FileTypeExtensionFilters;
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.RecentFiles;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode;
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.Accounts.AccountsRootNode;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
@ -33,6 +32,7 @@ import org.sleuthkit.datamodel.File;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
import org.sleuthkit.datamodel.LayoutFile;
|
||||
import org.sleuthkit.datamodel.LocalFile;
|
||||
import org.sleuthkit.datamodel.SlackFile;
|
||||
import org.sleuthkit.datamodel.SleuthkitItemVisitor;
|
||||
import org.sleuthkit.datamodel.SleuthkitVisitableItem;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
@ -108,6 +108,11 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
|
||||
return new VirtualDirectoryNode(ld);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractContentNode<? extends Content> visit(SlackFile sf) {
|
||||
return new SlackFileNode(sf);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractContentNode<? extends Content> defaultVisit(SleuthkitVisitableItem di) {
|
||||
throw new UnsupportedOperationException(NbBundle.getMessage(this.getClass(),
|
||||
@ -130,8 +135,8 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(FileTypeExtensionFilters sf) {
|
||||
return new FileTypesNode(sf.getSleuthkitCase(), null);
|
||||
public AbstractNode visit(FileTypesByExtension sf) {
|
||||
return new org.sleuthkit.autopsy.datamodel.FileTypesByExtension.FileTypesByExtNode(sf.getSleuthkitCase(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -189,6 +194,11 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
|
||||
return new ResultsNode(r.getSleuthkitCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(FileTypes ft) {
|
||||
return new FileTypesNode(ft.getSleuthkitCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(Reports reportsItem) {
|
||||
return new Reports.ReportsListNode();
|
||||
@ -205,5 +215,10 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"AbstractContentChildren.createAutopsyNodeVisitor.exception.noNodeMsg"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(FileTypesByMimeType ftByMimeTypeItem) {
|
||||
return ftByMimeTypeItem.new ByMimeTypeNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +84,9 @@ public abstract class AbstractFsContentNode<T extends AbstractFile> extends Abst
|
||||
ss.put(new NodeProperty<>(HIDE_PARENT, HIDE_PARENT, HIDE_PARENT, HIDE_PARENT));
|
||||
}
|
||||
|
||||
// add tags property to the sheet
|
||||
addTagProperty(ss);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,6 @@
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.TimeZone;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@ -42,7 +41,7 @@ public class ArtifactStringContent implements StringContent {
|
||||
BlackboardArtifact artifact;
|
||||
private String stringContent = "";
|
||||
static final Logger logger = Logger.getLogger(ArtifactStringContent.class.getName());
|
||||
private static SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
public ArtifactStringContent(BlackboardArtifact art) {
|
||||
artifact = art;
|
||||
@ -74,7 +73,7 @@ public class ArtifactStringContent implements StringContent {
|
||||
buffer.append("<tr><td>"); //NON-NLS
|
||||
buffer.append(attr.getAttributeType().getDisplayName());
|
||||
buffer.append("</td>"); //NON-NLS
|
||||
|
||||
|
||||
// value column
|
||||
buffer.append("<td>"); //NON-NLS
|
||||
switch (attr.getAttributeType().getValueType()) {
|
||||
|
@ -19,8 +19,6 @@
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.FileTypeExtensionFilters;
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.RecentFiles;
|
||||
|
||||
/**
|
||||
* This visitor goes over the AutopsyVisitableItems, which are currently the
|
||||
@ -33,13 +31,13 @@ public interface AutopsyItemVisitor<T> {
|
||||
|
||||
T visit(Views v);
|
||||
|
||||
T visit(FileTypeExtensionFilters sf);
|
||||
T visit(FileTypesByExtension sf);
|
||||
|
||||
T visit(FileTypeExtensionFilters.RootFilter fsf);
|
||||
T visit(FileTypesByExtension.RootFilter fsf);
|
||||
|
||||
T visit(FileTypeExtensionFilters.DocumentFilter df);
|
||||
T visit(FileTypesByExtension.DocumentFilter df);
|
||||
|
||||
T visit(FileTypeExtensionFilters.ExecutableFilter ef);
|
||||
T visit(FileTypesByExtension.ExecutableFilter ef);
|
||||
|
||||
T visit(RecentFiles rf);
|
||||
|
||||
@ -71,6 +69,11 @@ public interface AutopsyItemVisitor<T> {
|
||||
|
||||
T visit(Accounts accountsItem);
|
||||
|
||||
T visit(FileTypes fileTypesItem);
|
||||
|
||||
T visit(FileTypesByMimeType aThis);
|
||||
|
||||
|
||||
static abstract public class Default<T> implements AutopsyItemVisitor<T> {
|
||||
|
||||
protected abstract T defaultVisit(AutopsyVisitableItem ec);
|
||||
@ -81,25 +84,30 @@ public interface AutopsyItemVisitor<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(FileTypeExtensionFilters sf) {
|
||||
public T visit(FileTypesByExtension sf) {
|
||||
return defaultVisit(sf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(FileTypeExtensionFilters.RootFilter fsf) {
|
||||
public T visit(FileTypesByExtension.RootFilter fsf) {
|
||||
return defaultVisit(fsf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(FileTypeExtensionFilters.DocumentFilter df) {
|
||||
public T visit(FileTypesByExtension.DocumentFilter df) {
|
||||
return defaultVisit(df);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(FileTypeExtensionFilters.ExecutableFilter ef) {
|
||||
public T visit(FileTypesByExtension.ExecutableFilter ef) {
|
||||
return defaultVisit(ef);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public T visit(FileTypesByMimeType ftByMimeType) {
|
||||
return defaultVisit(ftByMimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(DeletedContent dc) {
|
||||
return defaultVisit(dc);
|
||||
@ -170,6 +178,12 @@ public interface AutopsyItemVisitor<T> {
|
||||
return defaultVisit(r);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public T visit(FileTypes ft) {
|
||||
return defaultVisit(ft);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(Reports reportsItem) {
|
||||
return defaultVisit(reportsItem);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -25,6 +27,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.swing.Action;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.nodes.Children;
|
||||
@ -35,6 +38,10 @@ import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
||||
import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction;
|
||||
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
@ -43,6 +50,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.Tag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
@ -70,6 +78,39 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
private static final Integer[] SHOW_FILE_METADATA = new Integer[]{
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),};
|
||||
|
||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString())) {
|
||||
BlackBoardArtifactTagAddedEvent event = (BlackBoardArtifactTagAddedEvent) evt;
|
||||
if (event.getAddedTag().getArtifact().equals(artifact)) {
|
||||
updateSheet();
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString())) {
|
||||
BlackBoardArtifactTagDeletedEvent event = (BlackBoardArtifactTagDeletedEvent) evt;
|
||||
if (event.getDeletedTagInfo().getArtifactID() == artifact.getArtifactID()) {
|
||||
updateSheet();
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())) {
|
||||
ContentTagAddedEvent event = (ContentTagAddedEvent) evt;
|
||||
if (event.getAddedTag().getContent().equals(associated)) {
|
||||
updateSheet();
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) {
|
||||
ContentTagDeletedEvent event = (ContentTagDeletedEvent) evt;
|
||||
if (event.getDeletedTagInfo().getContentID()== associated.getId()) {
|
||||
updateSheet();
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
if (evt.getNewValue() == null) {
|
||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||
removeListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct blackboard artifact node from an artifact and using provided
|
||||
* icon
|
||||
@ -86,6 +127,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
this.setName(Long.toString(artifact.getArtifactID()));
|
||||
this.setDisplayName();
|
||||
this.setIconBaseWithExtension(iconPath);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,6 +145,11 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
this.setName(Long.toString(artifact.getArtifactID()));
|
||||
this.setDisplayName();
|
||||
this.setIconBaseWithExtension(ExtractedContent.getIconFilePath(artifact.getArtifactTypeID())); //NON-NLS
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -157,7 +204,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
displayName = associated.getName();
|
||||
}
|
||||
|
||||
// If this is a node for a keyword hit on an artifact, we set the
|
||||
// If this is a node for a keyword hit on an artifact, we set the
|
||||
// display name to be the artifact type name followed by " Artifact"
|
||||
// e.g. "Messages Artifact".
|
||||
if (artifact != null && artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
||||
@ -208,6 +255,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
ss.put(np);
|
||||
}
|
||||
}
|
||||
|
||||
final int artifactTypeId = artifact.getArtifactTypeID();
|
||||
|
||||
// If mismatch, add props for extension and file type
|
||||
@ -294,9 +342,24 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
}
|
||||
}
|
||||
|
||||
// add properties for tags
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
try {
|
||||
tags.addAll(Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact));
|
||||
tags.addAll(Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(associated));
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to get tags for artifact " + artifact.getDisplayName(), ex);
|
||||
}
|
||||
ss.put(new NodeProperty<>("Tags", NbBundle.getMessage(AbstractAbstractFileNode.class, "BlackboardArtifactNode.createSheet.tags.displayName"),
|
||||
NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", "))));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private void updateSheet() {
|
||||
this.setSheet(createSheet());
|
||||
}
|
||||
|
||||
private String getRootParentName() {
|
||||
String parentName = associated.getName();
|
||||
Content parent = associated;
|
||||
@ -448,13 +511,8 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "BlackboardArtifact"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2014 Basis Technology Corp.
|
||||
* Copyright 2013-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -145,13 +145,8 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "BlackboardArtifactTag"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
@ -118,16 +118,16 @@ FileSize.createSheet.filterType.displayName=Filter Type
|
||||
FileSize.createSheet.filterType.desc=no description
|
||||
FileSize.exception.notSupported.msg=Not supported for this type of Displayable Item\: {0}
|
||||
FileTypeChildren.exception.notSupported.msg=Not supported for this type of Displayable Item\: {0}
|
||||
FileTypeNode.createSheet.filterType.name=Filter Type
|
||||
FileTypeNode.createSheet.filterType.displayName=Filter Type
|
||||
FileTypeNode.createSheet.filterType.desc=no description
|
||||
FileTypeNode.createSheet.fileExt.name=File Extensions
|
||||
FileTypeNode.createSheet.fileExt.displayName=File Extensions
|
||||
FileTypeNode.createSheet.fileExt.desc=no description
|
||||
FileTypesNode.fname.text=File Types
|
||||
FileTypesNode.createSheet.name.name=Name
|
||||
FileTypesNode.createSheet.name.displayName=Name
|
||||
FileTypesNode.createSheet.name.desc=no description
|
||||
FileTypesByExtNode.createSheet.filterType.name=Filter Type
|
||||
FileTypesByExtNode.createSheet.filterType.displayName=Filter Type
|
||||
FileTypesByExtNode.createSheet.filterType.desc=no description
|
||||
FileTypesByExtNode.createSheet.fileExt.name=File Extensions
|
||||
FileTypesByExtNode.createSheet.fileExt.displayName=File Extensions
|
||||
FileTypesByExtNode.createSheet.fileExt.desc=no description
|
||||
FileTypesByExtNode.fname.text=By Extension
|
||||
FileTypesByExtNode.createSheet.name.name=Name
|
||||
FileTypesByExtNode.createSheet.name.displayName=Name
|
||||
FileTypesByExtNode.createSheet.name.desc=no description
|
||||
HashsetHits.createSheet.name.name=Name
|
||||
HashsetHits.createSheet.name.displayName=Name
|
||||
HashsetHits.createSheet.name.desc=no description
|
||||
@ -222,6 +222,10 @@ ReportNode.reportNameProperty.name=Report Name
|
||||
ReportNode.reportNameProperty.displayName=Report Name
|
||||
ReportNode.reportNameProperty.desc=Name of the report
|
||||
ReportsListNode.displayName=Reports
|
||||
SlackFileFilterNode.selectionContext.dataSources=Data Sources
|
||||
SlackFileFilterNode.selectionContext.views=Views
|
||||
SlackFileNode.getActions.viewInNewWin.text=View in New Window
|
||||
SlackFileNode.getActions.viewFileInDir.text=View File in Directory
|
||||
TagNameNode.namePlusTags.text={0} Tags
|
||||
TagNameNode.contentTagTypeNodeKey.text=Content Tags
|
||||
TagNameNode.bbArtTagTypeNodeKey.text=Result Tags
|
||||
@ -266,3 +270,19 @@ DeleteReportAction.actionDisplayName.multipleReports=Delete Reports
|
||||
DeleteReportAction.actionPerformed.showConfirmDialog.title=Confirm Deletion
|
||||
DeleteReportAction.actionPerformed.showConfirmDialog.single.msg=Do you want to delete 1 report from the case?
|
||||
DeleteReportAction.actionPerformed.showConfirmDialog.multiple.msg=Do you want to delete {0} reports from the case?
|
||||
AbstractAbstractFileNode.addFileProperty.desc=no description
|
||||
AbstractAbstractFileNode.addFileProperty.tags.name=Tags
|
||||
AbstractAbstractFileNode.addFileProperty.tags.displayName=Tags
|
||||
BlackboardArtifactNode.createSheet.tags.name=Tags
|
||||
BlackboardArtifactNode.createSheet.tags.displayName=Tags
|
||||
FileTypeExtensionFilters.tskImgFilter.text=Images
|
||||
FileTypeExtensionFilters.tskVideoFilter.text=Videos
|
||||
FileTypeExtensionFilters.tskAudioFilter.text=Audio
|
||||
FileTypeExtensionFilters.tskArchiveFilter.text=Archives
|
||||
FileTypeExtensionFilters.tskDocumentFilter.text=Documents
|
||||
FileTypeExtensionFilters.tskExecFilter.text=Executable
|
||||
FileTypeExtensionFilters.autDocHtmlFilter.text=HTML
|
||||
FileTypeExtensionFilters.autDocOfficeFilter.text=Office
|
||||
FileTypeExtensionFilters.autoDocPdfFilter.text=PDF
|
||||
FileTypeExtensionFilters.autDocTxtFilter.text=Plain Text
|
||||
FileTypeExtensionFilters.autDocRtfFilter.text=Rich Text
|
@ -112,16 +112,15 @@ FileTypeExtensionFilters.autDocOfficeFilter.text=\u30aa\u30d5\u30a3\u30b9
|
||||
FileTypeExtensionFilters.autoDocPdfFilter.text=PDF
|
||||
FileTypeExtensionFilters.autDocTxtFilter.text=\u30d7\u30ec\u30fc\u30f3\u30c6\u30ad\u30b9\u30c8
|
||||
FileTypeExtensionFilters.autDocRtfFilter.text=\u30ea\u30c3\u30c1\u30c6\u30ad\u30b9\u30c8
|
||||
FileTypeNode.createSheet.filterType.name=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7
|
||||
FileTypeNode.createSheet.filterType.displayName=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7
|
||||
FileTypeNode.createSheet.filterType.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093
|
||||
FileTypeNode.createSheet.fileExt.name=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50
|
||||
FileTypeNode.createSheet.fileExt.displayName=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50
|
||||
FileTypeNode.createSheet.fileExt.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093
|
||||
FileTypesNode.fname.text=\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7
|
||||
FileTypesNode.createSheet.name.name=\u540d\u524d
|
||||
FileTypesNode.createSheet.name.displayName=\u540d\u524d
|
||||
FileTypesNode.createSheet.name.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093
|
||||
FileTypesByExtNode.createSheet.filterType.name=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7
|
||||
FileTypesByExtNode.createSheet.filterType.displayName=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7
|
||||
FileTypesByExtNode.createSheet.filterType.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093
|
||||
FileTypesByExtNode.createSheet.fileExt.name=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50
|
||||
FileTypesByExtNode.createSheet.fileExt.displayName=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50
|
||||
FileTypesByExtNode.createSheet.fileExt.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093
|
||||
FileTypesByExtNode.createSheet.name.name=\u540d\u524d
|
||||
FileTypesByExtNode.createSheet.name.displayName=\u540d\u524d
|
||||
FileTypesByExtNode.createSheet.name.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093
|
||||
HashsetHits.createSheet.name.name=\u540d\u524d
|
||||
HashsetHits.createSheet.name.displayName=\u540d\u524d
|
||||
HashsetHits.createSheet.name.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093
|
||||
|
@ -41,6 +41,8 @@ interface ContentNodeVisitor<T> {
|
||||
T visit(LayoutFileNode lcn);
|
||||
|
||||
T visit(LocalFileNode dfn);
|
||||
|
||||
T visit(SlackFileNode sfn);
|
||||
|
||||
/**
|
||||
* Visitor with an implementable default behavior for all types. Override
|
||||
@ -93,5 +95,10 @@ interface ContentNodeVisitor<T> {
|
||||
public T visit(VirtualDirectoryNode ldn) {
|
||||
return defaultVisit(ldn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(SlackFileNode sfn) {
|
||||
return defaultVisit(sfn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 Basis Technology Corp.
|
||||
* Copyright 2013-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -42,6 +42,8 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
*/
|
||||
class ContentTagNode extends DisplayableItemNode {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(ContentTagNode.class.getName());
|
||||
|
||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/blue-tag-icon-16.png"; //NON-NLS
|
||||
private final ContentTag tag;
|
||||
|
||||
@ -60,7 +62,7 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
try {
|
||||
contentPath = content.getUniquePath();
|
||||
} catch (TskCoreException ex) {
|
||||
Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + content.getId() + ")", ex); //NON-NLS
|
||||
LOGGER.log(Level.SEVERE, "Failed to get path for content (id = " + content.getId() + ")", ex); //NON-NLS
|
||||
contentPath = NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.unavail.path");
|
||||
}
|
||||
AbstractFile file = content instanceof AbstractFile ? (AbstractFile) content : null;
|
||||
@ -103,6 +105,7 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.displayName"),
|
||||
"",
|
||||
content.getSize()));
|
||||
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
@ -115,7 +118,7 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
if (file != null) {
|
||||
actions.add(ViewFileInTimelineAction.createViewFileAction(file));
|
||||
}
|
||||
actions.add(null); // Adds a menu item separator.
|
||||
actions.add(null); // Adds a menu item separator.
|
||||
actions.add(DeleteContentTagAction.getInstance());
|
||||
return actions.toArray(new Action[actions.size()]);
|
||||
}
|
||||
@ -130,13 +133,8 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "ContentTag"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ import org.sleuthkit.datamodel.Image;
|
||||
import org.sleuthkit.datamodel.LayoutFile;
|
||||
import org.sleuthkit.datamodel.LocalFile;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||
import org.sleuthkit.datamodel.SlackFile;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
|
||||
@ -355,6 +356,18 @@ public final class ContentUtils {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(SlackFile f) {
|
||||
try {
|
||||
ContentUtils.writeToFile(f, dest, progress, worker, source);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE,
|
||||
"Trouble extracting slack file to " + dest.getAbsolutePath(), //NON-NLS
|
||||
ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(Directory dir) {
|
||||
|
@ -37,6 +37,7 @@ import org.sleuthkit.datamodel.Directory;
|
||||
import org.sleuthkit.datamodel.File;
|
||||
import org.sleuthkit.datamodel.LayoutFile;
|
||||
import org.sleuthkit.datamodel.LocalFile;
|
||||
import org.sleuthkit.datamodel.SlackFile;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
|
||||
/**
|
||||
@ -80,6 +81,23 @@ public class DataModelActionsFactory {
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
public static List<Action> getActions(SlackFile slackFile, boolean isArtifactSource) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), slackFile));
|
||||
final SlackFileNode slackFileNode = new SlackFileNode(slackFile);
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, slackFileNode));
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
if (isArtifactSource) {
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
}
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
public static List<Action> getActions(LayoutFile file, boolean isArtifactSource) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
@ -184,6 +202,8 @@ public class DataModelActionsFactory {
|
||||
return getActions((LocalFile) content, isArtifactSource);
|
||||
} else if (content instanceof DerivedFile) {
|
||||
return getActions((DerivedFile) content, isArtifactSource);
|
||||
} else if (content instanceof SlackFile) {
|
||||
return getActions((SlackFile) content, isArtifactSource);
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2014 Basis Technology Corp.
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -23,6 +23,7 @@ import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
@ -56,15 +57,10 @@ public class DataSourcesNode extends DisplayableItemNode {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png"); //NON-NLS
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "DataSources"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
/*
|
||||
* Custom Keys implementation that listens for new data sources being added.
|
||||
@ -108,7 +104,7 @@ public class DataSourcesNode extends DisplayableItemNode {
|
||||
currentKeys = Case.getCurrentCase().getDataSources();
|
||||
setKeys(currentKeys);
|
||||
} catch (TskCoreException | IllegalStateException ex) {
|
||||
logger.severe("Error getting data sources: " + ex.getMessage()); // NON-NLS
|
||||
logger.log(Level.SEVERE, "Error getting data sources: {0}", ex.getMessage()); // NON-NLS
|
||||
setKeys(Collections.<Content>emptySet());
|
||||
}
|
||||
}
|
||||
|
@ -147,15 +147,10 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "DeletedContent"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeletedContentsChildren extends ChildFactory<DeletedContent.DeletedContentFilter> {
|
||||
@ -285,16 +280,6 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering
|
||||
* code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "DeletedContentChildren"; //NON-NLS
|
||||
// }
|
||||
// update the display name when new events are fired
|
||||
private class DeletedContentNodeObserver implements Observer {
|
||||
|
||||
@ -338,8 +323,17 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
/**
|
||||
* Return getClass().getName() + filter.getName() if custom
|
||||
* settings are desired for different filters.
|
||||
*/
|
||||
return DisplayableItemNode.FILE_PARENT_NODE_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
static class DeletedContentChildren extends ChildFactory.Detachable<AbstractFile> {
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
|
@ -105,13 +105,8 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "Directory"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return DisplayableItemNode.FILE_PARENT_NODE_KEY;
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
*/
|
||||
public abstract class DisplayableItemNode extends AbstractNode {
|
||||
|
||||
final static String FILE_PARENT_NODE_KEY = "orgsleuthkitautopsydatamodel" + "FileTypeParentNode";
|
||||
|
||||
public DisplayableItemNode(Children children) {
|
||||
super(children);
|
||||
}
|
||||
@ -45,18 +47,22 @@ public abstract class DisplayableItemNode extends AbstractNode {
|
||||
|
||||
public abstract <T> T accept(DisplayableItemNodeVisitor<T> v);
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
/**
|
||||
* Returns type of DisplayableItemNode to allow TableFilterNode to pass
|
||||
* the information to DataResultViewerTable to allow custom settings for
|
||||
* column orderings.
|
||||
*
|
||||
* Added to support this feature.
|
||||
* @return A String representing the type of node, based on its name and
|
||||
* whether or not it wraps any special items (filters, artifact
|
||||
* types).
|
||||
*/
|
||||
// public abstract String getItemType();
|
||||
public abstract String getItemType();
|
||||
|
||||
/**
|
||||
* this code started as a cut and past of
|
||||
* DataResultFilterNode.GetPopupActionsDisplayableItemNodeVisitor.findLinked(BlackboardArtifactNode
|
||||
* ba)
|
||||
*
|
||||
*
|
||||
* @param artifact
|
||||
*
|
||||
* @return
|
||||
|
@ -22,6 +22,7 @@ import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.De
|
||||
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
|
||||
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode;
|
||||
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode;
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
|
||||
|
||||
/**
|
||||
@ -49,12 +50,15 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
|
||||
T visit(VolumeNode vn);
|
||||
|
||||
T visit(SlackFileNode sfn);
|
||||
|
||||
|
||||
/*
|
||||
* Views Area
|
||||
*/
|
||||
T visit(ViewsNode vn);
|
||||
|
||||
T visit(FileTypeNode fsfn);
|
||||
T visit(org.sleuthkit.autopsy.datamodel.FileTypesByExtension.FileExtensionNode fsfn);
|
||||
|
||||
T visit(DeletedContentNode dcn);
|
||||
|
||||
@ -64,7 +68,7 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
|
||||
T visit(FileSizeNode fsn);
|
||||
|
||||
T visit(FileTypesNode sfn);
|
||||
T visit(org.sleuthkit.autopsy.datamodel.FileTypesByExtension.FileTypesByExtNode sfn);
|
||||
|
||||
T visit(RecentFilesNode rfn);
|
||||
|
||||
@ -140,6 +144,16 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
|
||||
T visit(Accounts.DefaultAccountTypeNode node);
|
||||
|
||||
T visit(FileTypes.FileTypesNode fileTypes);
|
||||
|
||||
T visit(FileTypesByMimeType.ByMimeTypeNode ftByMimeTypeNode);
|
||||
|
||||
T visit(FileTypesByMimeType.MediaTypeNode ftByMimeTypeMediaType);
|
||||
|
||||
T visit(FileTypesByMimeType.MediaSubTypeNode ftByMimeTypeMediaSubType);
|
||||
|
||||
T visit(EmptyNode.MessageNode emptyNode);
|
||||
|
||||
/**
|
||||
* Visitor with an implementable default behavior for all types. Override
|
||||
* specific visit types to not use the default behavior.
|
||||
@ -177,6 +191,11 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
return defaultVisit(vn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(SlackFileNode sfn) {
|
||||
return defaultVisit(sfn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(BlackboardArtifactNode ban) {
|
||||
return defaultVisit(ban);
|
||||
@ -193,10 +212,30 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(FileTypeNode fsfn) {
|
||||
public T visit(org.sleuthkit.autopsy.datamodel.FileTypesByExtension.FileExtensionNode fsfn) {
|
||||
return defaultVisit(fsfn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(FileTypesByMimeType.ByMimeTypeNode ftByMimeTypeNode) {
|
||||
return defaultVisit(ftByMimeTypeNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(FileTypesByMimeType.MediaTypeNode ftByMimeTypeMediaTypeNode) {
|
||||
return defaultVisit(ftByMimeTypeMediaTypeNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(FileTypesByMimeType.MediaSubTypeNode ftByMimeTypeMediaTypeNode) {
|
||||
return defaultVisit(ftByMimeTypeMediaTypeNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(EmptyNode.MessageNode ftByMimeTypeEmptyNode) {
|
||||
return defaultVisit(ftByMimeTypeEmptyNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(DeletedContentNode dcn) {
|
||||
return defaultVisit(dcn);
|
||||
@ -218,7 +257,7 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(FileTypesNode sfn) {
|
||||
public T visit(org.sleuthkit.autopsy.datamodel.FileTypesByExtension.FileTypesByExtNode sfn) {
|
||||
return defaultVisit(sfn);
|
||||
}
|
||||
|
||||
@ -257,6 +296,11 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
return defaultVisit(rn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(FileTypesNode ft) {
|
||||
return defaultVisit(ft);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(DataSourcesNode in) {
|
||||
return defaultVisit(in);
|
||||
@ -381,6 +425,7 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
public T visit(Accounts.BINNode node) {
|
||||
return defaultVisit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(Accounts.DefaultAccountTypeNode node) {
|
||||
return defaultVisit(node);
|
||||
|
@ -204,15 +204,10 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "EmailExtractedRoot"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -364,15 +359,10 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "EmailExtractedAccount"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -460,15 +450,10 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "EmailExtractedFolder"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
97
Core/src/org/sleuthkit/autopsy/datamodel/EmptyNode.java
Normal file
97
Core/src/org/sleuthkit/autopsy/datamodel/EmptyNode.java
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.util.List;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
|
||||
/**
|
||||
* Provides a root node for the results views with a single child node that
|
||||
* displays a message as the sole item in its property sheet, useful for
|
||||
* displaying explanatory text in the result views when there is a node with no
|
||||
* children in the tree view.
|
||||
*/
|
||||
public final class EmptyNode extends AbstractNode {
|
||||
|
||||
/**
|
||||
* Provides a root node for the results views with a single child node that
|
||||
* displays a message as the sole item in its property sheet, useful for
|
||||
* displaying explanatory text in the result views when there is a node with
|
||||
* no children in the tree view.
|
||||
*
|
||||
* @param displayedMessage The text for the property sheet of the child
|
||||
* node.
|
||||
*/
|
||||
public EmptyNode(String displayedMessage) {
|
||||
super(Children.create(new EmptyNodeChildren(displayedMessage), true));
|
||||
}
|
||||
|
||||
static class EmptyNodeChildren extends ChildFactory<String> {
|
||||
|
||||
String displayedMessage;
|
||||
|
||||
private EmptyNodeChildren(String displayedMessage) {
|
||||
this.displayedMessage = displayedMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<String> keys) {
|
||||
keys.add(displayedMessage);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(String key) {
|
||||
return new MessageNode(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The single child node of an EmptyNode, responsible for displaying a
|
||||
* message as the sole item in its property sheet.
|
||||
*/
|
||||
static class MessageNode extends DisplayableItemNode {
|
||||
|
||||
MessageNode(String name) {
|
||||
super(Children.LEAF);
|
||||
super.setName(name);
|
||||
setName(name);
|
||||
setDisplayName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
}
|
@ -169,15 +169,10 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "ExtractedContentRoot"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -374,15 +369,10 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return type.getDisplayName();
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName() + type.getDisplayName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,13 +170,8 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "File"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
@ -144,15 +144,10 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "FileSizeRoot"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -291,16 +286,15 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering
|
||||
* code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "FileSize"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
/**
|
||||
* Return getClass().getName() + filter.getName() if custom
|
||||
* settings are desired for different filters.
|
||||
*/
|
||||
return DisplayableItemNode.FILE_PARENT_NODE_KEY;
|
||||
}
|
||||
|
||||
// update the display name when new events are fired
|
||||
private class FileSizeNodeObserver implements Observer {
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2013 Basis Technology Corp.
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -74,4 +74,8 @@ public class FileTypeExtensions {
|
||||
public static List<String> getArchiveExtensions() {
|
||||
return ARCHIVE_EXTENSIONS;
|
||||
}
|
||||
|
||||
private FileTypeExtensions() {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,277 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2014 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.FileTypeExtensionFilters;
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.ContentVisitor;
|
||||
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.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* Node for a specific file type / extension. Children of it will be the files
|
||||
* of that type.
|
||||
*/
|
||||
public class FileTypeNode extends DisplayableItemNode {
|
||||
|
||||
FileTypeExtensionFilters.SearchFilterInterface filter;
|
||||
SleuthkitCase skCase;
|
||||
|
||||
// deprecated in favor of the version that takes an observable to provide refresh updates
|
||||
@Deprecated
|
||||
FileTypeNode(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase) {
|
||||
super(Children.create(new FileTypeChildFactory(filter, skCase), true), Lookups.singleton(filter.getDisplayName()));
|
||||
this.filter = filter;
|
||||
this.skCase = skCase;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param filter Extensions that will be shown for this node
|
||||
* @param skCase
|
||||
* @param o Observable that sends updates when the child factories
|
||||
* should refresh
|
||||
*/
|
||||
FileTypeNode(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) {
|
||||
super(Children.create(new FileTypeChildFactory(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName()));
|
||||
this.filter = filter;
|
||||
this.skCase = skCase;
|
||||
init();
|
||||
o.addObserver(new FileTypeNodeObserver());
|
||||
}
|
||||
|
||||
private void init() {
|
||||
super.setName(filter.getName());
|
||||
updateDisplayName();
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "FileType"; //NON-NLS
|
||||
// }
|
||||
|
||||
// update the display name when new events are fired
|
||||
private class FileTypeNodeObserver implements Observer {
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
updateDisplayName();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDisplayName() {
|
||||
final long count = FileTypeChildFactory.calculateItems(skCase, filter);
|
||||
super.setDisplayName(filter.getDisplayName() + " (" + count + ")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||
if (ss == null) {
|
||||
ss = Sheet.createPropertiesSet();
|
||||
s.put(ss);
|
||||
}
|
||||
|
||||
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypeNode.createSheet.filterType.name"),
|
||||
NbBundle.getMessage(this.getClass(), "FileTypeNode.createSheet.filterType.displayName"),
|
||||
NbBundle.getMessage(this.getClass(), "FileTypeNode.createSheet.filterType.desc"),
|
||||
filter.getDisplayName()));
|
||||
String extensions = "";
|
||||
for (String ext : filter.getFilter()) {
|
||||
extensions += "'" + ext + "', ";
|
||||
}
|
||||
extensions = extensions.substring(0, extensions.lastIndexOf(','));
|
||||
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypeNode.createSheet.fileExt.name"),
|
||||
NbBundle.getMessage(this.getClass(), "FileTypeNode.createSheet.fileExt.displayName"),
|
||||
NbBundle.getMessage(this.getClass(), "FileTypeNode.createSheet.fileExt.desc"),
|
||||
extensions));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Child node factory for a specific file type - does the database query.
|
||||
*/
|
||||
public static class FileTypeChildFactory extends ChildFactory.Detachable<Content> {
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
private final FileTypeExtensionFilters.SearchFilterInterface filter;
|
||||
private final static Logger logger = Logger.getLogger(FileTypeChildFactory.class.getName());
|
||||
private Observable notifier;
|
||||
|
||||
// use the constructor that gets an observable passed in for updates
|
||||
@Deprecated
|
||||
FileTypeChildFactory(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase) {
|
||||
super();
|
||||
this.filter = filter;
|
||||
this.skCase = skCase;
|
||||
notifier = null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param filter Extensions to display
|
||||
* @param skCase
|
||||
* @param o Observable that will notify when there could be new
|
||||
* data to display
|
||||
*/
|
||||
FileTypeChildFactory(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) {
|
||||
super();
|
||||
this.filter = filter;
|
||||
this.skCase = skCase;
|
||||
notifier = o;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
if (notifier != null) {
|
||||
notifier.addObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeNotify() {
|
||||
if (notifier != null) {
|
||||
notifier.deleteObserver(observer);
|
||||
}
|
||||
}
|
||||
private final Observer observer = new FileTypeChildFactoryObserver();
|
||||
|
||||
// Cause refresh of children if there are changes
|
||||
private class FileTypeChildFactoryObserver implements Observer {
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
refresh(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get children count without actually loading all nodes
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static long calculateItems(SleuthkitCase sleuthkitCase, FileTypeExtensionFilters.SearchFilterInterface filter) {
|
||||
try {
|
||||
return sleuthkitCase.countFilesWhere(createQuery(filter));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting file search view count", ex); //NON-NLS
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<Content> list) {
|
||||
try {
|
||||
List<AbstractFile> files = skCase.findAllFilesWhere(createQuery(filter));
|
||||
list.addAll(files);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String createQuery(FileTypeExtensionFilters.SearchFilterInterface filter) {
|
||||
StringBuilder query = new StringBuilder();
|
||||
query.append("(dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()).append(")"); //NON-NLS
|
||||
if (UserPreferences.hideKnownFilesInViewsTree()) {
|
||||
query.append(" AND (known IS NULL OR known != ").append(TskData.FileKnown.KNOWN.getFileKnownValue()).append(")"); //NON-NLS
|
||||
}
|
||||
query.append(" AND (NULL"); //NON-NLS
|
||||
for (String s : filter.getFilter()) {
|
||||
query.append(" OR LOWER(name) LIKE LOWER('%").append(s).append("')"); //NON-NLS
|
||||
}
|
||||
query.append(')');
|
||||
return query.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(Content key) {
|
||||
return key.accept(new ContentVisitor.Default<AbstractNode>() {
|
||||
@Override
|
||||
public FileNode visit(File f) {
|
||||
return new FileNode(f, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirectoryNode visit(Directory d) {
|
||||
return new DirectoryNode(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutFileNode visit(LayoutFile lf) {
|
||||
return new LayoutFileNode(lf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalFileNode visit(DerivedFile df) {
|
||||
return new LocalFileNode(df);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalFileNode visit(LocalFile lf) {
|
||||
return new LocalFileNode(lf);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractNode defaultVisit(Content di) {
|
||||
throw new UnsupportedOperationException(NbBundle.getMessage(this.getClass(), "FileTypeChildren.exception.notSupported.msg", di.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
102
Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java
Normal file
102
Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
|
||||
/**
|
||||
* File Types node support
|
||||
*/
|
||||
public final class FileTypes implements AutopsyVisitableItem {
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
|
||||
FileTypes(SleuthkitCase skCase) {
|
||||
this.skCase = skCase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
SleuthkitCase getSleuthkitCase() {
|
||||
return skCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Node which will contain By Mime Type and By Extension nodes.
|
||||
*/
|
||||
public static final class FileTypesNode extends DisplayableItemNode {
|
||||
|
||||
@NbBundle.Messages("FileTypes.name.text=File Types")
|
||||
private static final String NAME = Bundle.FileTypes_name_text();
|
||||
|
||||
FileTypesNode(SleuthkitCase sleuthkitCase) {
|
||||
super(new RootContentChildren(Arrays.asList(
|
||||
new FileTypesByExtension(sleuthkitCase),
|
||||
new FileTypesByMimeType(sleuthkitCase)
|
||||
)), Lookups.singleton(NAME));
|
||||
setName(NAME);
|
||||
setDisplayName(NAME);
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NbBundle.Messages({
|
||||
"FileTypes.createSheet.name.name=Name",
|
||||
"FileTypes.createSheet.name.displayName=Name",
|
||||
"FileTypes.createSheet.name.desc=no description"})
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||
if (ss == null) {
|
||||
ss = Sheet.createPropertiesSet();
|
||||
s.put(ss);
|
||||
}
|
||||
|
||||
ss.put(new NodeProperty<>(Bundle.FileTypes_createSheet_name_name(),
|
||||
Bundle.FileTypes_createSheet_name_displayName(),
|
||||
Bundle.FileTypes_createSheet_name_desc(),
|
||||
NAME
|
||||
));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,639 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.ContentVisitor;
|
||||
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.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* Filters database results by file extension.
|
||||
*/
|
||||
public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
|
||||
public FileTypesByExtension(SleuthkitCase skCase) {
|
||||
this.skCase = skCase;
|
||||
}
|
||||
|
||||
public SleuthkitCase getSleuthkitCase() {
|
||||
return this.skCase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for case and ingest invest. Updates observers when events are
|
||||
* fired. FileType and FileTypes nodes are all listening to this.
|
||||
*/
|
||||
private static class FileTypesByExtObservable extends Observable {
|
||||
|
||||
private FileTypesByExtObservable() {
|
||||
super();
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
deleteObservers();
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
}
|
||||
|
||||
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString()) || eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString()) || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked out.
|
||||
* Currently, remote events may be received for a case that is
|
||||
* already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
update();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||
if (evt.getNewValue() == null) {
|
||||
removeListeners();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void update() {
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Node for root of file types view. Children are nodes for specific types.
|
||||
*/
|
||||
static class FileTypesByExtNode extends DisplayableItemNode {
|
||||
|
||||
private static final String FNAME = NbBundle.getMessage(FileTypesByExtNode.class, "FileTypesByExtNode.fname.text");
|
||||
private final FileTypesByExtension.RootFilter filter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param skCase
|
||||
* @param filter null to display root node of file type tree, pass in
|
||||
* something to provide a sub-node.
|
||||
*/
|
||||
FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter) {
|
||||
super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, null), true), Lookups.singleton(filter == null ? FNAME : filter.getName()));
|
||||
this.filter = filter;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param skCase
|
||||
* @param filter
|
||||
* @param o Observable that was created by a higher-level node that
|
||||
* provides updates on events
|
||||
*/
|
||||
private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, Observable o) {
|
||||
super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, o), true), Lookups.singleton(filter == null ? FNAME : filter.getName()));
|
||||
this.filter = filter;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
// root node of tree
|
||||
if (filter == null) {
|
||||
super.setName(FNAME);
|
||||
super.setDisplayName(FNAME);
|
||||
} // sub-node in file tree (i.e. documents, exec, etc.)
|
||||
else {
|
||||
super.setName(filter.getName());
|
||||
super.setDisplayName(filter.getDisplayName());
|
||||
}
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||
if (ss == null) {
|
||||
ss = Sheet.createPropertiesSet();
|
||||
s.put(ss);
|
||||
}
|
||||
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.desc"), getName()));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
/**
|
||||
* Because Documents and Executable are further expandable, their
|
||||
* column order settings should be stored separately.
|
||||
*/
|
||||
if (filter == null) {
|
||||
return getClass().getName();
|
||||
}
|
||||
if (filter.equals(FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER) || filter.equals(FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER)) {
|
||||
return getClass().getName() + filter.getName();
|
||||
}
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
private static class FileTypesByExtNodeChildren extends ChildFactory<FileTypesByExtension.SearchFilterInterface> {
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
private final FileTypesByExtension.RootFilter filter;
|
||||
private final Observable notifier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param skCase
|
||||
* @param filter Is null for root node
|
||||
* @param o Observable that provides updates based on events
|
||||
* being fired (or null if one needs to be created)
|
||||
*/
|
||||
private FileTypesByExtNodeChildren(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, Observable o) {
|
||||
super();
|
||||
this.skCase = skCase;
|
||||
this.filter = filter;
|
||||
if (o == null) {
|
||||
this.notifier = new FileTypesByExtObservable();
|
||||
} else {
|
||||
this.notifier = o;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<FileTypesByExtension.SearchFilterInterface> list) {
|
||||
// root node
|
||||
if (filter == null) {
|
||||
list.addAll(Arrays.asList(FileTypesByExtension.RootFilter.values()));
|
||||
} // document and executable has another level of nodes
|
||||
else if (filter.equals(FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER)) {
|
||||
list.addAll(Arrays.asList(FileTypesByExtension.DocumentFilter.values()));
|
||||
} else if (filter.equals(FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER)) {
|
||||
list.addAll(Arrays.asList(FileTypesByExtension.ExecutableFilter.values()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(FileTypesByExtension.SearchFilterInterface key) {
|
||||
// make new nodes for the sub-nodes
|
||||
if (key.getName().equals(FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER.getName())) {
|
||||
return new FileTypesByExtNode(skCase, FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER, notifier);
|
||||
} else if (key.getName().equals(FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER.getName())) {
|
||||
return new FileTypesByExtNode(skCase, FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER, notifier);
|
||||
} else {
|
||||
return new FileExtensionNode(key, skCase, notifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Node for a specific file type / extension. Children of it will be the
|
||||
* files of that type.
|
||||
*/
|
||||
static class FileExtensionNode extends DisplayableItemNode {
|
||||
|
||||
FileTypesByExtension.SearchFilterInterface filter;
|
||||
SleuthkitCase skCase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param filter Extensions that will be shown for this node
|
||||
* @param skCase
|
||||
* @param o Observable that sends updates when the child factories
|
||||
* should refresh
|
||||
*/
|
||||
FileExtensionNode(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) {
|
||||
super(Children.create(new FileExtensionNodeChildren(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName()));
|
||||
this.filter = filter;
|
||||
this.skCase = skCase;
|
||||
init();
|
||||
o.addObserver(new ByExtNodeObserver());
|
||||
}
|
||||
|
||||
private void init() {
|
||||
super.setName(filter.getName());
|
||||
updateDisplayName();
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
|
||||
}
|
||||
|
||||
// update the display name when new events are fired
|
||||
private class ByExtNodeObserver implements Observer {
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
updateDisplayName();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDisplayName() {
|
||||
final long count = FileExtensionNodeChildren.calculateItems(skCase, filter);
|
||||
super.setDisplayName(filter.getDisplayName() + " (" + count + ")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||
if (ss == null) {
|
||||
ss = Sheet.createPropertiesSet();
|
||||
s.put(ss);
|
||||
}
|
||||
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.name"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.desc"), filter.getDisplayName()));
|
||||
String extensions = "";
|
||||
for (String ext : filter.getFilter()) {
|
||||
extensions += "'" + ext + "', ";
|
||||
}
|
||||
extensions = extensions.substring(0, extensions.lastIndexOf(','));
|
||||
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.name"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.desc"), extensions));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consider allowing different configurations for Images, Videos, etc
|
||||
* (in which case we'd return getClass().getName() + filter.getName()
|
||||
* for all filters).
|
||||
*/
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return DisplayableItemNode.FILE_PARENT_NODE_KEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Child node factory for a specific file type - does the database
|
||||
* query.
|
||||
*/
|
||||
private static class FileExtensionNodeChildren extends ChildFactory.Detachable<Content> {
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
private final FileTypesByExtension.SearchFilterInterface filter;
|
||||
private static final Logger LOGGER = Logger.getLogger(FileExtensionNodeChildren.class.getName());
|
||||
private final Observable notifier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param filter Extensions to display
|
||||
* @param skCase
|
||||
* @param o Observable that will notify when there could be new
|
||||
* data to display
|
||||
*/
|
||||
private FileExtensionNodeChildren(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) {
|
||||
super();
|
||||
this.filter = filter;
|
||||
this.skCase = skCase;
|
||||
notifier = o;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
if (notifier != null) {
|
||||
notifier.addObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeNotify() {
|
||||
if (notifier != null) {
|
||||
notifier.deleteObserver(observer);
|
||||
}
|
||||
}
|
||||
private final Observer observer = new FileTypeChildFactoryObserver();
|
||||
|
||||
// Cause refresh of children if there are changes
|
||||
private class FileTypeChildFactoryObserver implements Observer {
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
refresh(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get children count without actually loading all nodes
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static long calculateItems(SleuthkitCase sleuthkitCase, FileTypesByExtension.SearchFilterInterface filter) {
|
||||
try {
|
||||
return sleuthkitCase.countFilesWhere(createQuery(filter));
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error getting file search view count", ex); //NON-NLS
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<Content> list) {
|
||||
try {
|
||||
List<AbstractFile> files = skCase.findAllFilesWhere(createQuery(filter));
|
||||
list.addAll(files);
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String createQuery(FileTypesByExtension.SearchFilterInterface filter) {
|
||||
StringBuilder query = new StringBuilder();
|
||||
query.append("(dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()).append(")"); //NON-NLS
|
||||
if (UserPreferences.hideKnownFilesInViewsTree()) {
|
||||
query.append(" AND (known IS NULL OR known != ").append(TskData.FileKnown.KNOWN.getFileKnownValue()).append(")"); //NON-NLS
|
||||
}
|
||||
query.append(" AND (NULL"); //NON-NLS
|
||||
for (String s : filter.getFilter()) {
|
||||
query.append(" OR LOWER(name) LIKE LOWER('%").append(s).append("')"); //NON-NLS
|
||||
}
|
||||
query.append(')');
|
||||
return query.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(Content key) {
|
||||
return key.accept(new ContentVisitor.Default<AbstractNode>() {
|
||||
@Override
|
||||
public FileNode visit(File f) {
|
||||
return new FileNode(f, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirectoryNode visit(Directory d) {
|
||||
return new DirectoryNode(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutFileNode visit(LayoutFile lf) {
|
||||
return new LayoutFileNode(lf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalFileNode visit(DerivedFile df) {
|
||||
return new LocalFileNode(df);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalFileNode visit(LocalFile lf) {
|
||||
return new LocalFileNode(lf);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractNode defaultVisit(Content di) {
|
||||
throw new UnsupportedOperationException(NbBundle.getMessage(this.getClass(), "FileTypeChildren.exception.notSupported.msg", di.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// root node filters
|
||||
public static enum RootFilter implements AutopsyVisitableItem, SearchFilterInterface {
|
||||
|
||||
TSK_IMAGE_FILTER(0, "TSK_IMAGE_FILTER", //NON-NLS
|
||||
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskImgFilter.text"),
|
||||
FileTypeExtensions.getImageExtensions()),
|
||||
TSK_VIDEO_FILTER(1, "TSK_VIDEO_FILTER", //NON-NLS
|
||||
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskVideoFilter.text"),
|
||||
FileTypeExtensions.getVideoExtensions()),
|
||||
TSK_AUDIO_FILTER(2, "TSK_AUDIO_FILTER", //NON-NLS
|
||||
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskAudioFilter.text"),
|
||||
FileTypeExtensions.getAudioExtensions()),
|
||||
TSK_ARCHIVE_FILTER(3, "TSK_ARCHIVE_FILTER", //NON-NLS
|
||||
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskArchiveFilter.text"),
|
||||
FileTypeExtensions.getArchiveExtensions()),
|
||||
TSK_DOCUMENT_FILTER(3, "TSK_DOCUMENT_FILTER", //NON-NLS
|
||||
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDocumentFilter.text"),
|
||||
Arrays.asList(".doc", ".docx", ".pdf", ".xls", ".rtf", ".txt")), //NON-NLS
|
||||
TSK_EXECUTABLE_FILTER(3, "TSK_EXECUTABLE_FILTER", //NON-NLS
|
||||
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskExecFilter.text"),
|
||||
Arrays.asList(".exe", ".dll", ".bat", ".cmd", ".com")); //NON-NLS
|
||||
|
||||
private final int id;
|
||||
private final String name;
|
||||
private final String displayName;
|
||||
private final List<String> filter;
|
||||
|
||||
private RootFilter(int id, String name, String displayName, List<String> filter) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.displayName = displayName;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFilter() {
|
||||
return this.filter;
|
||||
}
|
||||
}
|
||||
|
||||
// document sub-node filters
|
||||
public static enum DocumentFilter implements AutopsyVisitableItem, SearchFilterInterface {
|
||||
|
||||
AUT_DOC_HTML(0, "AUT_DOC_HTML", //NON-NLS
|
||||
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocHtmlFilter.text"),
|
||||
Arrays.asList(".htm", ".html")), //NON-NLS
|
||||
AUT_DOC_OFFICE(1, "AUT_DOC_OFFICE", //NON-NLS
|
||||
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocOfficeFilter.text"),
|
||||
Arrays.asList(".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx")), //NON-NLS
|
||||
AUT_DOC_PDF(2, "AUT_DOC_PDF", //NON-NLS
|
||||
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autoDocPdfFilter.text"),
|
||||
Arrays.asList(".pdf")), //NON-NLS
|
||||
AUT_DOC_TXT(3, "AUT_DOC_TXT", //NON-NLS
|
||||
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocTxtFilter.text"),
|
||||
Arrays.asList(".txt")), //NON-NLS
|
||||
AUT_DOC_RTF(4, "AUT_DOC_RTF", //NON-NLS
|
||||
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocRtfFilter.text"),
|
||||
Arrays.asList(".rtf")); //NON-NLS
|
||||
|
||||
private final int id;
|
||||
private final String name;
|
||||
private final String displayName;
|
||||
private final List<String> filter;
|
||||
|
||||
private DocumentFilter(int id, String name, String displayName, List<String> filter) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.displayName = displayName;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFilter() {
|
||||
return this.filter;
|
||||
}
|
||||
}
|
||||
|
||||
// executable sub-node filters
|
||||
public static enum ExecutableFilter implements AutopsyVisitableItem, SearchFilterInterface {
|
||||
|
||||
ExecutableFilter_EXE(0, "ExecutableFilter_EXE", ".exe", Arrays.asList(".exe")), //NON-NLS
|
||||
ExecutableFilter_DLL(1, "ExecutableFilter_DLL", ".dll", Arrays.asList(".dll")), //NON-NLS
|
||||
ExecutableFilter_BAT(2, "ExecutableFilter_BAT", ".bat", Arrays.asList(".bat")), //NON-NLS
|
||||
ExecutableFilter_CMD(3, "ExecutableFilter_CMD", ".cmd", Arrays.asList(".cmd")), //NON-NLS
|
||||
ExecutableFilter_COM(4, "ExecutableFilter_COM", ".com", Arrays.asList(".com")); //NON-NLS
|
||||
|
||||
private final int id;
|
||||
private final String name;
|
||||
private final String displayName;
|
||||
private final List<String> filter;
|
||||
|
||||
private ExecutableFilter(int id, String name, String displayName, List<String> filter) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.displayName = displayName;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFilter() {
|
||||
return this.filter;
|
||||
}
|
||||
}
|
||||
|
||||
interface SearchFilterInterface {
|
||||
|
||||
public String getName();
|
||||
|
||||
public int getId();
|
||||
|
||||
public String getDisplayName();
|
||||
|
||||
public List<String> getFilter();
|
||||
}
|
||||
}
|
@ -0,0 +1,507 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.ContentVisitor;
|
||||
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.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* Class which contains the Nodes for the 'By Mime Type' view located in the
|
||||
* File Types view, shows all files with a mime type. Will initially be empty
|
||||
* until file type identification has been performed. Contains a Property Change
|
||||
* Listener which is checking for changes in IngestJobEvent Completed or
|
||||
* Cancelled and IngestModuleEvent Content Changed.
|
||||
*/
|
||||
public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem {
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
/**
|
||||
* The nodes of this tree will be determined dynamically by the mimetypes
|
||||
* which exist in the database. This hashmap will store them with the media
|
||||
* type as the key and a list of media subtypes as the value.
|
||||
*/
|
||||
private final HashMap<String, List<String>> existingMimeTypes = new HashMap<>();
|
||||
private static final Logger LOGGER = Logger.getLogger(FileTypesByMimeType.class.getName());
|
||||
|
||||
private void removeListeners() {
|
||||
deleteObservers();
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
}
|
||||
|
||||
/*
|
||||
* The pcl is in the class because it has the easiest mechanisms to add
|
||||
* and remove itself during its life cycles.
|
||||
*/
|
||||
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|
||||
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked out.
|
||||
* Currently, remote events may be received for a case that is
|
||||
* already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
populateHashMap();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
if (evt.getNewValue() == null) {
|
||||
removeListeners();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the media types by retrieving the keyset from the hashmap.
|
||||
*
|
||||
* @return mediaTypes - a list of strings representing all distinct media
|
||||
* types of files for this case
|
||||
*/
|
||||
private List<String> getMediaTypeList() {
|
||||
synchronized (existingMimeTypes) {
|
||||
List<String> mediaTypes = new ArrayList<>(existingMimeTypes.keySet());
|
||||
Collections.sort(mediaTypes);
|
||||
return mediaTypes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the query on the database to get all distinct MIME types of
|
||||
* files in it, and populate the hashmap with those results.
|
||||
*/
|
||||
private void populateHashMap() {
|
||||
StringBuilder allDistinctMimeTypesQuery = new StringBuilder();
|
||||
allDistinctMimeTypesQuery.append("SELECT DISTINCT mime_type from tsk_files where mime_type IS NOT null"); //NON-NLS
|
||||
allDistinctMimeTypesQuery.append(" AND dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()); //NON-NLS
|
||||
allDistinctMimeTypesQuery.append(" AND (type IN (").append(TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal()).append(","); //NON-NLS
|
||||
allDistinctMimeTypesQuery.append(TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal()).append(",");
|
||||
allDistinctMimeTypesQuery.append(TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal()).append(",");
|
||||
allDistinctMimeTypesQuery.append(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()).append("))");
|
||||
synchronized (existingMimeTypes) {
|
||||
existingMimeTypes.clear();
|
||||
|
||||
if (skCase == null) {
|
||||
|
||||
return;
|
||||
}
|
||||
try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(allDistinctMimeTypesQuery.toString())) {
|
||||
ResultSet resultSet = dbQuery.getResultSet();
|
||||
while (resultSet.next()) {
|
||||
final String mime_type = resultSet.getString("mime_type"); //NON-NLS
|
||||
if (!mime_type.isEmpty()) {
|
||||
String mimeType[] = mime_type.split("/");
|
||||
if (!mimeType[0].isEmpty() && !mimeType[1].isEmpty()) {
|
||||
if (!existingMimeTypes.containsKey(mimeType[0])) {
|
||||
existingMimeTypes.put(mimeType[0], new ArrayList<>());
|
||||
}
|
||||
existingMimeTypes.get(mimeType[0]).add(mimeType[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException | SQLException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to populate File Types by MIME Type tree view from DB: ", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
setChanged();
|
||||
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
FileTypesByMimeType(SleuthkitCase skCase) {
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
this.skCase = skCase;
|
||||
populateHashMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to check if the node in question is a ByMimeTypeNode which is
|
||||
* empty.
|
||||
*
|
||||
* @param node the Node which you wish to check.
|
||||
* @return True if originNode is an instance of ByMimeTypeNode and is empty,
|
||||
* false otherwise.
|
||||
*/
|
||||
public static boolean isEmptyMimeTypeNode(Node node) {
|
||||
boolean isEmptyMimeNode = false;
|
||||
if (node instanceof FileTypesByMimeType.ByMimeTypeNode && ((FileTypesByMimeType.ByMimeTypeNode) node).isEmpty()) {
|
||||
isEmptyMimeNode = true;
|
||||
}
|
||||
return isEmptyMimeNode;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Class which represents the root node of the "By MIME Type" tree, will
|
||||
* have children of each media type present in the database or no children
|
||||
* when the file detection module has not been run and MIME type is
|
||||
* currently unknown.
|
||||
*/
|
||||
class ByMimeTypeNode extends DisplayableItemNode {
|
||||
|
||||
@NbBundle.Messages("FileTypesByMimeType.name.text=By MIME Type")
|
||||
final String NAME = Bundle.FileTypesByMimeType_name_text();
|
||||
|
||||
ByMimeTypeNode() {
|
||||
super(Children.create(new ByMimeTypeNodeChildren(), true));
|
||||
super.setName(NAME);
|
||||
super.setDisplayName(NAME);
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return existingMimeTypes.isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the children for the "By MIME Type" node these children will each
|
||||
* represent a distinct media type present in the DB
|
||||
*/
|
||||
private class ByMimeTypeNodeChildren extends ChildFactory<String> implements Observer {
|
||||
|
||||
private ByMimeTypeNodeChildren() {
|
||||
super();
|
||||
addObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<String> mediaTypeNodes) {
|
||||
if (!existingMimeTypes.isEmpty()) {
|
||||
mediaTypeNodes.addAll(getMediaTypeList());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(String key) {
|
||||
return new MediaTypeNode(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
refresh(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The Media type node created by the ByMimeTypeNodeChildren and contains
|
||||
* one of the unique media types present in the database for this case.
|
||||
*/
|
||||
class MediaTypeNode extends DisplayableItemNode {
|
||||
|
||||
MediaTypeNode(String name) {
|
||||
super(Children.create(new MediaTypeNodeChildren(name), true));
|
||||
setName(name);
|
||||
setDisplayName(name);
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates children for media type nodes, children will be MediaSubTypeNodes
|
||||
* and represent one of the subtypes which are present in the database of
|
||||
* their media type.
|
||||
*/
|
||||
private class MediaTypeNodeChildren extends ChildFactory<String> implements Observer {
|
||||
|
||||
String mediaType;
|
||||
|
||||
MediaTypeNodeChildren(String name) {
|
||||
addObserver(this);
|
||||
this.mediaType = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<String> mediaTypeNodes) {
|
||||
mediaTypeNodes.addAll(existingMimeTypes.get(mediaType));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(String subtype) {
|
||||
String mimeType = mediaType + "/" + subtype;
|
||||
return new MediaSubTypeNode(mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
refresh(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Node which represents the media sub type in the By MIME type tree, the
|
||||
* media subtype is the portion of the MIME type following the /.
|
||||
*/
|
||||
class MediaSubTypeNode extends DisplayableItemNode implements Observer {
|
||||
|
||||
private MediaSubTypeNode(String mimeType) {
|
||||
super(Children.create(new MediaSubTypeNodeChildren(mimeType), true));
|
||||
addObserver(this);
|
||||
init(mimeType);
|
||||
}
|
||||
|
||||
private void init(String mimeType) {
|
||||
super.setName(mimeType);
|
||||
updateDisplayName(mimeType);
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the display name of the mediaSubTypeNode to include the count
|
||||
* of files which it represents.
|
||||
*
|
||||
* @param mimeType - the complete MimeType, needed for accurate query
|
||||
* results
|
||||
*/
|
||||
private void updateDisplayName(String mimeType) {
|
||||
|
||||
final long count = new MediaSubTypeNodeChildren(mimeType).calculateItems(skCase, mimeType);
|
||||
|
||||
super.setDisplayName(mimeType.split("/")[1] + " (" + count + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns true because any MediaSubTypeNode that exists is going
|
||||
* to be a bottom level node in the Tree view on the left of Autopsy.
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
updateDisplayName(getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for populating the contents of the Media Sub Type Node with the
|
||||
* files that match MimeType which is represented by this position in the
|
||||
* tree.
|
||||
*/
|
||||
private class MediaSubTypeNodeChildren extends ChildFactory.Detachable<Content> implements Observer {
|
||||
|
||||
private final String mimeType;
|
||||
|
||||
private MediaSubTypeNodeChildren(String mimeType) {
|
||||
super();
|
||||
addObserver(this);
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get children count without actually loading all nodes
|
||||
*
|
||||
* @return count(*) - the number of items that will be shown in this
|
||||
* items Directory Listing
|
||||
*/
|
||||
private long calculateItems(SleuthkitCase sleuthkitCase, String mime_type) {
|
||||
try {
|
||||
return sleuthkitCase.countFilesWhere(createQuery(mime_type));
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error getting file search view count", ex); //NON-NLS
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the createQuery method to complete the query, Select * from
|
||||
* tsk_files WHERE. The results from the database will contain the files
|
||||
* which match this mime type and their information.
|
||||
*
|
||||
* @param list - will contain all files and their attributes from the
|
||||
* tsk_files table where mime_type matches the one specified
|
||||
* @return true
|
||||
*/
|
||||
@Override
|
||||
protected boolean createKeys(List<Content> list) {
|
||||
try {
|
||||
List<AbstractFile> files = skCase.findAllFilesWhere(createQuery(mimeType));
|
||||
list.addAll(files);
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the portion of the query following WHERE for a query of the
|
||||
* database for each file which matches the complete MIME type
|
||||
* represented by this node. Matches against the mime_type column in
|
||||
* tsk_files.
|
||||
*
|
||||
* @param mimeType - the complete mimetype of the file mediatype/subtype
|
||||
* @return query.toString - portion of SQL query which will follow a
|
||||
* WHERE clause.
|
||||
*/
|
||||
private String createQuery(String mime_type) {
|
||||
StringBuilder query = new StringBuilder();
|
||||
query.append("(dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()).append(")"); //NON-NLS
|
||||
query.append(" AND (type IN (").append(TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal()).append(","); //NON-NLS
|
||||
query.append(TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal()).append(",");
|
||||
query.append(TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal()).append(",");
|
||||
query.append(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()).append("))");
|
||||
if (UserPreferences.hideKnownFilesInViewsTree()) {
|
||||
query.append(" AND (known IS NULL OR known != ").append(TskData.FileKnown.KNOWN.getFileKnownValue()).append(")"); //NON-NLS
|
||||
}
|
||||
query.append(" AND mime_type = '").append(mime_type).append("'"); //NON-NLS
|
||||
return query.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
refresh(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the content to populate the Directory Listing Table view for
|
||||
* each file
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected Node createNodeForKey(Content key) {
|
||||
return key.accept(new ContentVisitor.Default<AbstractNode>() {
|
||||
@Override
|
||||
public FileNode visit(File f) {
|
||||
return new FileNode(f, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirectoryNode visit(Directory d) {
|
||||
return new DirectoryNode(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutFileNode visit(LayoutFile lf) {
|
||||
return new LayoutFileNode(lf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalFileNode visit(DerivedFile df) {
|
||||
return new LocalFileNode(df);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalFileNode visit(LocalFile lf) {
|
||||
return new LocalFileNode(lf);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractNode defaultVisit(Content di) {
|
||||
throw new UnsupportedOperationException(NbBundle.getMessage(this.getClass(), "FileTypeChildren.exception.notSupported.msg", di.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,233 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2015 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.FileTypeExtensionFilters;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
|
||||
/**
|
||||
* Node for root of file types view. Children are nodes for specific types.
|
||||
*/
|
||||
public class FileTypesNode extends DisplayableItemNode {
|
||||
|
||||
private static final String FNAME = NbBundle.getMessage(FileTypesNode.class, "FileTypesNode.fname.text");
|
||||
private final FileTypeExtensionFilters.RootFilter filter;
|
||||
/**
|
||||
*
|
||||
* @param skCase
|
||||
* @param filter null to display root node of file type tree, pass in
|
||||
* something to provide a sub-node.
|
||||
*/
|
||||
FileTypesNode(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter) {
|
||||
super(Children.create(new FileTypesChildren(skCase, filter, null), true), Lookups.singleton(filter == null ? FNAME : filter.getName()));
|
||||
this.filter = filter;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param skCase
|
||||
* @param filter
|
||||
* @param o Observable that was created by a higher-level node that
|
||||
* provides updates on events
|
||||
*/
|
||||
private FileTypesNode(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter, Observable o) {
|
||||
super(Children.create(new FileTypesChildren(skCase, filter, o), true), Lookups.singleton(filter == null ? FNAME : filter.getName()));
|
||||
this.filter = filter;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
// root node of tree
|
||||
if (filter == null) {
|
||||
super.setName(FNAME);
|
||||
super.setDisplayName(FNAME);
|
||||
} // sub-node in file tree (i.e. documents, exec, etc.)
|
||||
else {
|
||||
super.setName(filter.getName());
|
||||
super.setDisplayName(filter.getDisplayName());
|
||||
}
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||
if (ss == null) {
|
||||
ss = Sheet.createPropertiesSet();
|
||||
s.put(ss);
|
||||
}
|
||||
|
||||
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesNode.createSheet.name.name"),
|
||||
NbBundle.getMessage(this.getClass(), "FileTypesNode.createSheet.name.displayName"),
|
||||
NbBundle.getMessage(this.getClass(), "FileTypesNode.createSheet.name.desc"),
|
||||
getName()));
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// if(filter == null)
|
||||
// return "FileTypes"; //NON-NLS
|
||||
// if (filter.equals(FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER))
|
||||
// return "FileTypesDoc"; //NON-NLS
|
||||
// if (filter.equals(FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER))
|
||||
// return "FileTypesExe"; //NON-NLS
|
||||
// return "FileTypes"; //NON-NLS
|
||||
// }
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static class FileTypesChildren extends ChildFactory<FileTypeExtensionFilters.SearchFilterInterface> {
|
||||
|
||||
private SleuthkitCase skCase;
|
||||
private FileTypeExtensionFilters.RootFilter filter;
|
||||
private Observable notifier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param skCase
|
||||
* @param filter Is null for root node
|
||||
* @param o Observable that provides updates based on events being
|
||||
* fired (or null if one needs to be created)
|
||||
*/
|
||||
public FileTypesChildren(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter, Observable o) {
|
||||
super();
|
||||
this.skCase = skCase;
|
||||
this.filter = filter;
|
||||
if (o == null) {
|
||||
this.notifier = new FileTypesChildrenObservable();
|
||||
} else {
|
||||
this.notifier = o;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for case and ingest invest. Updates observers when events are
|
||||
* fired. FileType and FileTypes nodes are all listening to this.
|
||||
*/
|
||||
private final class FileTypesChildrenObservable extends Observable {
|
||||
|
||||
FileTypesChildrenObservable() {
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
deleteObservers();
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
}
|
||||
|
||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|
||||
|| eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure
|
||||
* until a different way of handling the closing of
|
||||
* cases is worked out. Currently, remote events may be
|
||||
* received for a case that is already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
update();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||
if (evt.getNewValue() == null) {
|
||||
removeListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void update() {
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<FileTypeExtensionFilters.SearchFilterInterface> list) {
|
||||
// root node
|
||||
if (filter == null) {
|
||||
list.addAll(Arrays.asList(FileTypeExtensionFilters.RootFilter.values()));
|
||||
} // document and executable has another level of nodes
|
||||
else if (filter.equals(FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER)) {
|
||||
list.addAll(Arrays.asList(FileTypeExtensionFilters.DocumentFilter.values()));
|
||||
} else if (filter.equals(FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER)) {
|
||||
list.addAll(Arrays.asList(FileTypeExtensionFilters.ExecutableFilter.values()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(FileTypeExtensionFilters.SearchFilterInterface key) {
|
||||
// make new nodes for the sub-nodes
|
||||
if (key.getName().equals(FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER.getName())) {
|
||||
return new FileTypesNode(skCase, FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER, notifier);
|
||||
} else if (key.getName().equals(FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER.getName())) {
|
||||
return new FileTypesNode(skCase, FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER, notifier);
|
||||
} else {
|
||||
return new FileTypeNode(key, skCase, notifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -178,15 +178,10 @@ public class HashsetHits implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "HashsetRoot"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -341,15 +336,14 @@ public class HashsetHits implements AutopsyVisitableItem {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "HashsetName"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
/**
|
||||
* For custom settings for each hash set, return
|
||||
* getClass().getName() + hashSetName instead.
|
||||
*/
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -195,13 +195,8 @@ public class ImageNode extends AbstractContentNode<Image> {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "Image"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
@ -172,15 +172,10 @@ public class InterestingHits implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "InterestingHitsRoot"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
private class SetNameFactory extends ChildFactory.Detachable<String> implements Observer {
|
||||
@ -328,15 +323,14 @@ public class InterestingHits implements AutopsyVisitableItem {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "InterestingHitsSetName"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
/**
|
||||
* For custom settings for each rule set, return
|
||||
* getClass().getName() + setName instead.
|
||||
*/
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
private class HitFactory extends ChildFactory<Long> implements Observer {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2015 Basis Technology Corp.
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -248,15 +248,10 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "KeywordRoot"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
private class ListFactory extends ChildFactory.Detachable<String> implements Observer {
|
||||
@ -351,7 +346,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
|
||||
public class ListNode extends DisplayableItemNode implements Observer {
|
||||
|
||||
private String listName;
|
||||
private final String listName;
|
||||
|
||||
public ListNode(String listName) {
|
||||
super(Children.create(new TermFactory(listName), true), Lookups.singleton(listName));
|
||||
@ -408,20 +403,15 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "KeywordList"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
private class TermFactory extends ChildFactory.Detachable<String> implements Observer {
|
||||
|
||||
private String setName;
|
||||
private final String setName;
|
||||
|
||||
private TermFactory(String setName) {
|
||||
super();
|
||||
@ -457,8 +447,8 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
|
||||
public class TermNode extends DisplayableItemNode implements Observer {
|
||||
|
||||
private String setName;
|
||||
private String keyword;
|
||||
private final String setName;
|
||||
private final String keyword;
|
||||
|
||||
public TermNode(String setName, String keyword) {
|
||||
super(Children.create(new HitsFactory(setName, keyword), true), Lookups.singleton(keyword));
|
||||
@ -511,21 +501,16 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "KeywordTerm"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
public class HitsFactory extends ChildFactory.Detachable<Long> implements Observer {
|
||||
|
||||
private String keyword;
|
||||
private String setName;
|
||||
private final String keyword;
|
||||
private final String setName;
|
||||
|
||||
public HitsFactory(String setName, String keyword) {
|
||||
super();
|
||||
|
@ -46,7 +46,7 @@ public class KnownFileFilterNode extends FilterNode {
|
||||
@Override
|
||||
public void preferenceChange(PreferenceChangeEvent evt) {
|
||||
switch (evt.getKey()) {
|
||||
case UserPreferences.HIDE_KNOWN_FILES_IN_DATA_SOURCES_TREE:
|
||||
case UserPreferences.HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE:
|
||||
filterFromDataSources = UserPreferences.hideKnownFilesInDataSourcesTree();
|
||||
break;
|
||||
case UserPreferences.HIDE_KNOWN_FILES_IN_VIEWS_TREE:
|
||||
|
@ -38,15 +38,6 @@ import org.sleuthkit.datamodel.TskData;
|
||||
*/
|
||||
public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "LayoutFile"; //NON-NLS
|
||||
// }
|
||||
public static enum LayoutContentPropertyType {
|
||||
|
||||
PARTS {
|
||||
@ -95,6 +86,9 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
||||
ss.put(new NodeProperty<>(entry.getKey(), entry.getKey(), NO_DESCR, entry.getValue()));
|
||||
}
|
||||
|
||||
// add tags property to the sheet
|
||||
addTagProperty(ss);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -135,4 +129,10 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
||||
AbstractAbstractFileNode.fillPropertyMap(map, content);
|
||||
map.put(LayoutContentPropertyType.PARTS.toString(), content.getNumParts());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2014 Basis Technology Corp.
|
||||
* Copyright 2013-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -19,6 +19,7 @@
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -74,7 +75,9 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
ss.put(new NodeProperty<>(entry.getKey(), entry.getKey(), NO_DESCR, entry.getValue()));
|
||||
}
|
||||
// @@@ add more properties here...
|
||||
|
||||
// add tags property to the sheet
|
||||
addTagProperty(ss);
|
||||
|
||||
return s;
|
||||
}
|
||||
@ -82,9 +85,7 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
||||
@Override
|
||||
public Action[] getActions(boolean context) {
|
||||
List<Action> actionsList = new ArrayList<>();
|
||||
for (Action a : super.getActions(true)) {
|
||||
actionsList.add(a);
|
||||
}
|
||||
actionsList.addAll(Arrays.asList(super.getActions(true)));
|
||||
actionsList.add(new ViewContextAction(NbBundle.getMessage(this.getClass(), "LocalFileNode.viewFileInDir.text"), this.content));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(new NewWindowViewAction(
|
||||
@ -119,13 +120,8 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
||||
return true; //!this.hasContentChildren();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "LocalFile"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel.accounts;
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.datamodel.AutopsyVisitableItem;
|
||||
import org.sleuthkit.autopsy.datamodel.AutopsyItemVisitor;
|
@ -18,7 +18,6 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.RecentFiles;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
|
@ -28,7 +28,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.RecentFiles.RecentFilesFilter;
|
||||
import org.sleuthkit.autopsy.datamodel.RecentFiles.RecentFilesFilter;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.ContentVisitor;
|
||||
|
@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.RecentFiles.RecentFilesFilter;
|
||||
import org.sleuthkit.autopsy.datamodel.RecentFiles.RecentFilesFilter;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
|
||||
/**
|
||||
@ -83,13 +83,12 @@ public class RecentFilesFilterNode extends DisplayableItemNode {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "RecentFilesFilter"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
if (filter == null) {
|
||||
return getClass().getName();
|
||||
} else {
|
||||
return getClass().getName() + filter.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,13 +66,8 @@ public class RecentFilesNode extends DisplayableItemNode {
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "RecentFiles"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.datamodel.Report;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
@ -90,15 +91,10 @@ public final class Reports implements AutopsyVisitableItem {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "ReportsList"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -218,15 +214,11 @@ public final class Reports implements AutopsyVisitableItem {
|
||||
return new OpenReportAction();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "Reports"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
private static class DeleteReportAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@ -292,30 +284,16 @@ public final class Reports implements AutopsyVisitableItem {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
File file = new File(ReportNode.this.report.getPath());
|
||||
try {
|
||||
Desktop.getDesktop().open(file);
|
||||
} catch (IOException ex) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.NoAssociatedEditorMessage"),
|
||||
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MessageBoxTitle"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.NoOpenInEditorSupportMessage"),
|
||||
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MessageBoxTitle"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MissingReportFileMessage"),
|
||||
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MessageBoxTitle"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (SecurityException ex) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.ReportFileOpenPermissionDeniedMessage"),
|
||||
NbBundle.getMessage(OpenReportAction.class, "OpenReportAction.actionPerformed.MessageBoxTitle"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
String reportPath = ReportNode.this.report.getPath();
|
||||
String extension = "";
|
||||
int extPosition = reportPath.lastIndexOf('.');
|
||||
|
||||
if (extPosition != -1) {
|
||||
extension = reportPath.substring(extPosition, reportPath.length()).toLowerCase();
|
||||
}
|
||||
|
||||
File file = new File(reportPath);
|
||||
ExternalViewerAction.openFile("", extension, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ public class ResultsNode extends DisplayableItemNode {
|
||||
@NbBundle.Messages("ResultsNode.name.text=Results")
|
||||
public static final String NAME = Bundle.ResultsNode_name_text();
|
||||
|
||||
|
||||
|
||||
public ResultsNode(SleuthkitCase sleuthkitCase) {
|
||||
super(new RootContentChildren(Arrays.asList(
|
||||
new ExtractedContent(sleuthkitCase),
|
||||
@ -78,13 +80,8 @@ public class ResultsNode extends DisplayableItemNode {
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "Results"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2014 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.util.prefs.PreferenceChangeEvent;
|
||||
import java.util.prefs.PreferenceChangeListener;
|
||||
import org.openide.nodes.FilterNode;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* A Filter Node responsible for conditionally filtering out Nodes that
|
||||
* represent slack files.
|
||||
*
|
||||
* Filters known files IF the option to Filter Slack files for the given
|
||||
* SelectionContext is set. Otherwise, does nothing.
|
||||
*
|
||||
*/
|
||||
public class SlackFileFilterNode extends FilterNode {
|
||||
|
||||
private static boolean filterFromDataSources = UserPreferences.hideSlackFilesInDataSourcesTree();
|
||||
private static boolean filterFromViews = UserPreferences.hideSlackFilesInViewsTree();
|
||||
|
||||
static {
|
||||
UserPreferences.addChangeListener(new PreferenceChangeListener() {
|
||||
@Override
|
||||
public void preferenceChange(PreferenceChangeEvent evt) {
|
||||
switch (evt.getKey()) {
|
||||
case UserPreferences.HIDE_SLACK_FILES_IN_DATA_SRCS_TREE:
|
||||
filterFromDataSources = UserPreferences.hideSlackFilesInDataSourcesTree();
|
||||
break;
|
||||
case UserPreferences.HIDE_SLACK_FILES_IN_VIEWS_TREE:
|
||||
filterFromViews = UserPreferences.hideSlackFilesInViewsTree();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public enum SelectionContext {
|
||||
|
||||
DATA_SOURCES(NbBundle.getMessage(SlackFileFilterNode.class, "SlackFileFilterNode.selectionContext.dataSources")),
|
||||
VIEWS(NbBundle.getMessage(SlackFileFilterNode.class, "SlackFileFilterNode.selectionContext.views")),
|
||||
OTHER(""); // Subnode of another node.
|
||||
|
||||
private final String displayName;
|
||||
|
||||
SelectionContext(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public static SelectionContext getContextFromName(String name) {
|
||||
if (name.equals(DATA_SOURCES.getName())) {
|
||||
return DATA_SOURCES;
|
||||
} else if (name.equals(VIEWS.getName())) {
|
||||
return VIEWS;
|
||||
} else {
|
||||
return OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
private String getName() {
|
||||
return displayName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SlackFileFilterNode from the given Node. Note that the Node
|
||||
* should be from the directory tree.
|
||||
*
|
||||
* @param arg
|
||||
* @param context
|
||||
*/
|
||||
public SlackFileFilterNode(Node arg, SelectionContext context) {
|
||||
super(arg, new SlackFileFilterChildren(arg, context));
|
||||
}
|
||||
|
||||
private SlackFileFilterNode(Node arg, boolean filter) {
|
||||
super(arg, new SlackFileFilterChildren(arg, filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the selection context of a Node in the DirectoryTree.
|
||||
*
|
||||
* @param n
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static SelectionContext getSelectionContext(Node n) {
|
||||
if (n == null || n.getParentNode() == null) {
|
||||
// Parent of root node or root node. Occurs during case open / close.
|
||||
return SelectionContext.OTHER;
|
||||
} else if (n.getParentNode().getParentNode() == null) {
|
||||
// One level below root node. Should be one of DataSources, Views, or Results
|
||||
return SelectionContext.getContextFromName(n.getDisplayName());
|
||||
} else {
|
||||
return getSelectionContext(n.getParentNode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complementary class to SlackFileFilterNode.
|
||||
*
|
||||
* Filters out children Nodes that represent slack files. Otherwise, returns
|
||||
* the original node wrapped in another instance of the SlackFileFilterNode.
|
||||
*
|
||||
* @author jwallace
|
||||
*/
|
||||
private static class SlackFileFilterChildren extends FilterNode.Children {
|
||||
|
||||
/**
|
||||
* True if this SlackFileFilterChildren should filter out slack files.
|
||||
*/
|
||||
private boolean filter;
|
||||
|
||||
/**
|
||||
* Constructor used when the context has already been determined.
|
||||
*
|
||||
* @param arg
|
||||
* @param filter
|
||||
*/
|
||||
private SlackFileFilterChildren(Node arg, boolean filter) {
|
||||
super(arg);
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor used when the context has not been determined.
|
||||
*
|
||||
* @param arg
|
||||
* @param context
|
||||
*/
|
||||
private SlackFileFilterChildren(Node arg, SlackFileFilterNode.SelectionContext context) {
|
||||
super(arg);
|
||||
|
||||
switch (context) {
|
||||
case DATA_SOURCES:
|
||||
filter = filterFromDataSources;
|
||||
break;
|
||||
case VIEWS:
|
||||
filter = filterFromViews;
|
||||
break;
|
||||
default:
|
||||
filter = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node[] createNodes(Node arg) {
|
||||
if (filter) {
|
||||
// Filter out child nodes that represent slack files
|
||||
AbstractFile file = arg.getLookup().lookup(AbstractFile.class);
|
||||
if ((file != null) && file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)) {
|
||||
return new Node[]{};
|
||||
}
|
||||
}
|
||||
return new Node[]{new SlackFileFilterNode(arg, filter)};
|
||||
}
|
||||
}
|
||||
}
|
120
Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java
Normal file
120
Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
||||
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
||||
|
||||
/**
|
||||
* This class is the Node for an AbstractFile. It may have derived files
|
||||
* children.
|
||||
*/
|
||||
public class SlackFileNode extends AbstractFsContentNode<AbstractFile> {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param file underlying Content
|
||||
*/
|
||||
public SlackFileNode(AbstractFile file) {
|
||||
this(file, true);
|
||||
|
||||
setIcon(file);
|
||||
}
|
||||
|
||||
public SlackFileNode(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"); //NON-NLS
|
||||
} else {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
|
||||
}
|
||||
} else {
|
||||
this.setIconBaseWithExtension(getIconForFileType(file));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action[] getActions(boolean popup) {
|
||||
List<Action> actionsList = new ArrayList<>();
|
||||
for (Action a : super.getActions(true)) {
|
||||
actionsList.add(a);
|
||||
}
|
||||
|
||||
if (!this.getDirectoryBrowseMode()) {
|
||||
actionsList.add(new ViewContextAction(NbBundle.getMessage(this.getClass(), "SlackFileNode.viewFileInDir.text"), this.content));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
}
|
||||
actionsList.add(new NewWindowViewAction(
|
||||
NbBundle.getMessage(this.getClass(), "SlackFileNode.getActions.viewInNewWin.text"), this));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(ExtractAction.getInstance());
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(AddContentTagAction.getInstance());
|
||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actionsList.toArray(new Action[actionsList.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(ContentNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
// Given a file, returns the correct icon for said
|
||||
// file based off it's extension
|
||||
static String getIconForFileType(AbstractFile file) {
|
||||
|
||||
return "org/sleuthkit/autopsy/images/file-icon.png"; //NON-NLS
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
// This seems wrong, but it also seems that it is never called
|
||||
// because the visitor to figure out if there are children or
|
||||
// not will check if it has children using the Content API
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2015 Basis Technology Corp.
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -46,8 +46,8 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
* factory built on top of the NetBeans Children.Keys class.
|
||||
*/
|
||||
public class Tags implements AutopsyVisitableItem {
|
||||
// Creation of a RootNode object corresponding to a Tags object is done
|
||||
// by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren
|
||||
// Creation of a RootNode object corresponding to a Tags object is done
|
||||
// by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren
|
||||
// override of Children.Keys<T>.createNodes().
|
||||
|
||||
private final TagResults tagResults = new TagResults();
|
||||
@ -105,19 +105,15 @@ public class Tags implements AutopsyVisitableItem {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
propertySheet.put(properties);
|
||||
}
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "TagsNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "TagsNode.createSheet.name.displayName"), "", getName()));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "TagsNode.createSheet.name.name"),
|
||||
NbBundle.getMessage(this.getClass(), "TagsNode.createSheet.name.displayName"), "", getName()));
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "TagsRoots"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
private class TagNameNodeFactory extends ChildFactory.Detachable<TagName> implements Observer {
|
||||
@ -255,7 +251,8 @@ public class Tags implements AutopsyVisitableItem {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
propertySheet.put(properties);
|
||||
}
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "TagNameNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "TagNameNode.createSheet.name.displayName"), tagName.getDescription(), getName()));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "TagNameNode.createSheet.name.name"),
|
||||
NbBundle.getMessage(this.getClass(), "TagNameNode.createSheet.name.displayName"), tagName.getDescription(), getName()));
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
@ -276,15 +273,10 @@ public class Tags implements AutopsyVisitableItem {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "TagsName"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -333,7 +325,7 @@ public class Tags implements AutopsyVisitableItem {
|
||||
public class ContentTagTypeNode extends DisplayableItemNode implements Observer {
|
||||
|
||||
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
|
||||
private TagName tagName;
|
||||
private final TagName tagName;
|
||||
|
||||
public ContentTagTypeNode(TagName tagName) {
|
||||
super(Children.create(new ContentTagNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " " + CONTENT_DISPLAY_NAME));
|
||||
@ -362,7 +354,8 @@ public class Tags implements AutopsyVisitableItem {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
propertySheet.put(properties);
|
||||
}
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagTypeNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "ContentTagTypeNode.createSheet.name.displayName"), "", getName()));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagTypeNode.createSheet.name.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagTypeNode.createSheet.name.displayName"), "", getName()));
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
@ -381,15 +374,10 @@ public class Tags implements AutopsyVisitableItem {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "TagsContentType"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
private class ContentTagNodeFactory extends ChildFactory<ContentTag> implements Observer {
|
||||
@ -435,7 +423,7 @@ public class Tags implements AutopsyVisitableItem {
|
||||
*/
|
||||
public class BlackboardArtifactTagTypeNode extends DisplayableItemNode implements Observer {
|
||||
|
||||
private TagName tagName;
|
||||
private final TagName tagName;
|
||||
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
|
||||
|
||||
public BlackboardArtifactTagTypeNode(TagName tagName) {
|
||||
@ -465,7 +453,8 @@ public class Tags implements AutopsyVisitableItem {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
propertySheet.put(properties);
|
||||
}
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagTypeNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagTypeNode.createSheet.name.displayName"), "", getName()));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagTypeNode.createSheet.name.name"),
|
||||
NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagTypeNode.createSheet.name.displayName"), "", getName()));
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
@ -484,15 +473,10 @@ public class Tags implements AutopsyVisitableItem {
|
||||
updateDisplayName();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "TagsBlackboardArtifact"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
private class BlackboardArtifactTagNodeFactory extends ChildFactory<BlackboardArtifactTag> implements Observer {
|
||||
@ -521,7 +505,7 @@ public class Tags implements AutopsyVisitableItem {
|
||||
// The blackboard artifact tags to be wrapped are used as the keys.
|
||||
return new BlackboardArtifactTagNode(key);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
refresh(true);
|
||||
|
@ -18,7 +18,6 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.datamodel.accounts.FileTypeExtensionFilters;
|
||||
import java.util.Arrays;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
@ -36,7 +35,7 @@ public class ViewsNode extends DisplayableItemNode {
|
||||
|
||||
public ViewsNode(SleuthkitCase sleuthkitCase) {
|
||||
super(new RootContentChildren(Arrays.asList(
|
||||
new FileTypeExtensionFilters(sleuthkitCase),
|
||||
new FileTypes(sleuthkitCase),
|
||||
// June '15: Recent Files was removed because it was not useful w/out filtering
|
||||
// add it back in if we can filter the results to a more managable size.
|
||||
// new RecentFiles(sleuthkitCase),
|
||||
@ -74,13 +73,8 @@ public class ViewsNode extends DisplayableItemNode {
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "Views"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
@ -148,6 +148,7 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
ss.put(new NodeProperty<>(entry.getKey(), entry.getKey(), NO_DESCR, entry.getValue()));
|
||||
}
|
||||
addTagProperty(ss);
|
||||
} else {
|
||||
ss.put(new NodeProperty<>(Bundle.VirtualDirectoryNode_createSheet_type_name(),
|
||||
Bundle.VirtualDirectoryNode_createSheet_type_displayName(),
|
||||
@ -224,13 +225,9 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "VirtualDirectory"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
// use content.isDataSource if different column settings are desired
|
||||
return DisplayableItemNode.FILE_PARENT_NODE_KEY;
|
||||
}
|
||||
}
|
||||
|
@ -194,13 +194,8 @@ public class VolumeNode extends AbstractContentNode<Volume> {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column reordering code
|
||||
*
|
||||
* Added to support this feature.
|
||||
*/
|
||||
// @Override
|
||||
// public String getItemType() {
|
||||
// return "Volume"; //NON-NLS
|
||||
// }
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return DisplayableItemNode.FILE_PARENT_NODE_KEY;
|
||||
}
|
||||
}
|
||||
|
@ -147,6 +147,14 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
*/
|
||||
private abstract class ObservingChildren<X> extends Children.Keys<X> {
|
||||
|
||||
/**
|
||||
* Override of default constructor to force lazy creation of nodes, by
|
||||
* concrete instances of ObservingChildren
|
||||
*/
|
||||
ObservingChildren() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create of keys used by this Children object to represent the child
|
||||
* nodes.
|
||||
@ -335,6 +343,11 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -412,6 +425,11 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -479,6 +497,11 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -612,6 +635,11 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
|
||||
updateDisplayName();
|
||||
@ -737,6 +765,11 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
|
||||
updateDisplayName();
|
||||
@ -921,6 +954,11 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NbBundle.Messages({
|
||||
"Accounts.FileWithCCNNode.nameProperty.displayName=File",
|
||||
@ -1036,8 +1074,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
|
||||
private BINNode(BinResult bin) {
|
||||
super(Children.LEAF);
|
||||
setChildren(Children.createLazy(CreditCardNumberFactory::new));
|
||||
this.bin = bin;
|
||||
setChildren(Children.createLazy(CreditCardNumberFactory::new));
|
||||
setName(getBinRangeString());
|
||||
updateDisplayName();
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/bank.png"); //NON-NLS
|
||||
@ -1093,6 +1131,11 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
private Sheet.Set getPropertySet(Sheet s) {
|
||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||
if (ss == null) {
|
||||
@ -1356,18 +1399,27 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
*/
|
||||
if (newStatus == BlackboardArtifact.ReviewStatus.REJECTED && showRejected == false) {
|
||||
List<Node> siblings = Arrays.asList(node.getParentNode().getChildren().getNodes());
|
||||
int indexOf = siblings.indexOf(node);
|
||||
//there is no previous for the first node, so instead we select the next one
|
||||
Node sibling = indexOf > 0
|
||||
? siblings.get(indexOf - 1)
|
||||
: siblings.get(indexOf + 1);
|
||||
createPath = NodeOp.createPath(sibling, null);
|
||||
if (siblings.size() > 1) {
|
||||
int indexOf = siblings.indexOf(node);
|
||||
//there is no previous for the first node, so instead we select the next one
|
||||
Node sibling = indexOf > 0
|
||||
? siblings.get(indexOf - 1)
|
||||
: siblings.get(Integer.max(indexOf + 1, siblings.size() - 1));
|
||||
createPath = NodeOp.createPath(sibling, null);
|
||||
} else {
|
||||
/* if there are no other siblings to select,
|
||||
* just return null, but note we need to filter
|
||||
* this out of stream below */
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
createPath = NodeOp.createPath(node, null);
|
||||
}
|
||||
//for the reselect to work we need to strip off the first part of the path.
|
||||
return Arrays.copyOfRange(createPath, 1, createPath.length);
|
||||
}).collect(Collectors.toList());
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
//change status of selected artifacts
|
||||
final Collection<? extends BlackboardArtifact> artifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
|
||||
|
@ -1,12 +0,0 @@
|
||||
FileTypeExtensionFilters.tskImgFilter.text=Images
|
||||
FileTypeExtensionFilters.tskVideoFilter.text=Videos
|
||||
FileTypeExtensionFilters.tskAudioFilter.text=Audio
|
||||
FileTypeExtensionFilters.tskArchiveFilter.text=Archives
|
||||
FileTypeExtensionFilters.tskDocumentFilter.text=Documents
|
||||
FileTypeExtensionFilters.tskExecFilter.text=Executable
|
||||
FileTypeExtensionFilters.autDocHtmlFilter.text=HTML
|
||||
FileTypeExtensionFilters.autDocOfficeFilter.text=Office
|
||||
FileTypeExtensionFilters.autoDocPdfFilter.text=PDF
|
||||
FileTypeExtensionFilters.autDocTxtFilter.text=Plain Text
|
||||
FileTypeExtensionFilters.autDocRtfFilter.text=Rich Text
|
||||
|
@ -1,223 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel.accounts;
|
||||
|
||||
import org.sleuthkit.autopsy.datamodel.AutopsyItemVisitor;
|
||||
import org.sleuthkit.autopsy.datamodel.AutopsyVisitableItem;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypeExtensions;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
|
||||
/**
|
||||
* Filters database results by file extension.
|
||||
*/
|
||||
public class FileTypeExtensionFilters implements AutopsyVisitableItem {
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
|
||||
// root node filters
|
||||
public enum RootFilter implements AutopsyVisitableItem, SearchFilterInterface {
|
||||
|
||||
TSK_IMAGE_FILTER(0, "TSK_IMAGE_FILTER", //NON-NLS
|
||||
NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.tskImgFilter.text"),
|
||||
FileTypeExtensions.getImageExtensions()),
|
||||
TSK_VIDEO_FILTER(1, "TSK_VIDEO_FILTER", //NON-NLS
|
||||
NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.tskVideoFilter.text"),
|
||||
FileTypeExtensions.getVideoExtensions()),
|
||||
TSK_AUDIO_FILTER(2, "TSK_AUDIO_FILTER", //NON-NLS
|
||||
NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.tskAudioFilter.text"),
|
||||
FileTypeExtensions.getAudioExtensions()),
|
||||
TSK_ARCHIVE_FILTER(3, "TSK_ARCHIVE_FILTER", //NON-NLS
|
||||
NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.tskArchiveFilter.text"),
|
||||
FileTypeExtensions.getArchiveExtensions()),
|
||||
TSK_DOCUMENT_FILTER(3, "TSK_DOCUMENT_FILTER", //NON-NLS
|
||||
NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.tskDocumentFilter.text"),
|
||||
Arrays.asList(".doc", ".docx", ".pdf", ".xls", ".rtf", ".txt")), //NON-NLS
|
||||
TSK_EXECUTABLE_FILTER(3, "TSK_EXECUTABLE_FILTER", //NON-NLS
|
||||
NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.tskExecFilter.text"),
|
||||
Arrays.asList(".exe", ".dll", ".bat", ".cmd", ".com")); //NON-NLS
|
||||
|
||||
private final int id;
|
||||
private final String name;
|
||||
private final String displayName;
|
||||
private final List<String> filter;
|
||||
|
||||
private RootFilter(int id, String name, String displayName, List<String> filter) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.displayName = displayName;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFilter() {
|
||||
return this.filter;
|
||||
}
|
||||
}
|
||||
|
||||
// document sub-node filters
|
||||
public enum DocumentFilter implements AutopsyVisitableItem, SearchFilterInterface {
|
||||
|
||||
AUT_DOC_HTML(0, "AUT_DOC_HTML", //NON-NLS
|
||||
NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.autDocHtmlFilter.text"),
|
||||
Arrays.asList(".htm", ".html")), //NON-NLS
|
||||
AUT_DOC_OFFICE(1, "AUT_DOC_OFFICE", //NON-NLS
|
||||
NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.autDocOfficeFilter.text"),
|
||||
Arrays.asList(".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx")), //NON-NLS
|
||||
AUT_DOC_PDF(2, "AUT_DOC_PDF", //NON-NLS
|
||||
NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.autoDocPdfFilter.text"),
|
||||
Arrays.asList(".pdf")), //NON-NLS
|
||||
AUT_DOC_TXT(3, "AUT_DOC_TXT", //NON-NLS
|
||||
NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.autDocTxtFilter.text"),
|
||||
Arrays.asList(".txt")), //NON-NLS
|
||||
AUT_DOC_RTF(4, "AUT_DOC_RTF", //NON-NLS
|
||||
NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.autDocRtfFilter.text"),
|
||||
Arrays.asList(".rtf")); //NON-NLS
|
||||
|
||||
private final int id;
|
||||
private final String name;
|
||||
private final String displayName;
|
||||
private final List<String> filter;
|
||||
|
||||
private DocumentFilter(int id, String name, String displayName, List<String> filter) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.displayName = displayName;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFilter() {
|
||||
return this.filter;
|
||||
}
|
||||
}
|
||||
|
||||
// executable sub-node filters
|
||||
public enum ExecutableFilter implements AutopsyVisitableItem, SearchFilterInterface {
|
||||
|
||||
ExecutableFilter_EXE(0, "ExecutableFilter_EXE", ".exe", Arrays.asList(".exe")), //NON-NLS
|
||||
ExecutableFilter_DLL(1, "ExecutableFilter_DLL", ".dll", Arrays.asList(".dll")), //NON-NLS
|
||||
ExecutableFilter_BAT(2, "ExecutableFilter_BAT", ".bat", Arrays.asList(".bat")), //NON-NLS
|
||||
ExecutableFilter_CMD(3, "ExecutableFilter_CMD", ".cmd", Arrays.asList(".cmd")), //NON-NLS
|
||||
ExecutableFilter_COM(4, "ExecutableFilter_COM", ".com", Arrays.asList(".com")); //NON-NLS
|
||||
|
||||
private final int id;
|
||||
private final String name;
|
||||
private final String displayName;
|
||||
private final List<String> filter;
|
||||
|
||||
private ExecutableFilter(int id, String name, String displayName, List<String> filter) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.displayName = displayName;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFilter() {
|
||||
return this.filter;
|
||||
}
|
||||
}
|
||||
|
||||
public FileTypeExtensionFilters(SleuthkitCase skCase) {
|
||||
this.skCase = skCase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
public SleuthkitCase getSleuthkitCase() {
|
||||
return this.skCase;
|
||||
}
|
||||
|
||||
public interface SearchFilterInterface {
|
||||
|
||||
public String getName();
|
||||
|
||||
public int getId();
|
||||
|
||||
public String getDisplayName();
|
||||
|
||||
public List<String> getFilter();
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
package org.sleuthkit.autopsy.datasourceprocessors;
|
||||
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskFileRange;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
|
||||
/*
|
||||
* A runnable that adds a raw data source to a case database.
|
||||
*/
|
||||
final class AddRawImageTask implements Runnable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AddRawImageTask.class.getName());
|
||||
private final String deviceId;
|
||||
private final String imageFilePath;
|
||||
private final String timeZone;
|
||||
private final long chunkSize;
|
||||
private final DataSourceProcessorProgressMonitor progressMonitor;
|
||||
private final DataSourceProcessorCallback callback;
|
||||
private boolean criticalErrorOccurred;
|
||||
private static final long TWO_GB = 2000000000L;
|
||||
|
||||
/**
|
||||
* Constructs a runnable that adds a raw data source to a case database.
|
||||
*
|
||||
* @param deviceId An ASCII-printable identifier for the
|
||||
* device associated with the data source
|
||||
* that is intended to be unique across
|
||||
* multiple cases (e.g., a UUID).
|
||||
* @param imageFilePath Path to a Raw data source file.
|
||||
* @param timeZone The time zone to use when processing dates
|
||||
* and times for the image, obtained from
|
||||
* java.util.TimeZone.getID.
|
||||
* @param breakupChunks 2GB or not breakup.
|
||||
* @param progressMonitor Progress monitor for reporting
|
||||
* progressMonitor during processing.
|
||||
* @param callback Callback to call when processing is done.
|
||||
*/
|
||||
AddRawImageTask(String deviceId, String imageFilePath, String timeZone, long chunkSize, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
||||
this.deviceId = deviceId;
|
||||
this.imageFilePath = imageFilePath;
|
||||
this.timeZone = timeZone;
|
||||
this.chunkSize = chunkSize;
|
||||
this.callback = callback;
|
||||
this.progressMonitor = progressMonitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a raw data source to a case database.
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
/*
|
||||
* Process the input image file.
|
||||
*/
|
||||
progressMonitor.setIndeterminate(true);
|
||||
progressMonitor.setProgress(0);
|
||||
List<Content> newDataSources = new ArrayList<>();
|
||||
List<String> errorMessages = new ArrayList<>();
|
||||
addImageToCase(newDataSources, errorMessages);
|
||||
|
||||
progressMonitor.setProgress(100);
|
||||
|
||||
/**
|
||||
* Return the results via the callback passed to the constructor.
|
||||
*/
|
||||
DataSourceProcessorCallback.DataSourceProcessorResult result;
|
||||
if (criticalErrorOccurred) {
|
||||
result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS;
|
||||
} else if (!errorMessages.isEmpty()) {
|
||||
result = DataSourceProcessorCallback.DataSourceProcessorResult.NONCRITICAL_ERRORS;
|
||||
} else {
|
||||
result = DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS;
|
||||
}
|
||||
callback.done(result, errorMessages, newDataSources);
|
||||
criticalErrorOccurred = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to add the input image to the case.
|
||||
*
|
||||
* @param newDataSources If the image is added, a data source is added to
|
||||
* this list for eventual return to the caller via the
|
||||
* callback.
|
||||
* @param errorMessages If there are any error messages, the error messages
|
||||
* are added to this list for eventual return to the
|
||||
* caller via the callback.
|
||||
*/
|
||||
@Messages({"AddRawImageTask.progress.add.text=Adding raw image: ",
|
||||
"AddRawImageTask.image.critical.error.adding=Critical error adding ",
|
||||
"AddRawImageTask.for.device=for device ",
|
||||
"AddRawImageTask.image.notExisting=is not existing.",
|
||||
"AddRawImageTask.image.noncritical.error.adding=Non-critical error adding "})
|
||||
private void addImageToCase(List<Content> dataSources, List<String> errorMessages) {
|
||||
progressMonitor.setProgressText(Bundle.AddRawImageTask_progress_add_text() + imageFilePath);
|
||||
List<String> imageFilePaths = new ArrayList<>();
|
||||
SleuthkitCase caseDatabase = Case.getCurrentCase().getSleuthkitCase();
|
||||
caseDatabase.acquireExclusiveLock();
|
||||
|
||||
File imageFile = Paths.get(imageFilePath).toFile();
|
||||
if (!imageFile.exists()) {
|
||||
errorMessages.add(Bundle.AddRawImageTask_image_critical_error_adding() + imageFilePath + Bundle.AddRawImageTask_for_device()
|
||||
+ deviceId + Bundle.AddRawImageTask_image_notExisting());
|
||||
criticalErrorOccurred = true;
|
||||
return;
|
||||
}
|
||||
|
||||
imageFilePaths.add(imageFilePath);
|
||||
|
||||
try {
|
||||
/*
|
||||
* Get Image that will be added to case
|
||||
*/
|
||||
Image dataSource = caseDatabase.addImageInfo(0, imageFilePaths, timeZone); //TODO: change hard coded deviceId.
|
||||
dataSources.add(dataSource);
|
||||
List<TskFileRange> fileRanges = new ArrayList<>();
|
||||
|
||||
/*
|
||||
* Verify the size of the new image. Note that it may not be what is
|
||||
* expected, but at least part of it was added to the case.
|
||||
*/
|
||||
String verificationError = dataSource.verifyImageSize();
|
||||
if (!verificationError.isEmpty()) {
|
||||
errorMessages.add(Bundle.AddRawImageTask_image_noncritical_error_adding() + imageFilePaths + Bundle.AddRawImageTask_for_device() + deviceId + ":" + verificationError);
|
||||
}
|
||||
|
||||
long imageSize = dataSource.getSize();
|
||||
int sequence = 0;
|
||||
//start byte and end byte
|
||||
long start = 0;
|
||||
if (chunkSize > 0 && imageSize >= TWO_GB) {
|
||||
for (double size = TWO_GB; size < dataSource.getSize(); size += TWO_GB) {
|
||||
fileRanges.add(new TskFileRange(start, TWO_GB, sequence));
|
||||
start += TWO_GB;
|
||||
sequence++;
|
||||
}
|
||||
|
||||
}
|
||||
double leftoverSize = imageSize - sequence * TWO_GB;
|
||||
fileRanges.add(new TskFileRange(start, (long)leftoverSize, sequence));
|
||||
|
||||
|
||||
caseDatabase.addLayoutFiles(dataSource, fileRanges);
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
errorMessages.add(Bundle.AddRawImageTask_image_critical_error_adding() + imageFilePaths + Bundle.AddRawImageTask_for_device() + deviceId + ":" + ex.getLocalizedMessage());
|
||||
criticalErrorOccurred = true;
|
||||
} finally {
|
||||
caseDatabase.releaseExclusiveLock();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
12
Core/src/org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties
Executable file
12
Core/src/org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties
Executable file
@ -0,0 +1,12 @@
|
||||
# To change this license header, choose License Headers in Project Properties.
|
||||
# To change this template file, choose Tools | Templates
|
||||
# and open the template in the editor.
|
||||
|
||||
RawDSInputPanel.pathLabel.text=Browse for an unallocated space image file:
|
||||
RawDSInputPanel.errorLabel.text=Error Label
|
||||
RawDSInputPanel.browseButton.text=Browse
|
||||
RawDSInputPanel.pathTextField.text=
|
||||
RawDSInputPanel.jBreakFileUpLabel.text=Break image up into:
|
||||
RawDSInputPanel.jNoBreakupRadioButton.text=Do not break up
|
||||
RawDSInputPanel.j2GBBreakupRadioButton.text=2GB chunks
|
||||
RawDSInputPanel.timeZoneLabel.text=Please select the input timezone:
|
170
Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.form
Executable file
170
Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.form
Executable file
@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<NonVisualComponents>
|
||||
<Component class="javax.swing.ButtonGroup" name="infileTypeButtonGroup">
|
||||
</Component>
|
||||
</NonVisualComponents>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="pathTextField" max="32767" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="browseButton" min="-2" pref="77" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="pathLabel" min="-2" pref="218" max="-2" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="timeZoneLabel" min="-2" pref="168" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="timeZoneComboBox" min="-2" pref="199" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="19" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jBreakFileUpLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="errorLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
||||
<Component id="j2GBBreakupRadioButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jNoBreakupRadioButton" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="pathLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="pathTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="timeZoneLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="timeZoneComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
|
||||
<Component id="jBreakFileUpLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jNoBreakupRadioButton" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="j2GBBreakupRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="pathLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.pathLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="pathTextField">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.pathTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="browseButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.browseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JRadioButton" name="j2GBBreakupRadioButton">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="infileTypeButtonGroup"/>
|
||||
</Property>
|
||||
<Property name="selected" type="boolean" value="true"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.j2GBBreakupRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="j2GBBreakupRadioButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jBreakFileUpLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.jBreakFileUpLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JRadioButton" name="jNoBreakupRadioButton">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="infileTypeButtonGroup"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.jNoBreakupRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jNoBreakupRadioButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="errorLabel">
|
||||
<Properties>
|
||||
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="0" green="0" red="ff" type="rgb"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.errorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="timeZoneLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.timeZoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="timeZoneComboBox">
|
||||
<Properties>
|
||||
<Property name="maximumRowCount" type="int" value="30"/>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="0"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
352
Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java
Executable file
352
Core/src/org/sleuthkit/autopsy/datasourceprocessors/RawDSInputPanel.java
Executable file
@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourceprocessors;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Calendar;
|
||||
import java.util.SimpleTimeZone;
|
||||
import java.util.TimeZone;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.autopsy.coreutils.PathValidator;
|
||||
|
||||
final class RawDSInputPanel extends JPanel implements DocumentListener {
|
||||
private static final long TWO_GB = 2000000000L;
|
||||
private static final long serialVersionUID = 1L; //default
|
||||
private final String PROP_LASTINPUT_PATH = "LBL_LastInputFile_PATH";
|
||||
private final JFileChooser fc = new JFileChooser();
|
||||
// Externally supplied name is used to store settings
|
||||
private final String contextName;
|
||||
/**
|
||||
* Creates new form RawDSInputPanel
|
||||
*/
|
||||
private RawDSInputPanel(String context) {
|
||||
initComponents();
|
||||
|
||||
errorLabel.setVisible(false);
|
||||
|
||||
fc.setDragEnabled(false);
|
||||
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
fc.setMultiSelectionEnabled(false);
|
||||
|
||||
this.contextName = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns an instance of a RawDSInputPanel.
|
||||
*/
|
||||
static synchronized RawDSInputPanel createInstance(String context) {
|
||||
RawDSInputPanel instance = new RawDSInputPanel(context);
|
||||
|
||||
instance.postInit();
|
||||
instance.createTimeZoneList();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
//post-constructor initialization to properly initialize listener support
|
||||
//without leaking references of uninitialized objects
|
||||
private void postInit() {
|
||||
pathTextField.getDocument().addDocumentListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the drop down list for the time zones and then makes the local
|
||||
* machine time zone to be selected.
|
||||
*/
|
||||
private void createTimeZoneList() {
|
||||
// load and add all timezone
|
||||
String[] ids = SimpleTimeZone.getAvailableIDs();
|
||||
for (String id : ids) {
|
||||
TimeZone zone = TimeZone.getTimeZone(id);
|
||||
int offset = zone.getRawOffset() / 1000;
|
||||
int hour = offset / 3600;
|
||||
int minutes = (offset % 3600) / 60;
|
||||
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
|
||||
|
||||
timeZoneComboBox.addItem(item);
|
||||
}
|
||||
// get the current timezone
|
||||
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
|
||||
int thisOffset = thisTimeZone.getRawOffset() / 1000;
|
||||
int thisHour = thisOffset / 3600;
|
||||
int thisMinutes = (thisOffset % 3600) / 60;
|
||||
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
|
||||
|
||||
// set the selected timezone
|
||||
timeZoneComboBox.setSelectedItem(formatted);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
infileTypeButtonGroup = new javax.swing.ButtonGroup();
|
||||
pathLabel = new javax.swing.JLabel();
|
||||
pathTextField = new javax.swing.JTextField();
|
||||
browseButton = new javax.swing.JButton();
|
||||
j2GBBreakupRadioButton = new javax.swing.JRadioButton();
|
||||
jBreakFileUpLabel = new javax.swing.JLabel();
|
||||
jNoBreakupRadioButton = new javax.swing.JRadioButton();
|
||||
errorLabel = new javax.swing.JLabel();
|
||||
timeZoneLabel = new javax.swing.JLabel();
|
||||
timeZoneComboBox = new javax.swing.JComboBox<>();
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.pathLabel.text")); // NOI18N
|
||||
|
||||
pathTextField.setText(org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.pathTextField.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.browseButton.text")); // NOI18N
|
||||
browseButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
browseButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
infileTypeButtonGroup.add(j2GBBreakupRadioButton);
|
||||
j2GBBreakupRadioButton.setSelected(true);
|
||||
org.openide.awt.Mnemonics.setLocalizedText(j2GBBreakupRadioButton, org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.j2GBBreakupRadioButton.text")); // NOI18N
|
||||
j2GBBreakupRadioButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
j2GBBreakupRadioButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jBreakFileUpLabel, org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.jBreakFileUpLabel.text")); // NOI18N
|
||||
|
||||
infileTypeButtonGroup.add(jNoBreakupRadioButton);
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jNoBreakupRadioButton, org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.jNoBreakupRadioButton.text")); // NOI18N
|
||||
jNoBreakupRadioButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
jNoBreakupRadioButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
errorLabel.setForeground(new java.awt.Color(255, 0, 0));
|
||||
org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.errorLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.timeZoneLabel.text")); // NOI18N
|
||||
|
||||
timeZoneComboBox.setMaximumRowCount(30);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(pathTextField)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(browseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(pathLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 218, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(timeZoneLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 168, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 199, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addGap(0, 19, Short.MAX_VALUE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jBreakFileUpLabel)
|
||||
.addComponent(errorLabel)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addComponent(j2GBBreakupRadioButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jNoBreakupRadioButton)))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(pathLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(browseButton))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(timeZoneLabel)
|
||||
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(errorLabel)
|
||||
.addGap(5, 5, 5)
|
||||
.addComponent(jBreakFileUpLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jNoBreakupRadioButton)
|
||||
.addComponent(j2GBBreakupRadioButton))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
@SuppressWarnings("deprecation")
|
||||
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
|
||||
String oldText = pathTextField.getText();
|
||||
// set the current directory of the FileChooser if the ImagePath Field is valid
|
||||
File currentDir = new File(oldText);
|
||||
if (currentDir.exists()) {
|
||||
fc.setCurrentDirectory(currentDir);
|
||||
}
|
||||
|
||||
int retval = fc.showOpenDialog(this);
|
||||
if (retval == JFileChooser.APPROVE_OPTION) {
|
||||
String path = fc.getSelectedFile().getPath();
|
||||
pathTextField.setText(path);
|
||||
}
|
||||
}//GEN-LAST:event_browseButtonActionPerformed
|
||||
|
||||
private void j2GBBreakupRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_j2GBBreakupRadioButtonActionPerformed
|
||||
// TODO add your handling code here:
|
||||
}//GEN-LAST:event_j2GBBreakupRadioButtonActionPerformed
|
||||
|
||||
private void jNoBreakupRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jNoBreakupRadioButtonActionPerformed
|
||||
// TODO add your handling code here:
|
||||
}//GEN-LAST:event_jNoBreakupRadioButtonActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton browseButton;
|
||||
private javax.swing.JLabel errorLabel;
|
||||
private javax.swing.ButtonGroup infileTypeButtonGroup;
|
||||
private javax.swing.JRadioButton j2GBBreakupRadioButton;
|
||||
private javax.swing.JLabel jBreakFileUpLabel;
|
||||
private javax.swing.JRadioButton jNoBreakupRadioButton;
|
||||
private javax.swing.JLabel pathLabel;
|
||||
private javax.swing.JTextField pathTextField;
|
||||
private javax.swing.JComboBox<String> timeZoneComboBox;
|
||||
private javax.swing.JLabel timeZoneLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
/**
|
||||
* Get the path of the user selected image.
|
||||
*
|
||||
* @return the image path
|
||||
*/
|
||||
String getImageFilePath() {
|
||||
return pathTextField.getText();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
//reset the UI elements to default
|
||||
pathTextField.setText(null);
|
||||
j2GBBreakupRadioButton.setSelected(true);
|
||||
}
|
||||
|
||||
long getChunkSize() {
|
||||
if (jNoBreakupRadioButton.isSelected()) {
|
||||
return -1;
|
||||
} else { //if have more choices here, the selection of each radiobutton should be checked
|
||||
return TWO_GB;
|
||||
}
|
||||
}
|
||||
|
||||
String getTimeZone() {
|
||||
String tz = timeZoneComboBox.getSelectedItem().toString();
|
||||
return tz.substring(tz.indexOf(")") + 2).trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we enable the next button of the wizard?
|
||||
*
|
||||
* @return true if a proper image has been selected, false otherwise
|
||||
*/
|
||||
boolean validatePanel() {
|
||||
errorLabel.setVisible(false);
|
||||
String path = getImageFilePath();
|
||||
if (path == null || path.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// display warning if there is one (but don't disable "next" button)
|
||||
warnIfPathIsInvalid(path);
|
||||
|
||||
boolean isExist = new File(path).exists();
|
||||
|
||||
return (isExist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates path to selected data source and displays warning if it is
|
||||
* invalid.
|
||||
*
|
||||
* @param path Absolute path to the selected data source
|
||||
*/
|
||||
@Messages({"RawDSInputPanel.error.text=Path to multi-user data source is on \"C:\" drive"})
|
||||
private void warnIfPathIsInvalid(String path) {
|
||||
if (!PathValidator.isValid(path, Case.getCurrentCase().getCaseType())) {
|
||||
errorLabel.setVisible(true);
|
||||
errorLabel.setText(Bundle.RawDSInputPanel_error_text());
|
||||
}
|
||||
}
|
||||
|
||||
void storeSettings() {
|
||||
String inFilePath = getImageFilePath();
|
||||
if (null != inFilePath) {
|
||||
String imagePath = inFilePath.substring(0, inFilePath.lastIndexOf(File.separator) + 1);
|
||||
ModuleSettings.setConfigSetting(contextName, PROP_LASTINPUT_PATH, imagePath);
|
||||
}
|
||||
}
|
||||
|
||||
void readSettings() {
|
||||
String inFilePath = ModuleSettings.getConfigSetting(contextName, PROP_LASTINPUT_PATH);
|
||||
if (null != inFilePath) {
|
||||
if (!inFilePath.isEmpty()) {
|
||||
pathTextField.setText(inFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update functions are called by the pathTextField which has this set as
|
||||
* it's DocumentEventListener. Each update function fires a property change
|
||||
* to be caught by the parent panel.
|
||||
*
|
||||
* @param e the event, which is ignored
|
||||
*/
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the focus to the pathTextField.
|
||||
*/
|
||||
void select() {
|
||||
pathTextField.requestFocusInWindow();
|
||||
}
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourceprocessors;
|
||||
|
||||
import java.util.UUID;
|
||||
import javax.swing.JPanel;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
|
||||
/**
|
||||
* A Raw data source processor that implements the DataSourceProcessor service
|
||||
* provider interface to allow integration with the add data source wizard.
|
||||
* It also provides a run method overload to allow it to be used independently
|
||||
* of the wizard.
|
||||
*/
|
||||
@ServiceProvider(service = DataSourceProcessor.class)
|
||||
public class RawDSProcessor implements DataSourceProcessor {
|
||||
private final RawDSInputPanel configPanel;
|
||||
private AddRawImageTask addImageTask;
|
||||
|
||||
/*
|
||||
* Constructs a Raw data source processor that implements the
|
||||
* DataSourceProcessor service provider interface to allow integration
|
||||
* with the add data source wizard. It also provides a run method
|
||||
* overload to allow it to be used independently of the wizard.
|
||||
*/
|
||||
public RawDSProcessor() {
|
||||
configPanel = RawDSInputPanel.createInstance(RawDSProcessor.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string that describes the type of data sources this processor is
|
||||
* able to add to the case database. The string is suitable for display in a
|
||||
* type selection UI component (e.g., a combo box).
|
||||
*
|
||||
* @return A data source type display string for this data source processor.
|
||||
*/
|
||||
@Messages({"RawDSProcessor.dataSourceType=Unallocated Space Image File"})
|
||||
public static String getType() {
|
||||
return Bundle.RawDSProcessor_dataSourceType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string that describes the type of data sources this processor is
|
||||
* able to add to the case database. The string is suitable for display in a
|
||||
* type selection UI component (e.g., a combo box).
|
||||
*
|
||||
* @return A data source type display string for this data source processor.
|
||||
*/
|
||||
@Override
|
||||
public String getDataSourceType() {
|
||||
return Bundle.RawDSProcessor_dataSourceType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the panel that allows a user to select a data source and do any
|
||||
* configuration required by the data source. The panel is less than 544
|
||||
* pixels wide and less than 173 pixels high.
|
||||
*
|
||||
* @return A selection and configuration panel for this data source
|
||||
* processor.
|
||||
*/
|
||||
@Override
|
||||
public JPanel getPanel() {
|
||||
configPanel.readSettings();
|
||||
configPanel.select();
|
||||
return configPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the settings in the selection and configuration panel
|
||||
* are valid and complete.
|
||||
*
|
||||
* @return True if the settings are valid and complete and the processor is
|
||||
* ready to have its run method called, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean isPanelValid() {
|
||||
return configPanel.validatePanel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a data source to the case database using a background task in a
|
||||
* separate thread and the settings provided by the selection and
|
||||
* configuration panel. Returns as soon as the background task is started.
|
||||
* The background task uses a callback object to signal task completion and
|
||||
* return results.
|
||||
*
|
||||
* This method should not be called unless isPanelValid returns true.
|
||||
*
|
||||
* @param progressMonitor Progress monitor that will be used by the
|
||||
* background task to report progress.
|
||||
* @param callback Callback that will be used by the background task
|
||||
* to return results.
|
||||
*/
|
||||
@Override
|
||||
public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
||||
configPanel.storeSettings();
|
||||
run(UUID.randomUUID().toString(), configPanel.getImageFilePath(), configPanel.getTimeZone(), configPanel.getChunkSize(), progressMonitor, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a data source to the case database using a background task in a
|
||||
* separate thread and the given settings instead of those provided by the
|
||||
* selection and configuration panel. Returns as soon as the background task
|
||||
* is started and uses the callback object to signal task completion and
|
||||
* return results.
|
||||
*
|
||||
* @param deviceId An ASCII-printable identifier for the
|
||||
* device associated with the data source
|
||||
* that is intended to be unique across
|
||||
* multiple cases (e.g., a UUID).
|
||||
* @param rawDSInputFilePath Path to a Raw data source file.
|
||||
* @param isHandsetFile Indicates whether the XML file is for a
|
||||
* handset or a SIM.
|
||||
* @param progressMonitor Progress monitor for reporting progress
|
||||
* during processing.
|
||||
*/
|
||||
private void run(String deviceId, String imageFilePath, String timeZone, long chunkSize, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
||||
addImageTask = new AddRawImageTask(deviceId, imageFilePath, timeZone, chunkSize, progressMonitor, callback);
|
||||
new Thread(addImageTask).start();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the selection and configuration panel for this data source
|
||||
* processor.
|
||||
*/
|
||||
@Override
|
||||
public void reset() {
|
||||
configPanel.reset();
|
||||
}
|
||||
|
||||
}
|
@ -42,9 +42,11 @@ import org.sleuthkit.autopsy.datamodel.DirectoryNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode;
|
||||
import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.Reports;
|
||||
import org.sleuthkit.autopsy.datamodel.SlackFileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
@ -55,6 +57,7 @@ import org.sleuthkit.datamodel.Directory;
|
||||
import org.sleuthkit.datamodel.File;
|
||||
import org.sleuthkit.datamodel.LayoutFile;
|
||||
import org.sleuthkit.datamodel.LocalFile;
|
||||
import org.sleuthkit.datamodel.SlackFile;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
|
||||
@ -200,6 +203,8 @@ public class DataResultFilterNode extends FilterNode {
|
||||
} else if ((c = ban.getLookup().lookup(LocalFile.class)) != null
|
||||
|| (c = ban.getLookup().lookup(DerivedFile.class)) != null) {
|
||||
n = new LocalFileNode((AbstractFile) c);
|
||||
} else if ((c = ban.getLookup().lookup(SlackFile.class)) != null) {
|
||||
n = new SlackFileNode((SlackFile) c);
|
||||
}
|
||||
if (n != null) {
|
||||
actions.add(null); // creates a menu separator
|
||||
@ -231,7 +236,13 @@ public class DataResultFilterNode extends FilterNode {
|
||||
// The base class Action is "Collapse All", inappropriate.
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Action> visit(FileTypesNode fileTypes) {
|
||||
return defaultVisit(fileTypes);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected List<Action> defaultVisit(DisplayableItemNode ditem) {
|
||||
//preserve the default node's actions
|
||||
@ -271,6 +282,7 @@ public class DataResultFilterNode extends FilterNode {
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -322,7 +334,14 @@ public class DataResultFilterNode extends FilterNode {
|
||||
protected AbstractAction defaultVisit(DisplayableItemNode c) {
|
||||
return openChild(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(FileTypesNode fileTypes) {
|
||||
return openChild(fileTypes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tell the originating ExplorerManager to display the given
|
||||
* dataModelNode.
|
||||
|
@ -29,8 +29,10 @@ import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode;
|
||||
import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.SlackFileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
|
||||
import org.sleuthkit.autopsy.datamodel.VolumeNode;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
@ -225,6 +227,11 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
||||
public Boolean visit(LayoutFileNode fn) {
|
||||
return visitDeep(fn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visit(SlackFileNode sfn) {
|
||||
return visitDeep(sfn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visit(VolumeNode vn) {
|
||||
@ -236,6 +243,12 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
||||
return visitDeep(vdn);
|
||||
//return ! vdn.hasContentChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visit(FileTypesNode ft) {
|
||||
return defaultVisit(ft);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class ShowItemVisitor extends DisplayableItemNodeVisitor.Default<Boolean> {
|
||||
@ -267,11 +280,22 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
||||
public Boolean visit(LayoutFileNode ln) {
|
||||
return ln.hasContentChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visit(SlackFileNode sfn) {
|
||||
return sfn.hasContentChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visit(VirtualDirectoryNode vdn) {
|
||||
return true;
|
||||
//return vdn.hasContentChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visit(FileTypesNode fileTypes) {
|
||||
return defaultVisit(fileTypes);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.directorytree;
|
||||
|
||||
import org.sleuthkit.autopsy.datamodel.EmptyNode;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.EventQueue;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
@ -60,13 +61,16 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DataSources;
|
||||
import org.sleuthkit.autopsy.datamodel.DataSourcesNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||
import org.sleuthkit.autopsy.datamodel.ExtractedContent;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypesByMimeType;
|
||||
import org.sleuthkit.autopsy.datamodel.KeywordHits;
|
||||
import org.sleuthkit.autopsy.datamodel.KnownFileFilterNode;
|
||||
import org.sleuthkit.autopsy.datamodel.Reports;
|
||||
import org.sleuthkit.autopsy.datamodel.Results;
|
||||
import org.sleuthkit.autopsy.datamodel.ResultsNode;
|
||||
import org.sleuthkit.autopsy.datamodel.RootContentChildren;
|
||||
import org.sleuthkit.autopsy.datamodel.SlackFileFilterNode;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
||||
import org.sleuthkit.autopsy.datamodel.Views;
|
||||
import org.sleuthkit.autopsy.datamodel.ViewsNode;
|
||||
@ -92,7 +96,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
private final LinkedList<String[]> backList;
|
||||
private final LinkedList<String[]> forwardList;
|
||||
private static final String PREFERRED_ID = "DirectoryTreeTopComponent"; //NON-NLS
|
||||
private static final Logger logger = Logger.getLogger(DirectoryTreeTopComponent.class.getName());
|
||||
private static final Logger LOGGER = Logger.getLogger(DirectoryTreeTopComponent.class.getName());
|
||||
private RootContentChildren contentChildren;
|
||||
|
||||
/**
|
||||
@ -126,10 +130,12 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
@Override
|
||||
public void preferenceChange(PreferenceChangeEvent evt) {
|
||||
switch (evt.getKey()) {
|
||||
case UserPreferences.HIDE_KNOWN_FILES_IN_DATA_SOURCES_TREE:
|
||||
case UserPreferences.HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE:
|
||||
case UserPreferences.HIDE_SLACK_FILES_IN_DATA_SRCS_TREE:
|
||||
refreshContentTreeSafe();
|
||||
break;
|
||||
case UserPreferences.HIDE_KNOWN_FILES_IN_VIEWS_TREE:
|
||||
case UserPreferences.HIDE_SLACK_FILES_IN_VIEWS_TREE:
|
||||
// TODO: Need a way to refresh the Views subtree
|
||||
break;
|
||||
}
|
||||
@ -307,14 +313,14 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
WindowManager winManager = WindowManager.getDefault();
|
||||
TopComponent win = winManager.findTopComponent(PREFERRED_ID);
|
||||
if (win == null) {
|
||||
logger.warning(
|
||||
LOGGER.warning(
|
||||
"Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system."); //NON-NLS
|
||||
return getDefault();
|
||||
}
|
||||
if (win instanceof DirectoryTreeTopComponent) {
|
||||
return (DirectoryTreeTopComponent) win;
|
||||
}
|
||||
logger.warning(
|
||||
LOGGER.warning(
|
||||
"There seem to be multiple components with the '" + PREFERRED_ID //NON-NLS
|
||||
+ "' ID. That is a potential source of errors and unexpected behavior."); //NON-NLS
|
||||
return getDefault();
|
||||
@ -360,7 +366,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
items.add(new Tags());
|
||||
items.add(new Reports());
|
||||
contentChildren = new RootContentChildren(items);
|
||||
|
||||
|
||||
Node root = new AbstractNode(contentChildren) {
|
||||
/**
|
||||
* to override the right click action in the white blank
|
||||
@ -429,7 +435,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
try {
|
||||
em.setSelectedNodes(new Node[]{childNodes.getNodeAt(0)});
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "Error setting default selected node.", ex); //NON-NLS
|
||||
LOGGER.log(Level.SEVERE, "Error setting default selected node.", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
@ -598,6 +604,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
}
|
||||
}
|
||||
|
||||
@NbBundle.Messages("DirectoryTreeTopComponent.emptyMimeNode.text=Data not available. Run file type identification module.")
|
||||
/**
|
||||
* Event handler to run when selection changed
|
||||
*
|
||||
@ -631,23 +638,28 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
if (origin == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Node originNode = origin.getNode();
|
||||
|
||||
//set node, wrap in filter node first to filter out children
|
||||
Node drfn = new DataResultFilterNode(originNode, DirectoryTreeTopComponent.this.em);
|
||||
Node kffn = new KnownFileFilterNode(drfn, KnownFileFilterNode.getSelectionContext(originNode));
|
||||
/*
|
||||
* TODO (AUT-1849): Correct or remove peristent column
|
||||
* reordering code
|
||||
*
|
||||
* The following conditional was added to support this
|
||||
* feature.
|
||||
*/
|
||||
// if(originNode instanceof DisplayableItemNode) {
|
||||
// dataResult.setNode(new TableFilterNode(kffn, true, ((DisplayableItemNode) originNode).getItemType()));
|
||||
// } else {
|
||||
dataResult.setNode(new TableFilterNode(kffn, true));
|
||||
// }
|
||||
Node sffn = new SlackFileFilterNode(kffn, SlackFileFilterNode.getSelectionContext(originNode));
|
||||
|
||||
// Create a TableFilterNode with knowledge of the node's type to allow for column order settings
|
||||
//Special case for when File Type Identification has not yet been run and
|
||||
//there are no mime types to populate Files by Mime Type Tree
|
||||
if (FileTypesByMimeType.isEmptyMimeTypeNode(originNode)) {
|
||||
EmptyNode emptyNode = new EmptyNode(Bundle.DirectoryTreeTopComponent_emptyMimeNode_text());
|
||||
Node emptyDrfn = new DataResultFilterNode(emptyNode, DirectoryTreeTopComponent.this.em);
|
||||
Node emptyKffn = new KnownFileFilterNode(emptyDrfn, KnownFileFilterNode.getSelectionContext(emptyNode));
|
||||
Node emptySffn = new SlackFileFilterNode(emptyKffn, SlackFileFilterNode.getSelectionContext(originNode));
|
||||
dataResult.setNode(new TableFilterNode(emptySffn, true, "This Node Is Empty")); //NON-NLS
|
||||
} else if (originNode instanceof DisplayableItemNode) {
|
||||
dataResult.setNode(new TableFilterNode(sffn, true, ((DisplayableItemNode) originNode).getItemType()));
|
||||
} else {
|
||||
dataResult.setNode(new TableFilterNode(sffn, true));
|
||||
}
|
||||
|
||||
String displayName = "";
|
||||
Content content = originNode.getLookup().lookup(Content.class);
|
||||
@ -655,7 +667,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
try {
|
||||
displayName = content.getUniquePath();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Exception while calling Content.getUniquePath() for node: " + originNode); //NON-NLS
|
||||
LOGGER.log(Level.SEVERE, "Exception while calling Content.getUniquePath() for node: " + originNode); //NON-NLS
|
||||
}
|
||||
} else if (originNode.getLookup().lookup(String.class) != null) {
|
||||
displayName = originNode.getLookup().lookup(String.class);
|
||||
@ -762,13 +774,13 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
Children rootChildren = em.getRootContext().getChildren();
|
||||
Node dataSourcesFilterNode = rootChildren.findChild(DataSourcesNode.NAME);
|
||||
if (dataSourcesFilterNode == null) {
|
||||
logger.log(Level.SEVERE, "Cannot find data sources filter node, won't refresh the content tree"); //NON-NLS
|
||||
LOGGER.log(Level.SEVERE, "Cannot find data sources filter node, won't refresh the content tree"); //NON-NLS
|
||||
return;
|
||||
}
|
||||
DirectoryTreeFilterNode.OriginalNode imagesNodeOrig = dataSourcesFilterNode.getLookup().lookup(DirectoryTreeFilterNode.OriginalNode.class);
|
||||
|
||||
if (imagesNodeOrig == null) {
|
||||
logger.log(Level.SEVERE, "Cannot find data sources node, won't refresh the content tree"); //NON-NLS
|
||||
LOGGER.log(Level.SEVERE, "Cannot find data sources node, won't refresh the content tree"); //NON-NLS
|
||||
return;
|
||||
}
|
||||
|
||||
@ -787,8 +799,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
* Set the selected node using a path to a previously selected node.
|
||||
*
|
||||
* @param previouslySelectedNodePath Path to a previously selected node.
|
||||
* @param rootNodeName Name of the root node to match, may be
|
||||
* null.
|
||||
* @param rootNodeName Name of the root node to match, may be null.
|
||||
*/
|
||||
private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) {
|
||||
if (previouslySelectedNodePath == null) {
|
||||
@ -812,7 +823,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
for (int i = 0; i < previouslySelectedNodePath.length; ++i) {
|
||||
nodePath.append(previouslySelectedNodePath[i]).append("/");
|
||||
}
|
||||
logger.log(Level.WARNING, "Failed to find any nodes to select on path " + nodePath.toString(), ex); //NON-NLS
|
||||
LOGGER.log(Level.WARNING, "Failed to find any nodes to select on path " + nodePath.toString(), ex); //NON-NLS
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -827,7 +838,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
try {
|
||||
em.setExploredContextAndSelection(selectedNode, new Node[]{selectedNode});
|
||||
} catch (PropertyVetoException ex) {
|
||||
logger.log(Level.WARNING, "Property veto from ExplorerManager setting selection to " + selectedNode.getName(), ex); //NON-NLS
|
||||
LOGGER.log(Level.WARNING, "Property veto from ExplorerManager setting selection to " + selectedNode.getName(), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -867,7 +878,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
}
|
||||
treeNode = hashsetRootChilds.findChild(setName);
|
||||
} catch (TskException ex) {
|
||||
logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
||||
LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
||||
}
|
||||
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
||||
Node keywordRootNode = resultsChilds.findChild(typeName);
|
||||
@ -894,7 +905,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
}
|
||||
treeNode = listChildren.findChild(keywordName);
|
||||
} catch (TskException ex) {
|
||||
logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
||||
LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
||||
}
|
||||
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()
|
||||
|| typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
|
||||
@ -911,7 +922,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
}
|
||||
treeNode = interestingItemsRootChildren.findChild(setName);
|
||||
} catch (TskException ex) {
|
||||
logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
||||
LOGGER.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
|
||||
}
|
||||
} else {
|
||||
Node extractedContent = resultsChilds.findChild(ExtractedContent.NAME);
|
||||
@ -929,7 +940,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
try {
|
||||
em.setExploredContextAndSelection(treeNode, new Node[]{treeNode});
|
||||
} catch (PropertyVetoException ex) {
|
||||
logger.log(Level.WARNING, "Property Veto: ", ex); //NON-NLS
|
||||
LOGGER.log(Level.WARNING, "Property Veto: ", ex); //NON-NLS
|
||||
}
|
||||
|
||||
// Another thread is needed because we have to wait for dataResult to populate
|
||||
@ -964,7 +975,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
try {
|
||||
firePropertyChange(BlackboardResultViewer.FINISHED_DISPLAY_EVT, 0, 1);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "DirectoryTreeTopComponent listener threw exception", e); //NON-NLS
|
||||
LOGGER.log(Level.SEVERE, "DirectoryTreeTopComponent listener threw exception", e); //NON-NLS
|
||||
MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.moduleErr"),
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"DirectoryTreeTopComponent.moduleErr.msg"),
|
||||
|
@ -30,6 +30,7 @@ import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||
import org.sleuthkit.autopsy.datamodel.SlackFileNode;
|
||||
|
||||
/**
|
||||
* Extracts a File object to a temporary file in the case directory, and then
|
||||
@ -68,13 +69,12 @@ public class ExternalViewerAction extends AbstractAction {
|
||||
// no point opening a file if it's empty, and java doesn't know how to
|
||||
// find an application for files without an extension
|
||||
// or if file is executable (for security reasons)
|
||||
if (!(size > 0) || extPos == -1 || isExecutable) {
|
||||
// Also skip slack files since their extension is the original extension + "-slack"
|
||||
if (!(size > 0) || extPos == -1 || isExecutable || (fileNode instanceof SlackFileNode)) {
|
||||
this.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Messages({"ExternalViewerAction.actionPerformed.failure.message=Could not find a viewer for the given file.",
|
||||
"ExternalViewerAction.actionPerformed.failure.title=Open Failure"})
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
// Get the temp folder path of the case
|
||||
@ -93,32 +93,73 @@ public class ExternalViewerAction extends AbstractAction {
|
||||
logger.log(Level.WARNING, "Can't save to temporary file.", ex); //NON-NLS
|
||||
}
|
||||
|
||||
ExternalViewerAction.openFile(fileObject.getMIMEType(), fileObjectExt, tempFile);
|
||||
|
||||
// delete the temporary file on exit
|
||||
tempFile.deleteOnExit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a file, taking into account user preferences and then the default
|
||||
* associated application.
|
||||
*
|
||||
* @param mimeType MIME type of the file
|
||||
* @param ext extension of the file
|
||||
* @param file the file object
|
||||
*/
|
||||
@Messages({
|
||||
"ExternalViewerAction.actionPerformed.failure.title=Open File Failure",
|
||||
"ExternalViewerAction.actionPerformed.failure.IO.message=There is no associated editor for files of this type or the associated application failed to launch.",
|
||||
"ExternalViewerAction.actionPerformed.failure.support.message=This platform (operating system) does not support opening a file in an editor this way.",
|
||||
"ExternalViewerAction.actionPerformed.failure.missingFile.message=The file no longer exists.",
|
||||
"ExternalViewerAction.actionPerformed.failure.permission.message=Permission to open the file was denied."})
|
||||
public static void openFile(String mimeType, String ext, File file) {
|
||||
/**
|
||||
* Check if the file MIME type or extension exists in the user defined
|
||||
* settings. Otherwise open with the default associated application.
|
||||
*/
|
||||
String exePath = ExternalViewerRulesManager.getInstance().getExePathForName(fileObject.getMIMEType());
|
||||
String exePath = ExternalViewerRulesManager.getInstance().getExePathForName(mimeType);
|
||||
if (exePath.equals("")) {
|
||||
exePath = ExternalViewerRulesManager.getInstance().getExePathForName(fileObjectExt);
|
||||
exePath = ExternalViewerRulesManager.getInstance().getExePathForName(ext);
|
||||
}
|
||||
if (!exePath.equals("")) {
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
String[] s = new String[]{exePath, tempFile.getAbsolutePath()};
|
||||
String[] s = new String[]{exePath, file.getAbsolutePath()};
|
||||
try {
|
||||
runtime.exec(s);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "Could not open the specified viewer for the given file: " + tempFile.getName(), ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(null, Bundle.ExternalViewerAction_actionPerformed_failure_message(), Bundle.ExternalViewerAction_actionPerformed_failure_title(), JOptionPane.ERROR_MESSAGE);
|
||||
logger.log(Level.WARNING, "Could not open the specified viewer for the given file: " + file.getName(), ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(null, Bundle.ExternalViewerAction_actionPerformed_failure_IO_message(), Bundle.ExternalViewerAction_actionPerformed_failure_title(), JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
Desktop.getDesktop().open(tempFile);
|
||||
Desktop.getDesktop().open(file);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "Could not find a viewer for the given file: " + tempFile.getName(), ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(null, Bundle.ExternalViewerAction_actionPerformed_failure_message(), Bundle.ExternalViewerAction_actionPerformed_failure_title(), JOptionPane.ERROR_MESSAGE);
|
||||
logger.log(Level.WARNING, "Could not find a viewer for the given file: " + file.getName(), ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(null,
|
||||
Bundle.ExternalViewerAction_actionPerformed_failure_IO_message(),
|
||||
Bundle.ExternalViewerAction_actionPerformed_failure_title(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
logger.log(Level.WARNING, "Platform cannot open " + file.getName() + " in the defined editor.", ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(null,
|
||||
Bundle.ExternalViewerAction_actionPerformed_failure_support_message(),
|
||||
Bundle.ExternalViewerAction_actionPerformed_failure_title(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
logger.log(Level.WARNING, "Could not find the given file: " + file.getName(), ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(null,
|
||||
Bundle.ExternalViewerAction_actionPerformed_failure_missingFile_message(),
|
||||
Bundle.ExternalViewerAction_actionPerformed_failure_title(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (SecurityException ex) {
|
||||
logger.log(Level.WARNING, "Could not get permission to open the given file: " + file.getName(), ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(null,
|
||||
Bundle.ExternalViewerAction_actionPerformed_failure_permission_message(),
|
||||
Bundle.ExternalViewerAction_actionPerformed_failure_title(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
// delete the file on exit
|
||||
tempFile.deleteOnExit();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -165,8 +165,9 @@ class FileSearchPanel extends javax.swing.JPanel {
|
||||
contentList = Collections.<AbstractFile>emptyList();
|
||||
}
|
||||
|
||||
SearchNode sn = new SearchNode(contentList);
|
||||
final TopComponent searchResultWin = DataResultTopComponent.createInstance(title, pathText,
|
||||
new TableFilterNode(new SearchNode(contentList), true), contentList.size());
|
||||
new TableFilterNode(sn, true, sn.getName()), contentList.size());
|
||||
|
||||
searchResultWin.requestActive(); // make it the active top component
|
||||
|
||||
|
@ -1,31 +1,35 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.filesearch;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import org.apache.tika.mime.MediaType;
|
||||
import org.apache.tika.mime.MimeTypes;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author oliver
|
||||
*/
|
||||
public class MimeTypePanel extends javax.swing.JPanel {
|
||||
|
||||
private static final SortedSet<MediaType> mediaTypes = MimeTypes.getDefaultMimeTypes().getMediaTypeRegistry().getTypes();
|
||||
private static final Logger logger = Logger.getLogger(MimeTypePanel.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -45,8 +49,8 @@ public class MimeTypePanel extends javax.swing.JPanel {
|
||||
|
||||
private String[] getMimeTypeArray() {
|
||||
Set<String> fileTypesCollated = new HashSet<>();
|
||||
for (MediaType mediaType : mediaTypes) {
|
||||
fileTypesCollated.add(mediaType.toString());
|
||||
for (String mediaType : FileTypeDetector.getStandardDetectedTypes()) {
|
||||
fileTypesCollated.add(mediaType);
|
||||
}
|
||||
|
||||
FileTypeDetector fileTypeDetector;
|
||||
@ -78,7 +82,7 @@ public class MimeTypePanel extends javax.swing.JPanel {
|
||||
boolean isSelected() {
|
||||
return this.mimeTypeCheckBox.isSelected();
|
||||
}
|
||||
|
||||
|
||||
void setComponentsEnabled() {
|
||||
boolean enabled = this.isSelected();
|
||||
this.mimeTypeList.setEnabled(enabled);
|
||||
|
@ -27,6 +27,7 @@ import org.sleuthkit.datamodel.File;
|
||||
import org.sleuthkit.datamodel.FileSystem;
|
||||
import org.sleuthkit.datamodel.LayoutFile;
|
||||
import org.sleuthkit.datamodel.LocalFile;
|
||||
import org.sleuthkit.datamodel.SlackFile;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
|
||||
/**
|
||||
@ -85,4 +86,11 @@ final class GetRootDirectoryVisitor extends GetFilesContentVisitor {
|
||||
return getAllFromChildren(localFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<AbstractFile> visit(SlackFile slackFile) {
|
||||
//can have slack files
|
||||
//TODO test this and overall scheduler with local files
|
||||
return getAllFromChildren(slackFile);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -46,9 +46,9 @@ final class IngestMessageTopComponent extends TopComponent {
|
||||
private static final Logger logger = Logger.getLogger(IngestMessageTopComponent.class.getName());
|
||||
private IngestMessageMainPanel messagePanel;
|
||||
private IngestManager manager;
|
||||
private static String PREFERRED_ID = "IngestMessageTopComponent"; //NON-NLS
|
||||
private ActionListener showIngestInboxAction;
|
||||
private static final Pattern tagRemove = Pattern.compile("<.+?>");
|
||||
private static final String PREFERRED_ID = "IngestMessageTopComponent"; //NON-NLS
|
||||
private final ActionListener showIngestInboxAction;
|
||||
private static final Pattern TAG_REMOVE = Pattern.compile("<.+?>");
|
||||
|
||||
public IngestMessageTopComponent() {
|
||||
initComponents();
|
||||
@ -292,6 +292,7 @@ final class IngestMessageTopComponent extends TopComponent {
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action[] getActions() {
|
||||
//disable TC toolbar actions
|
||||
return new Action[0];
|
||||
@ -302,7 +303,7 @@ final class IngestMessageTopComponent extends TopComponent {
|
||||
return string;
|
||||
}
|
||||
|
||||
Matcher m = tagRemove.matcher(string);
|
||||
Matcher m = TAG_REMOVE.matcher(string);
|
||||
return m.replaceAll("");
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
*
|
||||
* Copyright 2011-2015 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -145,8 +145,9 @@ class IngestMessagesToolbar extends javax.swing.JPanel {
|
||||
if (mode != null) {
|
||||
//TopComponent[] tcs = mode.getTopComponents();
|
||||
mode.dockInto(tc);
|
||||
String something = mode.getName();
|
||||
tc.open();
|
||||
//tc.requestActive();
|
||||
//tc.requestActive();
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,7 +159,7 @@ class IngestMessagesToolbar extends javax.swing.JPanel {
|
||||
|
||||
private static class IngestMessagesButton extends JButton {
|
||||
|
||||
private static final int fontSize = 9;
|
||||
private static final int FONT_SIZE = 9;
|
||||
private int messages = 0;
|
||||
|
||||
@Override
|
||||
@ -169,7 +170,7 @@ class IngestMessagesToolbar extends javax.swing.JPanel {
|
||||
return;
|
||||
}
|
||||
//paint text
|
||||
Font messagesFont = g.getFont().deriveFont(Font.PLAIN, fontSize);
|
||||
Font messagesFont = g.getFont().deriveFont(Font.PLAIN, FONT_SIZE);
|
||||
String messageStr = Integer.toString(messages);
|
||||
final int len = messageStr.length();
|
||||
g.setFont(messagesFont);
|
||||
@ -181,9 +182,9 @@ class IngestMessagesToolbar extends javax.swing.JPanel {
|
||||
}
|
||||
g.setColor(Color.GRAY);
|
||||
//g.fillRect(x, 1, dx, fontSize);
|
||||
g.fillRoundRect(x, 1, dx, fontSize, 2, 2);
|
||||
g.fillRoundRect(x, 1, dx, FONT_SIZE, 2, 2);
|
||||
g.setColor(Color.WHITE);
|
||||
g.drawString(messageStr, x + 2, fontSize);
|
||||
g.drawString(messageStr, x + 2, FONT_SIZE);
|
||||
}
|
||||
|
||||
void setMessages(int messages) {
|
||||
|
@ -60,11 +60,12 @@ public final class IngestProgressSnapshotDialog extends JDialog {
|
||||
super((Window) owner, TITLE, ModalityType.MODELESS);
|
||||
if (shouldBeModal && owner instanceof JDialog) { // if called from a modal dialog, manipulate the parent be just under this in z order, and not modal.
|
||||
final JDialog pseudoOwner = (JDialog) owner;
|
||||
final ModalityType originalModality = pseudoOwner.getModalityType();
|
||||
addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosed(WindowEvent e) { // Put it back to how it was before we manipulated it.
|
||||
pseudoOwner.setVisible(false);
|
||||
pseudoOwner.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
|
||||
pseudoOwner.setModalityType(originalModality);
|
||||
pseudoOwner.toFront();
|
||||
pseudoOwner.setVisible(true);
|
||||
}
|
||||
|
@ -108,7 +108,8 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule
|
||||
@Override
|
||||
public ProcessResult process(AbstractFile abstractFile) {
|
||||
// skip the unallocated blocks
|
||||
if (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) {
|
||||
if ((abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) ||
|
||||
(abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) {
|
||||
return ProcessResult.OK;
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,8 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
|
||||
blackboard = Case.getCurrentCase().getServices().getBlackboard();
|
||||
|
||||
//skip unalloc
|
||||
if (content.getType().equals(TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) {
|
||||
if ((content.getType().equals(TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) ||
|
||||
(content.getType().equals(TSK_DB_FILES_TYPE_ENUM.SLACK)))) {
|
||||
return ProcessResult.OK;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user