Merge remote-tracking branch 'upstream/release-4.3.0'

This commit is contained in:
Richard Cordovano 2017-01-04 15:20:25 -05:00
commit 5a5d42575b
312 changed files with 30354 additions and 3598 deletions

View File

@ -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

View File

@ -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

View File

@ -1,3 +1,5 @@
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/

View File

@ -87,6 +87,7 @@ public class AddBlackboardArtifactTagAction extends AddTagAction {
"AddBlackboardArtifactTagAction.taggingErr"),
JOptionPane.ERROR_MESSAGE);
});
break;
}
}
}).start();

View File

@ -141,6 +141,7 @@ public class AddContentTagAction extends AddTagAction {
NbBundle.getMessage(this.getClass(), "AddContentTagAction.taggingErr"),
JOptionPane.ERROR_MESSAGE);
});
break;
}
}
}).start();

View File

@ -75,6 +75,7 @@ public class DeleteBlackboardArtifactTagAction extends AbstractAction {
"DeleteBlackboardArtifactTagAction.tagDelErr"),
JOptionPane.ERROR_MESSAGE);
});
break;
}
}
}).start();

View File

@ -73,6 +73,7 @@ public class DeleteContentTagAction extends AbstractAction {
NbBundle.getMessage(this.getClass(), "DeleteContentTagAction.tagDelErr"),
JOptionPane.ERROR_MESSAGE);
});
break;
}
}
}).start();

View File

@ -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,6 +93,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
datasourceProcessorsMap.remove(LocalDiskDSProcessor.getType());
}
coreDSPTypes.add(LocalFilesDSProcessor.getType());
coreDSPTypes.add(RawDSProcessor.getType());
for (String dspType : coreDSPTypes) {
typeComboBox.addItem(dspType);

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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() {

View File

@ -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.

View File

@ -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 {

View File

@ -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,8 +212,11 @@ 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;
}

View File

@ -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);

View File

@ -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;
}
}
} 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 custom startup window found, using the default"); //NON-NLS
logger.log(Level.SEVERE, "Unexpected error, no startup window chosen, using the default"); //NON-NLS
startupWindowToUse = new org.sleuthkit.autopsy.casemodule.StartupWindow();
}
}
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}
}
}

View File

@ -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,6 +49,43 @@
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" 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"/>
<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="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">
@ -56,40 +93,25 @@
<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>
</Group>
<EmptySpace min="395" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" 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>
</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="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"/>
<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="dataSourcesHideSlackCB" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideSlackCB" 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 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>
<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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>

View File

@ -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(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.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))
.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(jLabelSelectFile)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(keepCurrentViewerRB)
.addComponent(useBestViewerRB)
.addComponent(dataSourcesHideKnownCB)
.addComponent(viewsHideKnownCB)
.addGroup(jPanel1Layout.createSequentialGroup()
.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(viewsHideKnownCB))))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabelHideKnownFiles)
.addComponent(jLabelTimeDisplay)
.addComponent(jLabelHideSlackFiles)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(useLocalTimeRB)
.addComponent(useGMTTimeRB)))
.addComponent(jLabelSelectFile)
.addComponent(jLabelNumThreads)
.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())
.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
}

View File

@ -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&trade; is a digital forensics platform based on The Sleuth Kit&trade; 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 &copy; 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

View File

@ -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");
@ -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,8 +56,8 @@ 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;
/**
@ -59,15 +69,30 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
//@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.
// 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.
*/
// 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));
// }
// }
// });
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);
}
}
}
/*
* TODO (AUT-1849): Correct or remove peristent column reordering code
*
* The following three methods were added for this feature
/**
* 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.
*/
// 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";
// }
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) {
// 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) {
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 {
rowValues[rowCount][j] = properties[j].getValue();
tagFound = !prop.getValue().equals("");
} catch (IllegalAccessException | InvocationTargetException ignore) {
rowValues[rowCount][j] = "n/a"; //NON-NLS
}
break;
}
}
}
++rowCount;
}
return rowValues;
//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));
}
}
/**
* Loads the stored column order from the preference file.
*
* @return a List<Node.Property<?>> of the preferences in order
*/
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);
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;
}
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() {
SwingUtilities.invokeLater(() -> {
setupTable(nme.getNode());
}
});
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}

View File

@ -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.

View File

@ -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");
@ -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) {

View File

@ -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();
}
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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");

View File

@ -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
@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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

View File

@ -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

View File

@ -42,6 +42,8 @@ interface ContentNodeVisitor<T> {
T visit(LocalFileNode dfn);
T visit(SlackFileNode sfn);
/**
* Visitor with an implementable default behavior for all types. Override
* specific visit types to not use the default behavior.
@ -93,5 +95,10 @@ interface ContentNodeVisitor<T> {
public T visit(VirtualDirectoryNode ldn) {
return defaultVisit(ldn);
}
@Override
public T visit(SlackFileNode sfn) {
return defaultVisit(sfn);
}
}
}

View File

@ -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;
}
@ -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();
}
}

View File

@ -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;
@ -356,6 +357,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) {
return visitDir(dir);

View File

@ -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;
/**
@ -81,6 +82,23 @@ public class DataModelActionsFactory {
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<>();
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
@ -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<>();
}

View File

@ -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());
}
}

View File

@ -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,6 +323,15 @@ 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> {

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);

View File

@ -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();
}
}
/**

View 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();
}
}
}

View File

@ -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();
}
}
/**

View File

@ -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();
}
}

View File

@ -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 getClass().getName() + filter.getName() if custom
* settings are desired for different filters.
*/
// @Override
// public String getItemType() {
// return "FileSize"; //NON-NLS
// }
return DisplayableItemNode.FILE_PARENT_NODE_KEY;
}
// update the display name when new events are fired
private class FileSizeNodeObserver implements Observer {

View File

@ -1,7 +1,7 @@
/*
* 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");
@ -74,4 +74,8 @@ public class FileTypeExtensions {
public static List<String> getArchiveExtensions() {
return ARCHIVE_EXTENSIONS;
}
private FileTypeExtensions() {
}
}

View File

@ -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()));
}
});
}
}
}

View 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();
}
}
}

View File

@ -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();
}
}

View File

@ -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()));
}
});
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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() {
/**
* For custom settings for each hash set, return
* getClass().getName() + hashSetName instead.
*/
// @Override
// public String getItemType() {
// return "HashsetName"; //NON-NLS
// }
return getClass().getName();
}
}
/**

View File

@ -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();
}
}

View File

@ -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() {
/**
* For custom settings for each rule set, return
* getClass().getName() + setName instead.
*/
// @Override
// public String getItemType() {
// return "InterestingHitsSetName"; //NON-NLS
// }
return getClass().getName();
}
}
private class HitFactory extends ChildFactory<Long> implements Observer {

View File

@ -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();

View File

@ -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:

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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();
}
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View 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();
}
}

View File

@ -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)};
}
}
}

View 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();
}
}

View File

@ -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");
@ -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 {

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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());
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(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);

View File

@ -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

View File

@ -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();
}
}

View File

@ -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();
}
}
}

View 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:

View 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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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, &quot;{key}&quot;)"/>
</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="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Form>

View 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();
}
}

View File

@ -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();
}
}

View File

@ -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
@ -232,6 +237,12 @@ public class DataResultFilterNode extends FilterNode {
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;
}
}
/*
@ -323,6 +335,13 @@ public class DataResultFilterNode extends FilterNode {
return openChild(c);
}
@Override
public AbstractAction visit(FileTypesNode fileTypes) {
return openChild(fileTypes);
}
/**
* Tell the originating ExplorerManager to display the given
* dataModelNode.

View File

@ -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;
@ -226,6 +228,11 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
return visitDeep(fn);
}
@Override
public Boolean visit(SlackFileNode sfn) {
return visitDeep(sfn);
}
@Override
public Boolean visit(VolumeNode vn) {
return isLeafVolume(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> {
@ -268,10 +281,21 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
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);
}
}
}

View File

@ -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();
@ -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"),

View File

@ -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();
}
}

View File

@ -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

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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("");
}
}

View File

@ -145,6 +145,7 @@ class IngestMessagesToolbar extends javax.swing.JPanel {
if (mode != null) {
//TopComponent[] tcs = mode.getTopComponents();
mode.dockInto(tc);
String something = mode.getName();
tc.open();
//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) {

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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