diff --git a/Core/build.xml b/Core/build.xml index 6ea271b16e..00bcca3a01 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -5,11 +5,7 @@ Builds, tests, and runs the project org.sleuthkit.autopsy.core - - - - - + @@ -30,7 +26,6 @@ - diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index 718f0bb9fb..dc9774ed72 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -19,15 +19,13 @@ package org.sleuthkit.autopsy.casemodule; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.logging.Level; - import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitJNI; @@ -35,66 +33,220 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskDataException; /* - * A background task that adds the given image to database using the Sleuthkit - * JNI interface. - * - * It updates the given ProgressMonitor as it works through adding the image, - * and et the end, calls the specified Callback. + * A runnable that adds an image data source to the case database. */ class AddImageTask implements Runnable { private final Logger logger = Logger.getLogger(AddImageTask.class.getName()); - - private final Case currentCase; - - // true if the process was requested to cancel - private final Object lock = new Object(); // synchronization object for cancelRequested - private volatile boolean cancelRequested = false; - - //true if revert has been invoked. - private boolean reverted = false; - - // true if there was a critical error in adding the data source - private boolean hasCritError = false; - - private final List errorList = new ArrayList<>(); - - private final DataSourceProcessorProgressMonitor progressMonitor; - private final DataSourceProcessorCallback callbackObj; - - private final List newContents = Collections.synchronizedList(new ArrayList()); - - private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess; - private Thread dirFetcher; - + private final String deviceId; private final String imagePath; - String timeZone; - boolean noFatOrphans; - - private final String dataSourceId; + private final String timeZone; + private final boolean ignoreFatOrphanFiles; + private final DataSourceProcessorProgressMonitor progressMonitor; + private final DataSourceProcessorCallback callback; + private boolean criticalErrorOccurred; /* - * A thread that updates the progressMonitor with the name of the directory - * currently being processed by the AddImageTask + * The cancellation requested flag and SleuthKit add image process are + * guarded by a monitor (called a lock here to avoid confusion with the + * progress monitor) to synchronize cancelling the process (setting the flag + * and calling its stop method) and calling either its commit or revert + * method. The built-in monitor of the add image process can't be used for + * this because it is already used to synchronize its run (init part), + * commit, revert, and currentDirectory methods. + * + * TODO (AUT-2021): Merge SleuthkitJNI.AddImageProcess and AddImageTask */ - private class CurrentDirectoryFetcher implements Runnable { + private final Object tskAddImageProcessLock; + private boolean tskAddImageProcessStopped; + private SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess; - DataSourceProcessorProgressMonitor progressMonitor; - SleuthkitJNI.CaseDbHandle.AddImageProcess process; + /** + * Constructs a runnable task that adds an image to the 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 imagePath Path to the image file. + * @param timeZone The time zone to use when processing dates + * and times for the image, obtained from + * java.util.TimeZone.getID. + * @param ignoreFatOrphanFiles Whether to parse orphans if the image has a + * FAT filesystem. + * @param progressMonitor Progress monitor to report progress during + * processing. + * @param callback Callback to call when processing is done. + */ + AddImageTask(String deviceId, String imagePath, String timeZone, boolean ignoreFatOrphanFiles, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { + this.deviceId = deviceId; + this.imagePath = imagePath; + this.timeZone = timeZone; + this.ignoreFatOrphanFiles = ignoreFatOrphanFiles; + this.callback = callback; + this.progressMonitor = progressMonitor; + tskAddImageProcessLock = new Object(); + } - CurrentDirectoryFetcher(DataSourceProcessorProgressMonitor aProgressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess proc) { - this.progressMonitor = aProgressMonitor; - this.process = proc; + /** + * Adds the image to the case database. + */ + @Override + public void run() { + progressMonitor.setIndeterminate(true); + progressMonitor.setProgress(0); + Case currentCase = Case.getCurrentCase(); + List errorMessages = new ArrayList<>(); + List newDataSources = new ArrayList<>(); + try { + currentCase.getSleuthkitCase().acquireExclusiveLock(); + synchronized (tskAddImageProcessLock) { + tskAddImageProcess = currentCase.makeAddImageProcess(timeZone, true, ignoreFatOrphanFiles); + } + Thread progressUpdateThread = new Thread(new ProgressUpdater(progressMonitor, tskAddImageProcess)); + progressUpdateThread.start(); + runAddImageProcess(errorMessages); + if (null != progressUpdateThread) { + progressUpdateThread.interrupt(); + } + commitOrRevertAddImageProcess(currentCase, errorMessages, newDataSources); + progressMonitor.setProgress(100); + } finally { + currentCase.getSleuthkitCase().releaseExclusiveLock(); + DataSourceProcessorCallback.DataSourceProcessorResult result; + if (criticalErrorOccurred) { + result = DataSourceProcessorResult.CRITICAL_ERRORS; + } else if (!errorMessages.isEmpty()) { + result = DataSourceProcessorResult.NONCRITICAL_ERRORS; + } else { + result = DataSourceProcessorResult.NO_ERRORS; + } + callback.done(result, errorMessages, newDataSources); + } + } + + /* + * Attempts to cancel adding the image to the case database. + */ + public void cancelTask() { + synchronized (tskAddImageProcessLock) { + if (null != tskAddImageProcess) { + try { + /* + * All this does is set a flag that will make the TSK add + * image process exit when the flag is checked between + * processing steps. The state of the flag is not + * accessible, so record it here so that it is known that + * the revert method of the process object needs to be + * called. + */ + tskAddImageProcess.stop(); + tskAddImageProcessStopped = true; + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error cancelling adding image %s to the case database", imagePath), ex); //NON-NLS + } + } + } + } + + /** + * Runs the TSK add image process. + * + * @param errorMessages Error messages, if any, are added to this list for + * eventual return via the callback. + */ + private void runAddImageProcess(List errorMessages) { + try { + tskAddImageProcess.run(deviceId, new String[]{imagePath}); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Critical error occurred adding image %s", imagePath), ex); //NON-NLS + criticalErrorOccurred = true; + errorMessages.add(ex.getMessage()); + } catch (TskDataException ex) { + logger.log(Level.WARNING, String.format("Non-critical error occurred adding image %s", imagePath), ex); //NON-NLS + errorMessages.add(ex.getMessage()); + } + } + + /** + * Commits or reverts the results of the TSK add image process. If the + * process was stopped before it completed or there was a critical error the + * results are reverted, otherwise they are committed. + * + * @param currentCase The current case. + * @param errorMessages Error messages, if any, are added to this list for + * eventual return via the callback. + * @param newDataSources If the new image is successfully committed, it is + * added to this list for eventual return via the + * callback. + * + * @return + */ + private void commitOrRevertAddImageProcess(Case currentCase, List errorMessages, List newDataSources) { + synchronized (tskAddImageProcessLock) { + if (tskAddImageProcessStopped || criticalErrorOccurred) { + try { + tskAddImageProcess.revert(); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error reverting adding image %s to the case database", imagePath), ex); //NON-NLS + errorMessages.add(ex.getMessage()); + criticalErrorOccurred = true; + } + } else { + try { + long imageId = tskAddImageProcess.commit(); + if (imageId != 0) { + Image newImage = currentCase.getSleuthkitCase().getImageById(imageId); + String verificationError = newImage.verifyImageSize(); + if (!verificationError.isEmpty()) { + errorMessages.add(verificationError); + } + newDataSources.add(newImage); + } else { + String errorMessage = String.format("Error commiting adding image %s to the case database, no object id returned", imagePath); //NON-NLS + logger.log(Level.SEVERE, errorMessage); + errorMessages.add(errorMessage); + criticalErrorOccurred = true; + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error committing adding image %s to the case database", imagePath), ex); //NON-NLS + errorMessages.add(ex.getMessage()); + criticalErrorOccurred = true; + } + } + } + } + + /** + * A Runnable that updates the progress monitor with the name of the + * directory currently being processed by the SleuthKit add image process. + */ + private class ProgressUpdater implements Runnable { + + private final DataSourceProcessorProgressMonitor progressMonitor; + private final SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess; + + /** + * Constructs a Runnable that updates the progress monitor with the name + * of the directory currently being processed by the SleuthKit. + * + * @param progressMonitor + * @param tskAddImageProcess + */ + ProgressUpdater(DataSourceProcessorProgressMonitor progressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess) { + this.progressMonitor = progressMonitor; + this.tskAddImageProcess = tskAddImageProcess; } /** - * @return the currently processing directory + * Updates the progress monitor with the name of the directory currently + * being processed by the SleuthKit add image process. */ @Override public void run() { try { while (!Thread.currentThread().isInterrupted()) { - String currDir = process.currentDirectory(); + String currDir = tskAddImageProcess.currentDirectory(); if (currDir != null) { if (!currDir.isEmpty()) { progressMonitor.setProgressText( @@ -102,227 +254,20 @@ class AddImageTask implements Runnable { currDir)); } } - // this sleep here prevents the UI from locking up - // due to too frequent updates to the progressMonitor above + /* + * The sleep here throttles the UI updates and provides a + * non-standard mechanism for completing this task by + * interrupting the thread in which it is running. + * + * TODO (AUT-1870): Replace this with giving the task to a + * java.util.concurrent.ScheduledThreadPoolExecutor that is + * shut down when the main task completes. + */ Thread.sleep(500); } - } catch (InterruptedException ie) { - // nothing to do, thread was interrupted externally - // signaling the end of AddImageProcess + } catch (InterruptedException expected) { } } } - /** - * Constructs a runnable task that adds an image to the case database. - * - * @param dataSourceId An ASCII-printable identifier for the data - * source that is intended to be unique across - * multiple cases (e.g., a UUID). - * @param imagePath Path to the image file. - * @param timeZone The time zone to use when processing dates - * and times for the image, obtained from - * java.util.TimeZone.getID. - * @param ignoreFatOrphanFiles Whether to parse orphans if the image has a - * FAT filesystem. - * @param monitor Progress monitor to report progress during - * processing. - * @param cbObj Callback to call when processing is done. - */ - AddImageTask(String dataSourceId, String imagePath, String timeZone, boolean ignoreFatOrphanFiles, DataSourceProcessorProgressMonitor monitor, DataSourceProcessorCallback cbObj) { - currentCase = Case.getCurrentCase(); - this.dataSourceId = dataSourceId; - this.imagePath = imagePath; - this.timeZone = timeZone; - this.noFatOrphans = ignoreFatOrphanFiles; - this.callbackObj = cbObj; - this.progressMonitor = monitor; - } - - /** - * Starts the addImage process, but does not commit the results. - * - * @return - * - * @throws Exception - */ - @Override - public void run() { - errorList.clear(); - try { - currentCase.getSleuthkitCase().acquireExclusiveLock(); - addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans); - dirFetcher = new Thread(new CurrentDirectoryFetcher(progressMonitor, addImageProcess)); - try { - progressMonitor.setIndeterminate(true); - progressMonitor.setProgress(0); - dirFetcher.start(); - addImageProcess.run(dataSourceId, new String[]{imagePath}); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Core errors occurred while running add image on " + imagePath, ex); //NON-NLS - hasCritError = true; - errorList.add(ex.getMessage()); - } catch (TskDataException ex) { - logger.log(Level.WARNING, "Data errors occurred while running add image " + imagePath, ex); //NON-NLS - errorList.add(ex.getMessage()); - } - postProcess(); - } finally { - currentCase.getSleuthkitCase().releaseExclusiveLock(); - } - } - - /** - * Commit the newly added image to DB - * - * - * @throws Exception if commit or adding the image to the case failed - */ - private void commitImage() throws Exception { - - long imageId = 0; - try { - imageId = addImageProcess.commit(); - } catch (TskCoreException e) { - logger.log(Level.WARNING, "Errors occurred while committing the image " + imagePath, e); //NON-NLS - errorList.add(e.getMessage()); - } finally { - if (imageId != 0) { - // get the newly added Image so we can return to caller - Image newImage = currentCase.getSleuthkitCase().getImageById(imageId); - - //while we have the image, verify the size of its contents - String verificationErrors = newImage.verifyImageSize(); - if (verificationErrors.equals("") == false) { - //data error (non-critical) - errorList.add(verificationErrors); - } - - // Add the image to the list of new content - newContents.add(newImage); - } - - logger.log(Level.INFO, "Image committed, imageId: {0}", imageId); //NON-NLS - logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo()); - } - } - - /** - * Post processing after the addImageProcess is done. - * - */ - private void postProcess() { - - // cancel the directory fetcher - dirFetcher.interrupt(); - - if (cancelRequested() || hasCritError) { - logger.log(Level.WARNING, "Critical errors or interruption in add image process on {0}. Image will not be committed.", imagePath); //NON-NLS - revert(); - } - - if (!errorList.isEmpty()) { - logger.log(Level.INFO, "There were errors that occurred in add image process for {0}", imagePath); //NON-NLS - } - - // When everything happens without an error: - if (!(cancelRequested() || hasCritError)) { - try { - if (addImageProcess != null) { - // commit image - try { - commitImage(); - } catch (Exception ex) { - errorList.add(ex.getMessage()); - // Log error/display warning - logger.log(Level.SEVERE, "Error adding image " + imagePath + " to case.", ex); //NON-NLS - } - } else { - logger.log(Level.SEVERE, "Missing image process object"); //NON-NLS - } - - // Tell the progress monitor we're done - progressMonitor.setProgress(100); - } catch (Exception ex) { - //handle unchecked exceptions post image add - errorList.add(ex.getMessage()); - - logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup for " + imagePath, ex); //NON-NLS - logger.log(Level.SEVERE, "Error adding image " + imagePath + " to case", ex); //NON-NLS - } - } - - // invoke the callBack, unless the caller cancelled - if (!cancelRequested()) { - doCallBack(); - } - } - - /* - * Call the callback with results, new content, and errors, if any - */ - private void doCallBack() { - DataSourceProcessorCallback.DataSourceProcessorResult result; - - if (hasCritError) { - result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; - } else if (!errorList.isEmpty()) { - result = DataSourceProcessorCallback.DataSourceProcessorResult.NONCRITICAL_ERRORS; - } else { - result = DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS; - } - - // invoke the callback, passing it the result, list of new contents, and list of errors - callbackObj.done(result, errorList, newContents); - } - - /* - * cancel the image addition, if possible - */ - public void cancelTask() { - - synchronized (lock) { - cancelRequested = true; - try { - interrupt(); - } catch (Exception ex) { - logger.log(Level.SEVERE, "Failed to interrupt the add image task..."); //NON-NLS - } - } - } - - /* - * Interrupt the add image process if it is still running - */ - private void interrupt() throws Exception { - - try { - logger.log(Level.INFO, "interrupt() add image process"); //NON-NLS - addImageProcess.stop(); //it might take time to truly stop processing and writing to db - } catch (TskCoreException ex) { - throw new Exception(NbBundle.getMessage(this.getClass(), "AddImageTask.interrupt.exception.msg"), ex); - } - } - - /* - * Revert - if image has already been added but not committed yet - */ - private void revert() { - - if (!reverted) { - logger.log(Level.INFO, "Revert after add image process"); //NON-NLS - try { - addImageProcess.revert(); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error reverting add image process", ex); //NON-NLS - } - reverted = true; - } - } - - private boolean cancelRequested() { - synchronized (lock) { - return cancelRequested; - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java index 1db3ab9c5c..489c713af8 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java @@ -146,6 +146,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { * * @param panel instance of ImageTypePanel to change to */ + @SuppressWarnings("deprecation") private void updateCurrentPanel(JPanel panel) { currentPanel = panel; typePanel.removeAll(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index 46114c52fb..6e1d353e22 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -68,6 +68,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel errList, List contents) { dataSourceProcessorDone(dataSourceId, result, errList, contents); } - }; progressPanel.setStateStarted(); @@ -258,9 +259,6 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel { - Case.getCurrentCase().notifyFailedAddingDataSource(dataSourceId); - }).start(); dsProcessor.cancel(); } @@ -303,21 +301,23 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel { - if (!newContents.isEmpty()) { - Case.getCurrentCase().notifyDataSourceAdded(newContents.get(0), dataSourceId); + if (!contents.isEmpty()) { + Case.getCurrentCase().notifyDataSourceAdded(contents.get(0), dataSourceId); } else { Case.getCurrentCase().notifyFailedAddingDataSource(dataSourceId); } }).start(); - // Start ingest if we can - progressPanel.setStateStarted(); - startIngest(); + if (!cancelled) { + newContents.clear(); + newContents.addAll(contents); + progressPanel.setStateStarted(); + startIngest(); + } else { + cancelled = false; + } } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 6d0aca0f6e..6615cde7e6 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -219,11 +219,11 @@ public class Case implements SleuthkitCase.ErrorObserver { * multi-user (using PostgreSql) */ @NbBundle.Messages({"Case_caseType_singleUser=Single-user case", - "Case_caseType_multiUser=Multi-user case"}) + "Case_caseType_multiUser=Multi-user case"}) public enum CaseType { - SINGLE_USER_CASE(Bundle.Case_caseType_singleUser()), - MULTI_USER_CASE(Bundle.Case_caseType_multiUser()); + SINGLE_USER_CASE("Single-user case"), //NON-NLS + MULTI_USER_CASE("Multi-user case"); //NON-NLS private final String caseType; @@ -250,6 +250,14 @@ public class Case implements SleuthkitCase.ErrorObserver { public String toString() { return caseType; } + + String getLocalizedDisplayName() { + if (fromString(caseType) == SINGLE_USER_CASE) { + return Bundle.Case_caseType_singleUser(); + } else { + return Bundle.Case_caseType_multiUser(); + } + } }; private String name; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java index c9c4d87864..eae7cf228d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java @@ -92,7 +92,7 @@ class CasePropertiesForm extends javax.swing.JPanel { CaseMetadata caseMetadata = new CaseMetadata(Paths.get(currentCase.getConfigFilePath())); tbDbName.setText(caseMetadata.getCaseDatabaseName()); Case.CaseType caseType = caseMetadata.getCaseType(); - tbDbType.setText(caseType.toString()); + tbDbType.setText(caseType.getLocalizedDisplayName()); if (caseType == Case.CaseType.SINGLE_USER_CASE) { deleteCaseButton.setEnabled(true); } else { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java b/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java index 0fb3601d88..afa68ac5c3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CollaborationMonitor.java @@ -466,7 +466,11 @@ final class CollaborationMonitor { */ @Override public void run() { - eventPublisher.publishRemotely(new CollaborationEvent(hostName, localTasksManager.getCurrentTasks())); + try { + eventPublisher.publishRemotely(new CollaborationEvent(hostName, localTasksManager.getCurrentTasks())); + } catch (Exception ex) { + logger.log(Level.SEVERE, "Unexpected exception in HeartbeatTask", ex); //NON-NLS + } } } @@ -482,7 +486,11 @@ final class CollaborationMonitor { */ @Override public void run() { - remoteTasksManager.finishStaleTasks(); + try { + remoteTasksManager.finishStaleTasks(); + } catch (Exception ex) { + logger.log(Level.SEVERE, "Unexpected exception in StaleTaskDetectionTask", ex); //NON-NLS + } } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index be3c9466a7..fa9f92188c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -31,7 +31,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; /** - * An image file data source processor that implements the DataSourceProcessor + * A image file 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. @@ -81,10 +81,10 @@ public class ImageDSProcessor implements DataSourceProcessor { /** * Gets a string that describes the type of data sources this processor is - * able to process. + * 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 string suitable for display in a data source processor - * selection UI component (e.g., a combo box). + * @return A data source type display string for this data source processor. */ public static String getType() { return DATA_SOURCE_TYPE; @@ -92,21 +92,23 @@ public class ImageDSProcessor implements DataSourceProcessor { /** * Gets a string that describes the type of data sources this processor is - * able to process. + * 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 string suitable for display in a data source processor - * 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 DATA_SOURCE_TYPE; + return getType(); } /** * Gets the panel that allows a user to select a data source and do any - * configuration the data source processor may require. + * configuration required by the data source. The panel is less than 544 + * pixels wide and less than 173 pixels high. * - * @return A JPanel less than 544 pixels wide and 173 pixels high. + * @return A selection and configuration panel for this data source + * processor. */ @Override public JPanel getPanel() { @@ -116,10 +118,11 @@ public class ImageDSProcessor implements DataSourceProcessor { } /** - * Indicates whether the settings in the panel are valid and complete. + * 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. + * ready to have its run method called, false otherwise. */ @Override public boolean isPanelValid() { @@ -127,16 +130,18 @@ public class ImageDSProcessor implements DataSourceProcessor { } /** - * Adds a data source to the case database using a separate thread and the - * settings provided by the panel. Returns as soon as the background task is - * started and uses the callback object to signal task completion and return - * results. + * 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. * - * NOTE: This method should not be called unless isPanelValid returns true. + * This method should not be called unless isPanelValid returns true. * - * @param progressMonitor Progress monitor for reporting progress during - * processing. - * @param callback Callback to call when processing is done. + * @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) { @@ -151,10 +156,11 @@ public class ImageDSProcessor implements DataSourceProcessor { } /** - * Adds a data source to the case database using a separate thread and the - * given settings instead of those provided by the panel. Returns as soon as - * the background task is started and uses the callback object to signal - * task completion and return results. + * 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 @@ -176,8 +182,11 @@ public class ImageDSProcessor implements DataSourceProcessor { } /** - * Requests cancellation of the data source processing task after it is - * started using the run method. Cancellation is not guaranteed. + * Requests cancellation of the background task that adds a data source to + * the case database, after the task is started using the run method. This + * is a "best effort" cancellation, with no guarantees that the case + * database will be unchanged. If cancellation succeeded, the list of new + * data sources returned by the background task will be empty. */ @Override public void cancel() { @@ -185,7 +194,8 @@ public class ImageDSProcessor implements DataSourceProcessor { } /** - * Resets the panel. + * Resets the selection and configuration panel for this data source + * processor. */ @Override public void reset() { @@ -199,7 +209,7 @@ public class ImageDSProcessor implements DataSourceProcessor { /** * Sets the configuration of the data source processor without using the - * configuration panel. + * selection and configuration panel. * * @param imagePath Path to the image file. * @param timeZone The time zone to use when processing dates diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 4d59cd4d91..5c7cca0a59 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -190,7 +190,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //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 diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java index cb80535e01..c699eb740d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java @@ -61,10 +61,10 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { /** * Gets a string that describes the type of data sources this processor is - * able to process. + * 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 string suitable for display in a data source processor - * selection UI component (e.g., a combo box). + * @return A data source type display string for this data source processor. */ public static String getType() { return DATA_SOURCE_TYPE; @@ -72,10 +72,10 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { /** * Gets a string that describes the type of data sources this processor is - * able to process. + * 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 string suitable for display in a data source processor - * selection UI component (e.g., a combo box). + * @return A data source type display string for this data source processor. */ @Override public String getDataSourceType() { @@ -83,10 +83,12 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { } /** - * Gets the JPanel that allows a user to select a data source and do any - * configuration the data source processor may require. + * 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 JPanel less than 544 pixels wide and 173 pixels high. + * @return A selection and configuration panel for this data source + * processor. */ @Override public JPanel getPanel() { @@ -95,10 +97,11 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { } /** - * Indicates whether the settings in the panel are valid and complete. + * 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. + * ready to have its run method called, false otherwise. */ @Override public boolean isPanelValid() { @@ -106,16 +109,18 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { } /** - * Adds a data source to the case database using a separate thread and the - * settings provided by the panel. Returns as soon as the background task is - * started and uses the callback object to signal task completion and return - * results. + * 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. * - * NOTE: This method should not be called unless isPanelValid returns true. + * This method should not be called unless isPanelValid returns true. * - * @param progressMonitor Progress monitor for reporting progress during - * processing. - * @param callback Callback to call when processing is done. + * @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) { @@ -130,10 +135,11 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { } /** - * Adds a data source to the case database using a separate thread and the - * given settings instead of those provided by the panel. Returns as soon as - * the background task is started and uses the callback object to signal - * task completion and return results. + * 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 @@ -155,8 +161,11 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { } /** - * Requests cancellation of the data source processing task after it is - * started using the run method. Cancellation is not guaranteed. + * Requests cancellation of the background task that adds a data source to + * the case database, after the task is started using the run method. This + * is a "best effort" cancellation, with no guarantees that the case + * database will be unchanged. If cancellation succeeded, the list of new + * data sources returned by the background task will be empty. */ @Override public void cancel() { @@ -164,7 +173,8 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { } /** - * Resets the panel. + * Resets the selection and configuration panel for this data source + * processor. */ @Override public void reset() { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java index 6d5c028cbb..4eae9e4e7e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java @@ -59,10 +59,10 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { /** * Gets a string that describes the type of data sources this processor is - * able to process. + * 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 string suitable for display in a data source processor - * selection UI component (e.g., a combo box). + * @return A data source type display string for this data source processor. */ public static String getType() { return DATA_SOURCE_TYPE; @@ -70,10 +70,10 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { /** * Gets a string that describes the type of data sources this processor is - * able to process. + * 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 string suitable for display in a data source processor - * selection UI component (e.g., a combo box). + * @return A data source type display string for this data source processor. */ @Override public String getDataSourceType() { @@ -82,9 +82,11 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { /** * Gets the panel that allows a user to select a data source and do any - * configuration the data source processor may require. + * configuration required by the data source. The panel is less than 544 + * pixels wide and less than 173 pixels high. * - * @return A JPanel less than 544 pixels wide and 173 pixels high. + * @return A selection and configuration panel for this data source + * processor. */ @Override public JPanel getPanel() { @@ -93,10 +95,11 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { } /** - * Indicates whether the settings in the panel are valid and complete. + * 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. + * ready to have its run method called, false otherwise. */ @Override public boolean isPanelValid() { @@ -104,16 +107,18 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { } /** - * Adds a data source to the case database using a separate thread and the - * settings provided by the panel. Returns as soon as the background task is - * started and uses the callback object to signal task completion and return - * results. + * 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. * - * NOTE: This method should not be called unless isPanelValid returns true. + * This method should not be called unless isPanelValid returns true. * - * @param progressMonitor Progress monitor for reporting progress during - * processing. - * @param callback Callback to call when processing is done. + * @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) { @@ -125,10 +130,11 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { } /** - * Adds a data source to the case database using a separate thread and the - * given settings instead of those provided by the panel. Returns as soon as - * the background task is started and uses the callback object to signal - * task completion and return results. + * 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 @@ -151,18 +157,22 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { } /** - * Requests cancellation of the data source processing task after it is - * started using the run method. Cancellation is not guaranteed. + * Requests cancellation of the background task that adds a data source to + * the case database, after the task is started using the run method. This + * is a "best effort" cancellation, with no guarantees that the case + * database will be unchanged. If cancellation succeeded, the list of new + * data sources returned by the background task will be empty. + * + * TODO (AUT-1907): Implement cancellation by deleting rows added to the + * case database. */ @Override public void cancel() { - /* - * Cancellation is not currently supported. - */ } /** - * Resets the panel. + * Resets the selection and configuration panel for this data source + * processor. */ @Override public void reset() { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java index b7b432a9eb..24c1e2a17e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardPanel1.java @@ -239,7 +239,7 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,56 +23,72 @@ import java.util.List; import org.sleuthkit.datamodel.Content; /** - * Abstract class for a callback for a DataSourceProcessor. - * - * Ensures that DSP invokes the caller overridden method, doneEDT(), in the EDT - * thread. + * An abstract base class for callback objects to be given to data source + * processors for use by the background tasks that add data sources to a case + * database. The callback objects are used to signal task completion and return + * results. * + * Concrete implementations of DataSourceProcessorCallback should override + * either the done method or the doneEDT method, but not both. */ public abstract class DataSourceProcessorCallback { public enum DataSourceProcessorResult { - NO_ERRORS, ///< No errors were encountered while ading the data source - CRITICAL_ERRORS, ///< No data was added to the database. There were fundamental errors processing the data (such as no data or system failure). - NONCRITICAL_ERRORS, ///< There was data added to the database, but there were errors from data corruption or a small number of minor issues. + /** + * No errors occurred while ading the data source to the case database. + */ + NO_ERRORS, + /** + * Critical errors occurred while ading the data source to the case + * database. The data source was not added to the case database. + */ + CRITICAL_ERRORS, + /** + * Non-critical errors occurred while adding the data source to the case + * database. The data source was added to the database, but the data + * source may have been corrupted in some way. + */ + NONCRITICAL_ERRORS }; /** - * Called by a DSP implementation when it is done adding a data source to - * the database. Users of the DSP can override this method if they do not - * want to be notified on the EDT. Otherwise, this method will call - * doneEDT() with the same arguments. + * Called by a data source processor when it is done adding a data source to + * the case database, this method adds a task to call the doneEDT method to + * the EDT task queue. * - * @param result Code for status - * @param errList List of error strings - * @param newContents List of root Content objects that were added to - * database. Typically only one is given. + * IMPORTANT: Concrete implementations of DataSourceProcessorCallback should + * override this method if the callback SHOULD NOT be done in the EDT. + * + * @param result Result code. + * @param errList List of error messages, possibly empty. + * @param newDataSources A list of the data sources added, empty if critical + * errors occurred or processing was successfully + * cancelled. */ - public void done(DataSourceProcessorResult result, List errList, List newContents) { - + public void done(DataSourceProcessorResult result, List errList, List newDataSources) { final DataSourceProcessorResult resultf = result; final List errListf = errList; - final List newContentsf = newContents; - - // Invoke doneEDT() that runs on the EDT . - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - doneEDT(resultf, errListf, newContentsf); - } + final List newContentsf = newDataSources; + EventQueue.invokeLater(() -> { + doneEDT(resultf, errListf, newContentsf); }); } /** - * Called by done() if the default implementation is used. Users of DSPs - * that have UI updates to do after the DSP is finished adding the DS can - * implement this method to receive the updates on the EDT. + * Called by a data source processor when it is done adding a data source to + * the case database, if the default done method has not been overridden. * - * @param result Code for status - * @param errList List of error strings - * @param newContents List of root Content objects that were added to - * database. Typically only one is given. + * IMPORTANT: Concrete implementations of DataSourceProcessorCallback should + * override the done method and provide an implementation of this method + * that throws an UnsupportedOperationException if the callback SHOULD NOT + * be done in the EDT. + * + * @param result Result code. + * @param errList List of error messages, possibly empty. + * @param newDataSources A list of the data sources added, empty if critical + * errors occurred or processing was successfully + * cancelled. */ - public abstract void doneEDT(DataSourceProcessorResult result, List errList, List newContents); + abstract public void doneEDT(DataSourceProcessorResult result, List errList, List newDataSources); }; diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowPanel.java index 04501c4c5b..3584cb5211 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AboutWindowPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -47,16 +47,22 @@ import org.sleuthkit.datamodel.SleuthkitJNI; */ public final class AboutWindowPanel extends JPanel implements HyperlinkListener { - private static final Logger Logger = org.sleuthkit.autopsy.coreutils.Logger.getLogger(AboutWindowPanel.class.getName()); - + private static final long serialVersionUID = 1L; private URL url = null; - - private Icon about; - + private final Icon about; private boolean verboseLogging; + public AboutWindowPanel() { + about = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/splash.png")); + init(); + } + public AboutWindowPanel(String pathToBrandingImage) { about = new ImageIcon(ImageUtilities.loadImage(pathToBrandingImage)); + init(); + } + + private void init() { initComponents(); logoLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); description.setText(org.openide.util.NbBundle.getMessage(AboutWindowPanel.class, @@ -67,8 +73,7 @@ public final class AboutWindowPanel extends JPanel implements HyperlinkListener copyright.setBackground(getBackground()); if (verboseLoggingIsSet()) { disableVerboseLoggingButton(); - } - + } } // //GEN-BEGIN:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 2db3a4d69b..a0aeb51314 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -148,7 +148,7 @@ FXVideoPanel.progress.bufferingCancelled=media buffering was canceled FXVideoPanel.progress.bufferingInterrupted=media buffering was interrupted FXVideoPanel.progress.errorWritingVideoToDisk=Error writing video to disk OptionsCategory_Name_Multi_User_Settings=Multi-user -OptionsCategory_Keywords_Multi_User_Options=Multi-user Options +OptionsCategory_Keywords_Multi_User_Options=Multi-user Settings MultiUserSettingsPanel.lbSolrSettings.text=Solr Settings MultiUserSettingsPanel.cbEnableMultiUser.text=Enable Multi-user cases MultiUserSettingsPanel.lbDatabaseSettings.text=Database Settings diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java index 635a8b0e37..c7226483ef 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java @@ -488,7 +488,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat // if the artifact has an ASSOCIATED ARTIFACT, then we display the associated artifact instead try { for (BlackboardAttribute attr : artifact.getAttributes()) { - if (attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) { + if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) { long assocArtifactId = attr.getValueLong(); int assocArtifactIndex = -1; for (BlackboardArtifact art : artifacts) { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterChildren.java b/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterChildren.java index bcb1657314..753483e42c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterChildren.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterChildren.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,38 +23,67 @@ import org.openide.nodes.FilterNode; import org.openide.nodes.Node; /** - * Complementary class to TableFilterNode. + * A children (child factory) implementation for a TableFilterNode. A + * TableFilterNode 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. */ class TableFilterChildren extends FilterNode.Children { /** - * the constructor + * Constructs a children (child factory) implementation for a + * TableFilterNode. A TableFilterNode 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. + * + * @param wrappedNode The node wrapped by the TableFilterNode. */ - TableFilterChildren(Node arg) { - super(arg); - } - - @Override - protected Node copyNode(Node arg0) { - return new TableFilterNode(arg0, false); - } - - @Override - protected Node[] createNodes(Node arg0) { - // filter out the children - return new Node[]{this.copyNode(arg0)}; + TableFilterChildren(Node wrappedNode) { + super(wrappedNode); } /** - * Converts the given FsContent into "Children". + * Copies a TableFilterNode, with the create children (child factory) flag + * set to false. * - * @param fs + * @param nodeToCopy The TableFilterNode to copy. * - * @return children + * @return A copy of a TableFilterNode. */ - public static Children createInstance(Node arg, boolean createChild) { - if (createChild) { - return new TableFilterChildren(arg); + @Override + protected Node copyNode(Node nodeToCopy) { + return new TableFilterNode(nodeToCopy, false); + } + + /** + * Creates the child nodes represented by this children (child factory) + * object. + * + * @param key The key, i.e., the node, for which to create the child nodes. + * + * @return + */ + @Override + protected Node[] createNodes(Node key) { + return new Node[]{this.copyNode(key)}; + } + + /** + * Creates a children (child factory) object for a node wrapped in a + * TableFilterNode. A TableFilterNode 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. + * + * + * @param wrappedNode The node wrapped by the TableFilterNode. + * @param createChildren True if a children (child factory) object should be + * created for the wrapped node. + * + * @return A children (child factory) object for a node wrapped by a + * TableFilterNode. + */ + public static Children createInstance(Node wrappedNode, boolean createChildren) { + if (createChildren) { + return new TableFilterChildren(wrappedNode); } else { return Children.LEAF; } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterNode.java b/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterNode.java index 11caf66c75..9a524bcbd3 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,48 +23,40 @@ import org.openide.nodes.Node; import org.openide.util.NbBundle; /** - * This class is used to filter the nodes that we want to show on the - * "TreeTableView". So basically we just want to show one layer of nodes from - * it's parent. - * - * @author jantonius + * 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. */ public class TableFilterNode extends FilterNode { - private boolean createChild; - private String itemType; + private final boolean createChildren; /** - * the constructor - */ - public TableFilterNode(Node arg, boolean crChild) { - super(arg, TableFilterChildren.createInstance(arg, crChild)); - this.createChild = crChild; - this.itemType = ""; - } - - public TableFilterNode(Node arg, boolean crChild, String itemType) { - super(arg, TableFilterChildren.createInstance(arg, crChild)); - this.createChild = crChild; - this.itemType = itemType; - } - - /** - * Override the display name / header for the first (tree) column on the - * "TreeTableView". + * Constructs 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. * - * @return disName the display name for the first column + * @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. + */ + public TableFilterNode(Node wrappedNode, boolean createChildren) { + super(wrappedNode, TableFilterChildren.createInstance(wrappedNode, createChildren)); + this.createChildren = createChildren; + } + + /** + * Returns a display name for the wrapped node, for use in the first column + * of an Autopsy table view. + * + * @return The display name. */ @Override public String getDisplayName() { - if (createChild) { + if (createChildren) { return NbBundle.getMessage(this.getClass(), "TableFilterNode.displayName.text"); } else { return super.getDisplayName(); } } - - public String getItemType() { - return itemType; - } + } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java index 502a7828a4..db8607cd93 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java @@ -72,19 +72,19 @@ public class ArtifactStringContent implements StringContent { // name column buffer.append(""); //NON-NLS - buffer.append(attr.getAttributeTypeDisplayName()); + buffer.append(attr.getAttributeType().getDisplayName()); buffer.append(""); //NON-NLS // value column buffer.append(""); //NON-NLS - if (attr.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID() - || attr.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID() - || attr.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID() - || attr.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED.getTypeID() - || attr.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_RCVD.getTypeID() - || attr.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID() - || attr.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID() - || attr.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID()) { + if (attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID() + || attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID() + || attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID() + || attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED.getTypeID() + || attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_RCVD.getTypeID() + || attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID() + || attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID() + || attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID()) { long epoch = attr.getValueLong(); String time = "0000-00-00 00:00:00"; if (epoch != 0) { @@ -93,7 +93,7 @@ public class ArtifactStringContent implements StringContent { } buffer.append(time); } else { - switch (attr.getValueType()) { + switch (attr.getAttributeType().getValueType()) { case STRING: String str = attr.getValueString(); str = str.replaceAll(" ", " "); //NON-NLS @@ -117,7 +117,7 @@ public class ArtifactStringContent implements StringContent { case DATETIME: buffer.append(attr.getValueLong()); break; - + } } if (!"".equals(attr.getContext())) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 198baaf923..7101b3c023 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -117,7 +117,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode { if (artifact != null && artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { try { for (BlackboardAttribute attribute : artifact.getAttributes()) { - if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) { + if (attribute.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) { BlackboardArtifact associatedArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong()); if (associatedArtifact != null) { displayName = associatedArtifact.getDisplayName() + " Artifact"; // NON-NLS @@ -171,7 +171,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode { AbstractFile af = (AbstractFile) associated; ext = af.getNameExtension(); actualMimeType = af.getMIMEType(); - if(actualMimeType == null) { + if (actualMimeType == null) { actualMimeType = ""; } } @@ -179,11 +179,11 @@ public class BlackboardArtifactNode extends DisplayableItemNode { NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.ext.displayName"), NO_DESCR, ext)); - ss.put(new NodeProperty<>( - NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.mimeType.name"), - NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.mimeType.displayName"), - NO_DESCR, - actualMimeType)); + ss.put(new NodeProperty<>( + NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.mimeType.name"), + NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.mimeType.displayName"), + NO_DESCR, + actualMimeType)); } if (Arrays.asList(SHOW_UNIQUE_PATH).contains(artifactTypeId)) { @@ -282,8 +282,8 @@ public class BlackboardArtifactNode extends DisplayableItemNode { /** * Fill map with Artifact properties * - * @param map map with preserved ordering, where property names/values are - * put + * @param map map with preserved ordering, where property names/values + * are put * @param artifact to extract properties from */ @SuppressWarnings("deprecation") // TODO: Remove this when TSK_TAGGED_ARTIFACT rows are removed in a database upgrade. @@ -384,7 +384,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode { String keyword = null; String regexp = null; for (BlackboardAttribute att : attributes) { - final int attributeTypeID = att.getAttributeTypeID(); + final int attributeTypeID = att.getAttributeType().getTypeID(); if (attributeTypeID == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) { keyword = att.getValueString(); } else if (attributeTypeID == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()) { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index e4c34ebce9..52b1954188 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -271,8 +271,8 @@ public class DataResultFilterNode extends FilterNode { Content c = null; try { for (BlackboardAttribute attr : art.getAttributes()) { - if (attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()) { - switch (attr.getValueType()) { + if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()) { + switch (attr.getAttributeType().getValueType()) { case INTEGER: int i = attr.getValueInt(); if (i != -1) { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index cabc5cc3d4..57de4e760e 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -865,7 +865,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat String setName = null; List attributes = art.getAttributes(); for (BlackboardAttribute att : attributes) { - int typeId = att.getAttributeTypeID(); + int typeId = att.getAttributeType().getTypeID(); if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { setName = att.getValueString(); } @@ -882,7 +882,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat String keywordName = null; List attributes = art.getAttributes(); for (BlackboardAttribute att : attributes) { - int typeId = att.getAttributeTypeID(); + int typeId = att.getAttributeType().getTypeID(); if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { listName = att.getValueString(); } else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) { @@ -909,7 +909,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat String setName = null; List attributes = art.getAttributes(); for (BlackboardAttribute att : attributes) { - int typeId = att.getAttributeTypeID(); + int typeId = att.getAttributeType().getTypeID(); if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { setName = att.getValueString(); } diff --git a/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java b/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java index 6b679415f9..5fe17a57ef 100644 --- a/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java +++ b/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java @@ -40,7 +40,7 @@ public final class AutopsyEventPublisher { * Composed of thread-safe objects. */ private static final Logger logger = Logger.getLogger(AutopsyEventPublisher.class.getName()); - private static final int MAX_REMOTE_EVENT_PUBLISH_TRIES = 3; + private static final int MAX_REMOTE_EVENT_PUBLISH_TRIES = 1; private final LocalEventPublisher localPublisher; private RemoteEventPublisher remotePublisher; private String currentChannelName; @@ -86,15 +86,8 @@ public final class AutopsyEventPublisher { * events from other Autopsy nodes. */ public void closeRemoteEventChannel() { + stopRemotePublisher(); currentChannelName = null; - if (null != remotePublisher) { - try { - remotePublisher.stop(); - } catch (JMSException ex) { - logger.log(Level.SEVERE, "Error closing remote event channel", ex); //NON-NLS - } - remotePublisher = null; - } } /** @@ -162,12 +155,10 @@ public final class AutopsyEventPublisher { * @param event The event to publish. */ public void publishRemotely(AutopsyEvent event) { - /* - * This is a no-op if a remote channel has not been opened. - */ if (null != currentChannelName) { boolean published = false; int tryCount = 1; + while (false == published && tryCount <= MAX_REMOTE_EVENT_PUBLISH_TRIES) { try { if (null == remotePublisher) { @@ -175,16 +166,28 @@ public final class AutopsyEventPublisher { } remotePublisher.publish(event); published = true; - } catch (JMSException ex) { + } catch (AutopsyEventException | JMSException ex) { logger.log(Level.SEVERE, String.format("Failed to publish %s using channel %s (tryCount = %s)", event.getPropertyName(), currentChannelName, tryCount), ex); //NON-NLS - closeRemoteEventChannel(); - ++tryCount; - } catch (AutopsyEventException ex) { - logger.log(Level.SEVERE, String.format("Failed to reopen channel %s to publish %s event (tryCount = %s)", currentChannelName, event.getPropertyName(), tryCount), ex); //NON-NLS + stopRemotePublisher(); ++tryCount; } } - } + } + } + + /** + * Stops the remote event publisher, but does not reset the current channel + * name. + */ + private void stopRemotePublisher() { + if (null != remotePublisher) { + try { + remotePublisher.stop(); + } catch (JMSException ex) { + logger.log(Level.SEVERE, String.format("Error closing remote event publisher for channel %s", currentChannelName), ex); //NON-NLS + } + remotePublisher = null; + } } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index ba1e445d8a..ad71c7e523 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -115,5 +115,5 @@ IngestJob.cancelReason.notCancelled.text=Not cancelled IngestJob.cancelReason.cancelledByUser.text=Cancelled by user IngestJob.cancelReason.ingestModStartFail.text=Ingest modules startup failed IngestJob.cancelReason.outOfDiskSpace.text=Out of disk space -IngestJob.cancelReason.servicesDown.text=Not cancelled +IngestJob.cancelReason.servicesDown.text=Services Down IngestJob.cancelReason.caseClosed.text=Case closed diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties index b11134b1ac..68034d6409 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties @@ -1,116 +1,115 @@ -CTL_IngestMessageTopComponent=\u30E1\u30C3\u30BB\u30FC\u30B8 -HINT_IngestMessageTopComponent=\u30E1\u30C3\u30BB\u30FC\u30B8\u30A6\u30A3\u30F3\u30C9\u30A6 -IngestDialog.closeButton.title=\u9589\u3058\u308B -IngestDialog.startButton.title=\u958B\u59CB -IngestDialog.title.text=\u30E2\u30B8\u30E5\u30FC\u30EB\u3092\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8 -IngestJob.progress.cancelling={0}\uFF08\u30AD\u30E3\u30F3\u30BB\u30EB\u4E2D\u2026\uFF09 -IngestJob.progress.dataSourceIngest.displayName={1}\u306E{0} -IngestJob.progress.fileIngest.displayName={0}\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u89E3\u6790\u4E2D -IngestManager.moduleErr=\u30E2\u30B8\u30E5\u30FC\u30EB\u30A8\u30E9\u30FC -IngestManager.moduleErr.errListenToUpdates.msg=Ingest Manager\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u3092\u78BA\u8A8D\u4E2D\u306B\u30E2\u30B8\u30E5\u30FC\u30EB\u304C\u30A8\u30E9\u30FC\u3092\u8D77\u3053\u3057\u307E\u3057\u305F\u3002\u3069\u306E\u30E2\u30B8\u30E5\u30FC\u30EB\u304B\u30ED\u30B0\u3092\u78BA\u8A8D\u3057\u3066\u4E0B\u3055\u3044\u3002\u4E00\u90E8\u306E\u30C7\u30FC\u30BF\u304C\u4E0D\u5B8C\u5168\u304B\u3082\u3057\u308C\u307E\u305B\u3093\u3002 -IngestManager.StartIngestJobsTask.run.cancelling={0}\uFF08\u30AD\u30E3\u30F3\u30BB\u30EB\u4E2D\u2026\uFF09 -IngestManager.StartIngestJobsTask.run.displayName=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u958B\u59CB\u4E2D -IngestMessage.exception.srcSubjDetailsDataNotNull.msg=\u30BD\u30FC\u30B9\u3001\u30B5\u30D6\u30B8\u30A7\u30AF\u30C8\u3001\u8A73\u7D30\u304A\u3088\u3073\u30C7\u30FC\u30BF\u306F\u30CC\u30EB\u3067\u306F\u3044\u3051\u307E\u305B\u3093 -IngestMessage.exception.srcSubjNotNull.msg=\u30BD\u30FC\u30B9\u304A\u3088\u3073\u30B5\u30D6\u30B8\u30A7\u30AF\u30C8\u306F\u30CC\u30EB\u3067\u306F\u3044\u3051\u307E\u305B\u3093 -IngestMessage.exception.typeSrcSubjNotNull.msg=\u30E1\u30C3\u30BB\u30FC\u30B8\u30BF\u30A4\u30D7\u3001\u30BD\u30FC\u30B9\u304A\u3088\u3073\u30B5\u30D6\u30B8\u30A7\u30AF\u30C8\u306F\u30CC\u30EB\u3067\u306F\u3044\u3051\u307E\u305B\u3093 -IngestMessage.toString.data.text=\ \u30C7\u30FC\u30BF\uFF1A{0} -IngestMessage.toString.date.text=\ \u65E5\u4ED8\uFF1A{0} -IngestMessage.toString.details.text=\ \u8A73\u7D30\uFF1A{0} -IngestMessage.toString.subject.text=\ \u30B5\u30D6\u30B8\u30A7\u30AF\u30C8\uFF1A{0} -IngestMessage.toString.type.text=\u30BF\u30A4\u30D7\uFF1A{0} -IngestMessageDetailsPanel.copyMenuItem.text=\u30B3\u30D4\u30FC -IngestMessageDetailsPanel.messageDetailsPane.contentType=\u30C6\u30AD\u30B9\u30C8\uFF0Fhtml -IngestMessageDetailsPanel.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629E -IngestMessageDetailsPanel.viewArtifactButton.text=\u7D50\u679C\u3078\u79FB\u52D5 -IngestMessageDetailsPanel.viewContentButton.text=\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3078\u79FB\u52D5 -IngestMessagePanel.BooleanRenderer.exception.nonBoolVal.msg=\u30D6\u30FC\u30EB\u5024\u3067\u306F\u306A\u3044\u3082\u306E\u306BBooleanRenderer\u3092\u4F7F\u7528\u3057\u3088\u3046\u3068\u3057\u307E\u3057\u305F\u3002 -IngestMessagePanel.DateRenderer.exception.nonDateVal.text=\u65E5\u4ED8\u3067\u306F\u306A\u3044\u3082\u306E\u306BDateRenderer\u3092\u4F7F\u7528\u3057\u3088\u3046\u3068\u3057\u307E\u3057\u305F\u3002 -IngestMessagePanel.moduleErr=\u30E2\u30B8\u30E5\u30FC\u30EB\u30A8\u30E9\u30FC -IngestMessagePanel.moduleErr.errListenUpdates.text=IngestMessagePanel\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u3092\u78BA\u8A8D\u4E2D\u306B\u30E2\u30B8\u30E5\u30FC\u30EB\u304C\u30A8\u30E9\u30FC\u3092\u8D77\u3053\u3057\u307E\u3057\u305F\u3002\u3069\u306E\u30E2\u30B8\u30E5\u30FC\u30EB\u304B\u30ED\u30B0\u3092\u78BA\u8A8D\u3057\u3066\u4E0B\u3055\u3044\u3002\u4E00\u90E8\u306E\u30C7\u30FC\u30BF\u304C\u4E0D\u5B8C\u5168\u304B\u3082\u3057\u308C\u307E\u305B\u3093\u3002 -IngestMessagePanel.MsgTableMod.colNames.module=\u30E2\u30B8\u30E5\u30FC\u30EB -IngestMessagePanel.MsgTableMod.colNames.new=\u65B0\u898F\uFF1F -IngestMessagePanel.MsgTableMod.colNames.num=\u756A\u53F7 -IngestMessagePanel.MsgTableMod.colNames.subject=\u30B5\u30D6\u30B8\u30A7\u30AF\u30C8 -IngestMessagePanel.MsgTableMod.colNames.timestamp=\u30BF\u30A4\u30E0\u30B9\u30BF\u30F3\u30D7 -IngestMessagePanel.sortByComboBox.model.priority=\u512A\u5148\u5EA6 +CTL_IngestMessageTopComponent=\u30e1\u30c3\u30bb\u30fc\u30b8 +HINT_IngestMessageTopComponent=\u30e1\u30c3\u30bb\u30fc\u30b8\u30a6\u30a3\u30f3\u30c9\u30a6 +IngestDialog.closeButton.title=\u9589\u3058\u308b +IngestDialog.startButton.title=\u958b\u59cb +IngestDialog.title.text=\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8 +IngestJob.progress.cancelling={0}\uff08\u30ad\u30e3\u30f3\u30bb\u30eb\u4e2d\u2026\uff09 +IngestJob.progress.dataSourceIngest.displayName={1}\u306e{0} +IngestJob.progress.fileIngest.displayName={0}\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u89e3\u6790\u4e2d +IngestManager.moduleErr=\u30e2\u30b8\u30e5\u30fc\u30eb\u30a8\u30e9\u30fc +IngestManager.moduleErr.errListenToUpdates.msg=Ingest Manager\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3092\u78ba\u8a8d\u4e2d\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u30a8\u30e9\u30fc\u3092\u8d77\u3053\u3057\u307e\u3057\u305f\u3002\u3069\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u304b\u30ed\u30b0\u3092\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\u3002\u4e00\u90e8\u306e\u30c7\u30fc\u30bf\u304c\u4e0d\u5b8c\u5168\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 +IngestManager.StartIngestJobsTask.run.cancelling={0}\uff08\u30ad\u30e3\u30f3\u30bb\u30eb\u4e2d\u2026\uff09 +IngestManager.StartIngestJobsTask.run.displayName=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u958b\u59cb\u4e2d +IngestMessage.exception.srcSubjDetailsDataNotNull.msg=\u30bd\u30fc\u30b9\u3001\u30b5\u30d6\u30b8\u30a7\u30af\u30c8\u3001\u8a73\u7d30\u304a\u3088\u3073\u30c7\u30fc\u30bf\u306f\u30cc\u30eb\u3067\u306f\u3044\u3051\u307e\u305b\u3093 +IngestMessage.exception.srcSubjNotNull.msg=\u30bd\u30fc\u30b9\u304a\u3088\u3073\u30b5\u30d6\u30b8\u30a7\u30af\u30c8\u306f\u30cc\u30eb\u3067\u306f\u3044\u3051\u307e\u305b\u3093 +IngestMessage.exception.typeSrcSubjNotNull.msg=\u30e1\u30c3\u30bb\u30fc\u30b8\u30bf\u30a4\u30d7\u3001\u30bd\u30fc\u30b9\u304a\u3088\u3073\u30b5\u30d6\u30b8\u30a7\u30af\u30c8\u306f\u30cc\u30eb\u3067\u306f\u3044\u3051\u307e\u305b\u3093 +IngestMessage.toString.data.text=\ \u30c7\u30fc\u30bf\uff1a{0} +IngestMessage.toString.date.text=\ \u65e5\u4ed8\uff1a{0} +IngestMessage.toString.details.text=\ \u8a73\u7d30\uff1a{0} +IngestMessage.toString.subject.text=\ \u30b5\u30d6\u30b8\u30a7\u30af\u30c8\uff1a{0} +IngestMessage.toString.type.text=\u30bf\u30a4\u30d7\uff1a{0} +IngestMessageDetailsPanel.copyMenuItem.text=\u30b3\u30d4\u30fc +IngestMessageDetailsPanel.messageDetailsPane.contentType=\u30c6\u30ad\u30b9\u30c8\uff0fhtml +IngestMessageDetailsPanel.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629e +IngestMessageDetailsPanel.viewArtifactButton.text=\u7d50\u679c\u3078\u79fb\u52d5 +IngestMessageDetailsPanel.viewContentButton.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3078\u79fb\u52d5 +IngestMessagePanel.BooleanRenderer.exception.nonBoolVal.msg=\u30d6\u30fc\u30eb\u5024\u3067\u306f\u306a\u3044\u3082\u306e\u306bBooleanRenderer\u3092\u4f7f\u7528\u3057\u3088\u3046\u3068\u3057\u307e\u3057\u305f\u3002 +IngestMessagePanel.DateRenderer.exception.nonDateVal.text=\u65e5\u4ed8\u3067\u306f\u306a\u3044\u3082\u306e\u306bDateRenderer\u3092\u4f7f\u7528\u3057\u3088\u3046\u3068\u3057\u307e\u3057\u305f\u3002 +IngestMessagePanel.moduleErr=\u30e2\u30b8\u30e5\u30fc\u30eb\u30a8\u30e9\u30fc +IngestMessagePanel.moduleErr.errListenUpdates.text=IngestMessagePanel\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3092\u78ba\u8a8d\u4e2d\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u30a8\u30e9\u30fc\u3092\u8d77\u3053\u3057\u307e\u3057\u305f\u3002\u3069\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u304b\u30ed\u30b0\u3092\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\u3002\u4e00\u90e8\u306e\u30c7\u30fc\u30bf\u304c\u4e0d\u5b8c\u5168\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 +IngestMessagePanel.MsgTableMod.colNames.module=\u30e2\u30b8\u30e5\u30fc\u30eb +IngestMessagePanel.MsgTableMod.colNames.new=\u65b0\u898f\uff1f +IngestMessagePanel.MsgTableMod.colNames.num=\u756a\u53f7 +IngestMessagePanel.MsgTableMod.colNames.subject=\u30b5\u30d6\u30b8\u30a7\u30af\u30c8 +IngestMessagePanel.MsgTableMod.colNames.timestamp=\u30bf\u30a4\u30e0\u30b9\u30bf\u30f3\u30d7 +IngestMessagePanel.sortByComboBox.model.priority=\u512a\u5148\u5ea6 IngestMessagePanel.sortByComboBox.model.time=\u6642\u9593 -IngestMessagePanel.sortByComboBox.toolTipText=\u6642\u9593\u9806\uFF08\u6642\u7CFB\u5217\uFF09\u307E\u305F\u306F\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u512A\u5148\u5EA6\u3067\u30BD\u30FC\u30C8 -IngestMessagePanel.sortByLabel.text=\u6B21\u3067\u30BD\u30FC\u30C8\uFF1A -IngestMessagePanel.totalMessagesNameLabel.text=\u5408\u8A08\uFF1A +IngestMessagePanel.sortByComboBox.toolTipText=\u6642\u9593\u9806\uff08\u6642\u7cfb\u5217\uff09\u307e\u305f\u306f\u30e1\u30c3\u30bb\u30fc\u30b8\u306e\u512a\u5148\u5ea6\u3067\u30bd\u30fc\u30c8 +IngestMessagePanel.sortByLabel.text=\u6b21\u3067\u30bd\u30fc\u30c8\uff1a +IngestMessagePanel.totalMessagesNameLabel.text=\u5408\u8a08\uff1a IngestMessagePanel.totalMessagesNameVal.text=- -IngestMessagePanel.totalUniqueMessagesNameLabel.text=\u30E6\u30CB\u30FC\u30AF\uFF1A +IngestMessagePanel.totalUniqueMessagesNameLabel.text=\u30e6\u30cb\u30fc\u30af\uff1a IngestMessagePanel.totalUniqueMessagesNameVal.text=- -IngestMessagesToolbar.customizeButton.toolTipText=\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8 -IngestMessageTopComponent.displayName=\u30A4\u30F3\u30DC\u30C3\u30AF\u30B9\u3092\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8 -IngestMessageTopComponent.displayReport.option.GenRpt=\u30EC\u30DD\u30FC\u30C8\u3092\u751F\u6210 +IngestMessagesToolbar.customizeButton.toolTipText=\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8 +IngestMessageTopComponent.displayName=\u30a4\u30f3\u30dc\u30c3\u30af\u30b9\u3092\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8 +IngestMessageTopComponent.displayReport.option.GenRpt=\u30ec\u30dd\u30fc\u30c8\u3092\u751f\u6210 IngestMessageTopComponent.displayReport.option.OK=OK -IngestMessageTopComponent.initComponents.name=\u30A4\u30F3\u30DC\u30C3\u30AF\u30B9\u3092\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8 -IngestMessageTopComponent.msgDlg.ingestRpt.text=\u30EC\u30DD\u30FC\u30C8\u3092\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8 -IngestMonitor.mgrErrMsg.lowDiskSpace.msg=\u30C7\u30A3\u30B9\u30AF{0}\u306E\u30C7\u30A3\u30B9\u30AF\u9818\u57DF\u4E0D\u8DB3\u306E\u305F\u3081\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u3092\u4E2D\u6B62\u3057\u307E\u3059\u3002\n\u30B1\u30FC\u30B9\u30C9\u30E9\u30A4\u30D6\u306B\u6700\u4F4E1GB\u306E\u7A7A\u304D\u9818\u57DF\u304C\u3042\u308B\u306E\u3092\u78BA\u8A8D\u3057\u3001\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u3092\u518D\u5B9F\u884C\u3057\u3066\u4E0B\u3055\u3044\u3002 -IngestMonitor.mgrErrMsg.lowDiskSpace.title=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u304C\u4E2D\u6B62\u3055\u308C\u307E\u3057\u305F\u30FC{0}\u306E\u30C7\u30A3\u30B9\u30AF\u9818\u57DF\u4E0D\u8DB3 -OpenIDE-Module-Name=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8 -IngestManager.StartIngestJobsTask.run.startupErr.dlgErrorList=\n\u30A8\u30E9\u30FC\uFF1A\n{0} -IngestManager.StartIngestJobsTask.run.startupErr.dlgMsg=\u5358\u6570\u307E\u305F\u306F\u8907\u6570\u306E\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\u3092\u30B9\u30BF\u30FC\u30C8\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30B8\u30E7\u30D6\u306F\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F\u3002 -IngestManager.StartIngestJobsTask.run.startupErr.dlgSolution=\u5931\u6557\u3057\u305F\u30E2\u30B8\u30E5\u30FC\u30EB\u3092\u7121\u52B9\u5316\u3059\u308B\u304B\u30A8\u30E9\u30FC\u3092\u89E3\u6C7A\u3057\u3001\u305D\u306E\u5F8C\u30C7\u30FC\u30BF\u30BD\u30FC\u30B9\u3092\u53F3\u30AF\u30EA\u30C3\u30AF\u3057\u3001\n\u300C\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\u5B9F\u884C\u300D\u3092\u9078\u629E\u3057\u3066\u3001\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u3092\u518D\u5B9F\u884C\u3057\u3066\u4E0B\u3055\u3044\u3002 -IngestManager.StartIngestJobsTask.run.startupErr.dlgTitle=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u5931\u6557 -IngestJobSettings.createModuleSettingsFolder.warning=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\u8A2D\u5B9A\u30D5\u30A9\u30EB\u30C0\u306E\u4F5C\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002\u8A2D\u5B9A\u3092\u4FDD\u5B58\u3067\u304D\u307E\u305B\u3093\u3002 -IngestJob.progress.dataSourceIngest.initialDisplayName={0}\u3092\u89E3\u6790\u4E2D -IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.dataSource=\u30C7\u30FC\u30BF\u30BD\u30FC\u30B9 -IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.elapsedTime=\u7D4C\u904E\u6642\u9593\uFF08\u6642\uFF1A\u5206\uFF1A\u79D2\uFF09 -IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.file=\u30D5\u30A1\u30A4\u30EB -IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.startTime=\u958B\u59CB\u6642\u9593 -IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.threadID=\u30B9\u30EC\u30C3\u30C9ID -IngestManager.IngestMessage.ErrorMessageLimitReached.msg=\u6700\u5927\u6570({0})\u306E\u30A8\u30E9\u30FC\u304A\u3088\u3073\u307E\u305F\u306F\u8B66\u544A\u30E1\u30C3\u30BB\u30FC\u30B8\u304C\u63B2\u8F09\u3055\u308C\u307E\u3057\u305F\u3002\u3055\u3089\u306A\u308B\u30A8\u30E9\u30FC\uFF0F\u8B66\u544A\u306F\u30ED\u30B0\u3092\u78BA\u8A8D\u3057\u3066\u4E0B\u3055\u3044\uFF08\u30D8\u30EB\u30D7->\u30ED\u30B0\u30D5\u30A9\u30EB\u30C0\u30FC\u3092\u958B\u304F\uFF09 -IngestManager.IngestMessage.ErrorMessageLimitReached.subject=\u6700\u5927\u6570\u306E\u30A8\u30E9\u30FC\u304C\u63B2\u8F09\u3055\u308C\u307E\u3057\u305F -IngestManager.IngestMessage.ErrorMessageLimitReached.title=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30DE\u30CD\u30B8\u30E3\u30FC -IngestManager.IngestThreadActivitySnapshot.idleThread=\u30A2\u30A4\u30C9\u30EB -IngestProgressSnapshotDialog.title.text=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30D7\u30ED\u30B0\u30EC\u30B9\u30FB\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8 -IngestProgressSnapshotPanel.closeButton.text=\u9589\u3058\u308B -IngestProgressSnapshotPanel.refreshButton.text=\u30EA\u30D5\u30EC\u30C3\u30B7\u30E5 -IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.activity=\u30A2\u30AF\u30C6\u30A3\u30D3\u30C6\u30A3 -IngestJobSettingsPanel.advancedButton.actionCommand=\u30A2\u30C9\u30D0\u30F3\u30B9 -IngestJobSettingsPanel.advancedButton.text=\u30A2\u30C9\u30D0\u30F3\u30B9 +IngestMessageTopComponent.initComponents.name=\u30a4\u30f3\u30dc\u30c3\u30af\u30b9\u3092\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8 +IngestMessageTopComponent.msgDlg.ingestRpt.text=\u30ec\u30dd\u30fc\u30c8\u3092\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8 +IngestMonitor.mgrErrMsg.lowDiskSpace.msg=\u30c7\u30a3\u30b9\u30af{0}\u306e\u30c7\u30a3\u30b9\u30af\u9818\u57df\u4e0d\u8db3\u306e\u305f\u3081\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u3092\u4e2d\u6b62\u3057\u307e\u3059\u3002\n\u30b1\u30fc\u30b9\u30c9\u30e9\u30a4\u30d6\u306b\u6700\u4f4e1GB\u306e\u7a7a\u304d\u9818\u57df\u304c\u3042\u308b\u306e\u3092\u78ba\u8a8d\u3057\u3001\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u3092\u518d\u5b9f\u884c\u3057\u3066\u4e0b\u3055\u3044\u3002 +IngestMonitor.mgrErrMsg.lowDiskSpace.title=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u304c\u4e2d\u6b62\u3055\u308c\u307e\u3057\u305f\u30fc{0}\u306e\u30c7\u30a3\u30b9\u30af\u9818\u57df\u4e0d\u8db3 +OpenIDE-Module-Name=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8 +IngestManager.StartIngestJobsTask.run.startupErr.dlgErrorList=\n\u30a8\u30e9\u30fc\uff1a\n{0} +IngestManager.StartIngestJobsTask.run.startupErr.dlgMsg=\u5358\u6570\u307e\u305f\u306f\u8907\u6570\u306e\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u30b9\u30bf\u30fc\u30c8\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b8\u30e7\u30d6\u306f\u30ad\u30e3\u30f3\u30bb\u30eb\u3055\u308c\u307e\u3057\u305f\u3002 +IngestManager.StartIngestJobsTask.run.startupErr.dlgSolution=\u5931\u6557\u3057\u305f\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u7121\u52b9\u5316\u3059\u308b\u304b\u30a8\u30e9\u30fc\u3092\u89e3\u6c7a\u3057\u3001\u305d\u306e\u5f8c\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u3092\u53f3\u30af\u30ea\u30c3\u30af\u3057\u3001\n\u300c\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u5b9f\u884c\u300d\u3092\u9078\u629e\u3057\u3066\u3001\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u3092\u518d\u5b9f\u884c\u3057\u3066\u4e0b\u3055\u3044\u3002 +IngestManager.StartIngestJobsTask.run.startupErr.dlgTitle=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u5931\u6557 +IngestJobSettings.createModuleSettingsFolder.warning=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u8a2d\u5b9a\u30d5\u30a9\u30eb\u30c0\u306e\u4f5c\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3067\u304d\u307e\u305b\u3093\u3002 +IngestJob.progress.dataSourceIngest.initialDisplayName={0}\u3092\u89e3\u6790\u4e2d +IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.dataSource=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9 +IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.elapsedTime=\u7d4c\u904e\u6642\u9593\uff08\u6642\uff1a\u5206\uff1a\u79d2\uff09 +IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.file=\u30d5\u30a1\u30a4\u30eb +IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.startTime=\u958b\u59cb\u6642\u9593 +IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.threadID=\u30b9\u30ec\u30c3\u30c9ID +IngestManager.IngestMessage.ErrorMessageLimitReached.msg=\u6700\u5927\u6570({0})\u306e\u30a8\u30e9\u30fc\u304a\u3088\u3073\u307e\u305f\u306f\u8b66\u544a\u30e1\u30c3\u30bb\u30fc\u30b8\u304c\u63b2\u8f09\u3055\u308c\u307e\u3057\u305f\u3002\u3055\u3089\u306a\u308b\u30a8\u30e9\u30fc\uff0f\u8b66\u544a\u306f\u30ed\u30b0\u3092\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\uff08\u30d8\u30eb\u30d7->\u30ed\u30b0\u30d5\u30a9\u30eb\u30c0\u30fc\u3092\u958b\u304f\uff09 +IngestManager.IngestMessage.ErrorMessageLimitReached.subject=\u6700\u5927\u6570\u306e\u30a8\u30e9\u30fc\u304c\u63b2\u8f09\u3055\u308c\u307e\u3057\u305f +IngestManager.IngestMessage.ErrorMessageLimitReached.title=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30de\u30cd\u30b8\u30e3\u30fc +IngestManager.IngestThreadActivitySnapshot.idleThread=\u30a2\u30a4\u30c9\u30eb +IngestProgressSnapshotDialog.title.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30d7\u30ed\u30b0\u30ec\u30b9\u30fb\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 +IngestProgressSnapshotPanel.closeButton.text=\u9589\u3058\u308b +IngestProgressSnapshotPanel.refreshButton.text=\u30ea\u30d5\u30ec\u30c3\u30b7\u30e5 +IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.activity=\u30a2\u30af\u30c6\u30a3\u30d3\u30c6\u30a3 +IngestJobSettingsPanel.advancedButton.actionCommand=\u30a2\u30c9\u30d0\u30f3\u30b9 +IngestJobSettingsPanel.advancedButton.text=\u30a2\u30c9\u30d0\u30f3\u30b9 ModuleTableModel.colName.duration=\u6240\u8981\u6642\u9593 -IngestJob.cancellationDialog.title=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u3092\u30AD\u30E3\u30F3\u30BB\u30EB -IngestJobSettings.missingModule.warning=\u4EE5\u524D\u306B\u8AAD\u307F\u8FBC\u3093\u3060{0}\u30E2\u30B8\u30E5\u30FC\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -DataSourceIngestCancellationPanel.cancelAllModulesRadioButton.text=\u5168\u3066\u306E\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\u3092\u30AD\u30E3\u30F3\u30BB\u30EB -DataSourceIngestCancellationPanel.cancelCurrentModuleRadioButton.text=\u73FE\u5728\u306E\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\u306E\u307F\u30AD\u30E3\u30F3\u30BB\u30EB -FileIngestCancellationPanel.cancelFileIngestRadioButton.text=\u30D5\u30A1\u30A4\u30EB\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u306E\u307F\u30AD\u30E3\u30F3\u30BB\u30EB -FileIngestCancellationPanel.cancelIngestJobRadioButton.text=\u30C7\u30FC\u30BF\u30BD\u30FC\u30B9\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u304A\u3088\u3073\u30D5\u30A1\u30A4\u30EB\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u3092\u30AD\u30E3\u30F3\u30BB\u30EB -IngestJobSettings.moduleSettingsLoad.warning={1}\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u306E{0}\u30E2\u30B8\u30E5\u30FC\u30EB\u7528\u306E\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30B8\u30E7\u30D6\u8A2D\u5B9A\u3092\u8AAD\u307F\u8FBC\u307F\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u30C7\u30D5\u30A9\u30EB\u30C8\u8A2D\u5B9A\u3092\u4F7F\u7528\u3057\u3066\u3044\u307E\u3059\u3002 -IngestJobSettings.save.warning={0}\u30E2\u30B8\u30E5\u30FC\u30EB\u306E\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30B8\u30E7\u30D6\u8A2D\u5B9A\u3092\u4FDD\u5B58\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -IngestJobTableModel.colName.dataSource=\u30C7\u30FC\u30BF\u30BD\u30FC\u30B9 -IngestJobTableModel.colName.dirQueued=\u30AD\u30E5\u30FC\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA -IngestJobTableModel.colName.filesPerSec=\u30D5\u30A1\u30A4\u30EB\uFF0F\u79D2 -IngestJobTableModel.colName.filesQueued=\u30AD\u30E5\u30FC\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB -IngestJobTableModel.colName.inProgress=\u51E6\u7406\u4E2D -IngestJobTableModel.colName.jobID=\u30B8\u30E7\u30D6ID -IngestJobTableModel.colName.numProcessed=\u51E6\u7406\u3055\u308C\u305F\u6570 -IngestJobTableModel.colName.rootQueued=\u30AD\u30E5\u30FC\u3055\u308C\u305F\u30EB\u30FC\u30C8 -IngestJobTableModel.colName.start=\u30B9\u30BF\u30FC\u30C8 -IngestModuleFactoryLoader.errorMessages.duplicateDisplayName=\u5225\u306E\u30E2\u30B8\u30E5\u30FC\u30EB\u306E\u540D\u524D\u3092\u91CD\u8907\u3059\u308B\u3001{0}\u306E\u540D\u524D\u3092\u6301\u3064\u30E2\u30B8\u30E5\u30FC\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F\u3002\u30E2\u30B8\u30E5\u30FC\u30EB\u306F\u4F7F\u7528\u3057\u307E\u305B\u3093\u3002 -IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.jobID=\u30B8\u30E7\u30D6ID -ModuleTableModel.colName.module=\u30E2\u30B8\u30E5\u30FC\u30EB -IngestJobSettingsPanel.processUnallocCheckbox.toolTipText=\u524A\u9664\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB\u7B49\u306E\u672A\u5272\u308A\u5F53\u3066\u9818\u57DF\u3092\u51E6\u7406\u3002\u3088\u308A\u5B8C\u5168\u306A\u7D50\u679C\u304C\u51FA\u307E\u3059\u304C\u3001\u5927\u304D\u3044\u30A4\u30E1\u30FC\u30B8\u3067\u306F\u51E6\u7406\u6642\u9593\u304C\u9577\u304F\u306A\u308B\u304B\u3082\u3057\u308C\u307E\u305B\u3093\u3002 +IngestJob.cancellationDialog.title=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u3092\u30ad\u30e3\u30f3\u30bb\u30eb +IngestJobSettings.missingModule.warning=\u4ee5\u524d\u306b\u8aad\u307f\u8fbc\u3093\u3060{0}\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002 +DataSourceIngestCancellationPanel.cancelAllModulesRadioButton.text=\u5168\u3066\u306e\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u30ad\u30e3\u30f3\u30bb\u30eb +DataSourceIngestCancellationPanel.cancelCurrentModuleRadioButton.text=\u73fe\u5728\u306e\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u306e\u307f\u30ad\u30e3\u30f3\u30bb\u30eb +FileIngestCancellationPanel.cancelFileIngestRadioButton.text=\u30d5\u30a1\u30a4\u30eb\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u306e\u307f\u30ad\u30e3\u30f3\u30bb\u30eb +FileIngestCancellationPanel.cancelIngestJobRadioButton.text=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u304a\u3088\u3073\u30d5\u30a1\u30a4\u30eb\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u3092\u30ad\u30e3\u30f3\u30bb\u30eb +IngestJobSettings.moduleSettingsLoad.warning={1}\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e{0}\u30e2\u30b8\u30e5\u30fc\u30eb\u7528\u306e\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b8\u30e7\u30d6\u8a2d\u5b9a\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u8a2d\u5b9a\u3092\u4f7f\u7528\u3057\u3066\u3044\u307e\u3059\u3002 +IngestJobSettings.save.warning={0}\u30e2\u30b8\u30e5\u30fc\u30eb\u306e\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b8\u30e7\u30d6\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 +IngestJobTableModel.colName.dataSource=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9 +IngestJobTableModel.colName.dirQueued=\u30ad\u30e5\u30fc\u3055\u308c\u305f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea +IngestJobTableModel.colName.filesPerSec=\u30d5\u30a1\u30a4\u30eb\uff0f\u79d2 +IngestJobTableModel.colName.filesQueued=\u30ad\u30e5\u30fc\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb +IngestJobTableModel.colName.inProgress=\u51e6\u7406\u4e2d +IngestJobTableModel.colName.jobID=\u30b8\u30e7\u30d6ID +IngestJobTableModel.colName.numProcessed=\u51e6\u7406\u3055\u308c\u305f\u6570 +IngestJobTableModel.colName.rootQueued=\u30ad\u30e5\u30fc\u3055\u308c\u305f\u30eb\u30fc\u30c8 +IngestJobTableModel.colName.start=\u30b9\u30bf\u30fc\u30c8 +IngestModuleFactoryLoader.errorMessages.duplicateDisplayName=\u5225\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u306e\u540d\u524d\u3092\u91cd\u8907\u3059\u308b\u3001{0}\u306e\u540d\u524d\u3092\u6301\u3064\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f\u3002\u30e2\u30b8\u30e5\u30fc\u30eb\u306f\u4f7f\u7528\u3057\u307e\u305b\u3093\u3002 +IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.jobID=\u30b8\u30e7\u30d6ID +ModuleTableModel.colName.module=\u30e2\u30b8\u30e5\u30fc\u30eb +IngestJobSettingsPanel.processUnallocCheckbox.toolTipText=\u524a\u9664\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb\u7b49\u306e\u672a\u5272\u308a\u5f53\u3066\u9818\u57df\u3092\u51e6\u7406\u3002\u3088\u308a\u5b8c\u5168\u306a\u7d50\u679c\u304c\u51fa\u307e\u3059\u304c\u3001\u5927\u304d\u3044\u30a4\u30e1\u30fc\u30b8\u3067\u306f\u51e6\u7406\u6642\u9593\u304c\u9577\u304f\u306a\u308b\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 -IngestJobSettingsPanel.processUnallocCheckbox.text=\u672A\u5272\u308A\u5F53\u3066\u9818\u57DF\u306E\u51E6\u7406 -Menu/Tools/RunIngestModules=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\u3092\u5B9F\u884C -IngestJob.progress.fileIngest.cancelMessage={1}\u306E{0}\u3092\u5F85\u3063\u3066\u3044\u307E\u3059 -IngestManager.OpenEventChannel.Fail.ErrMsg=\u3053\u306E\u30B1\u30FC\u30B9\u3067\u4F7F\u308F\u308C\u3066\u3044\u308B\u304B\u3082\u3057\u308C\u306A\u3044\u4ED6\u306E\u30CE\u30FC\u30C9\u306B\u89E3\u6790\u30D7\u30ED\u30BB\u30B9\u304C\u63A5\u7D9A\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -IngestManager.OpenEventChannel.Fail.Title=\u63A5\u7D9A\u5931\u6557 -IngestJobSettings.moduleSettingsSave.warning={1}\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u306E{0}\u30E2\u30B8\u30E5\u30FC\u30EB\u7528\u306E\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30B8\u30E7\u30D6\u8A2D\u5B9A\u3092\u8AAD\u307F\u8FBC\u307F\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 -IngestJobTableModel.colName.dsQueued=\u30AD\u30E5\u30FC\u3055\u308C\u305FDS -IngestJobSettingsPanel.jButtonSelectAll.text=\u5168\u3066\u9078\u629E -IngestJobSettingsPanel.jButtonDeselectAll.text=\u5168\u3066\u9078\u629E\u89E3\u9664 -IngestManager.cancellingIngest.msgDlg.text=\u73FE\u5728\u5B9F\u884C\u4E2D\u306E\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30B8\u30E7\u30D6\u3092\u30AD\u30E3\u30F3\u30BB\u30EB\u4E2D -IngestManager.serviceIsDown.msgDlg.text={0}\u304C\u30C0\u30A6\u30F3\u3057\u3066\u3044\u307E\u3059 -RunIngestSubMenu.menuItem.empty=\u30FC\u7A7A\u767D\u30FC -RunIngestModulesMenu.getName.text=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\u3092\u5B9F\u884C -DataSourceIngestPipeline.moduleError.title.text={0}\u30A8\u30E9\u30FC -FileIngestPipeline.moduleError.title.text={0}\u30A8\u30E9\u30FC -IngestJob.cancelReason.notCancelled.text=\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u3066\u3044\u307E\u305B\u3093 -IngestJob.cancelReason.cancelledByUser.text=\u30E6\u30FC\u30B6\u30FC\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3057\u307E\u3057\u305F -IngestJob.cancelReason.ingestModStartFail.text=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\u306E\u8D77\u52D5\u306B\u5931\u6557 -IngestJob.cancelReason.outOfDiskSpace.text=\u30C7\u30A3\u30B9\u30AF\u30B9\u30DA\u30FC\u30B9\u304C\u8DB3\u308A\u307E\u305B\u3093 -IngestJob.cancelReason.servicesDown.text=\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F -IngestJob.cancelReason.caseClosed.text=\u30B1\u30FC\u30B9\u3092\u9589\u3058\u307E\u3057\u305F +IngestJobSettingsPanel.processUnallocCheckbox.text=\u672a\u5272\u308a\u5f53\u3066\u9818\u57df\u306e\u51e6\u7406 +Menu/Tools/RunIngestModules=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u5b9f\u884c +IngestJob.progress.fileIngest.cancelMessage={1}\u306e{0}\u3092\u5f85\u3063\u3066\u3044\u307e\u3059 +IngestManager.OpenEventChannel.Fail.ErrMsg=\u3053\u306e\u30b1\u30fc\u30b9\u3067\u4f7f\u308f\u308c\u3066\u3044\u308b\u304b\u3082\u3057\u308c\u306a\u3044\u4ed6\u306e\u30ce\u30fc\u30c9\u306b\u89e3\u6790\u30d7\u30ed\u30bb\u30b9\u304c\u63a5\u7d9a\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 +IngestManager.OpenEventChannel.Fail.Title=\u63a5\u7d9a\u5931\u6557 +IngestJobSettings.moduleSettingsSave.warning={1}\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e{0}\u30e2\u30b8\u30e5\u30fc\u30eb\u7528\u306e\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b8\u30e7\u30d6\u8a2d\u5b9a\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +IngestJobTableModel.colName.dsQueued=\u30ad\u30e5\u30fc\u3055\u308c\u305fDS +IngestJobSettingsPanel.jButtonSelectAll.text=\u5168\u3066\u9078\u629e +IngestJobSettingsPanel.jButtonDeselectAll.text=\u5168\u3066\u9078\u629e\u89e3\u9664 +IngestManager.cancellingIngest.msgDlg.text=\u73fe\u5728\u5b9f\u884c\u4e2d\u306e\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b8\u30e7\u30d6\u3092\u30ad\u30e3\u30f3\u30bb\u30eb\u4e2d +IngestManager.serviceIsDown.msgDlg.text={0}\u304c\u30c0\u30a6\u30f3\u3057\u3066\u3044\u307e\u3059 +RunIngestSubMenu.menuItem.empty=\u30fc\u7a7a\u767d\u30fc +RunIngestModulesMenu.getName.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u5b9f\u884c +DataSourceIngestPipeline.moduleError.title.text={0}\u30a8\u30e9\u30fc +FileIngestPipeline.moduleError.title.text={0}\u30a8\u30e9\u30fc +IngestJob.cancelReason.notCancelled.text=\u30ad\u30e3\u30f3\u30bb\u30eb\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +IngestJob.cancelReason.cancelledByUser.text=\u30e6\u30fc\u30b6\u30fc\u304c\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u307e\u3057\u305f +IngestJob.cancelReason.ingestModStartFail.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u306e\u8d77\u52d5\u306b\u5931\u6557 +IngestJob.cancelReason.outOfDiskSpace.text=\u30c7\u30a3\u30b9\u30af\u30b9\u30da\u30fc\u30b9\u304c\u8db3\u308a\u307e\u305b\u3093 +IngestJob.cancelReason.caseClosed.text=\u30b1\u30fc\u30b9\u3092\u9589\u3058\u307e\u3057\u305f diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java index de15f82949..827bbc016d 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,8 +39,10 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.python.util.PythonObjectInputStream; /** - * Encapsulates the ingest job settings for a particular context such as the Add - * Data Source wizard or the Run Ingest Modules dialog. + * Encapsulates the ingest job settings for a particular execution context. + * Examples of execution contexts include the add data source wizard and the run + * ingest modules dialog. Different execution conterxts may have different + * ingest job settings. */ public class IngestJobSettings { @@ -60,19 +62,30 @@ public class IngestJobSettings { private boolean processUnallocatedSpace; private final List warnings; - // Determines which modeules to run + /** + * The type of ingest modules to run. + */ public enum IngestType { - // Run all modules + /** + * Run both data source level and file-level ingest modules. + */ ALL_MODULES, - // Run only data source modules + /** + * Run only data source level ingest modules. + */ DATA_SOURCE_ONLY, - // Run only files modules + /** + * Run only file level ingest modules. + */ FILES_ONLY } /** - * Constructs an ingest job settings object for a given context. + * Constructs an ingest job settings object for a given execution context. + * Examples of execution contexts include the add data source wizard and the + * run ingest modules dialog. Different execution conterxts may have + * different ingest job settings. * * @param executionContext The ingest execution context identifier. */ @@ -87,7 +100,10 @@ public class IngestJobSettings { } /** - * Constructs an ingest job settings object for a given context. + * Constructs an ingest job settings object for a given context. Examples of + * execution contexts include the add data source wizard and the run ingest + * modules dialog. Different execution conterxts may have different ingest + * job settings. * * @param context The context identifier string. * @param ingestType The type of modules ingest is running. @@ -116,9 +132,12 @@ public class IngestJobSettings { } /** - * Get the ingest execution context identifier. + * Gets the ingest execution context identifier. Examples of execution + * contexts include the add data source wizard and the run ingest modules + * dialog. Different execution conterxts may have different ingest job + * settings. * - * @return The context string. + * @return The execution context identifier. */ String getExecutionContext() { return this.executionContext; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index f528cba6e6..c196caba8a 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -71,28 +71,27 @@ public class IngestManager { private static IngestManager instance; private final Object ingestMessageBoxLock = new Object(); - /** - * The ingest manager maintains a mapping of ingest job IDs to running + /* + * The ingest manager maintains a mapping of ingest job ids to running * ingest jobs. */ - private final ConcurrentHashMap jobsById; + private final Map jobsById; - /** + /* * Each runnable/callable task the ingest manager submits to its thread * pools is given a unique thread/task ID. */ private final AtomicLong nextThreadId; - /** - * Ingest jobs may be queued to be started on a pool thread by ingest job - * starters. A mapping of thread/task IDs to the result objects associated - * with each ingest job starter is maintained to provide handles that can be - * used to cancel the ingest job starter. + /* + * Ingest jobs may be queued to be started on a pool thread by start ingest + * job tasks. A mapping of task ids to the Future objects for each task is + * maintained to allow for task cancellation. */ - private final ConcurrentHashMap> ingestJobStarters; + private final Map> startIngestJobTasks; private final ExecutorService startIngestJobsThreadPool; - /** + /* * Ingest jobs use an ingest task scheduler to break themselves down into * data source level and file level tasks. The ingest scheduler puts these * ingest tasks into queues for execution on ingest manager pool threads by @@ -118,14 +117,14 @@ public class IngestManager { private AutopsyEventPublisher moduleEventPublisher; private final ExecutorService eventPublishingExecutor; - /** + /* * The ingest manager uses an ingest monitor to determine when system * resources are under pressure. If the monitor detects such a situation, it * calls back to the ingest manager to cancel all ingest jobs in progress. */ private final IngestMonitor ingestMonitor; - /** + /* * The ingest manager provides access to a top component that is used by * ingest module to post messages for the user. A count of the posts is used * as a cap to avoid bogging down the application. @@ -134,7 +133,7 @@ public class IngestManager { private volatile IngestMessageTopComponent ingestMessageBox; private final AtomicLong ingestErrorMessagePosts; - /** + /* * The ingest manager supports reporting of ingest processing progress by * collecting snapshots of the activities of the ingest threads, ingest job * progress, and ingest module run times. @@ -142,13 +141,13 @@ public class IngestManager { private final ConcurrentHashMap ingestThreadActivitySnapshots; private final ConcurrentHashMap ingestModuleRunTimes; - /** + /* * The ingest job creation capability of the ingest manager can be turned on * and off to support an orderly shut down of the application. */ private volatile boolean jobCreationIsEnabled; - /** + /* * Ingest manager subscribes to service outage notifications. If key * services are down, ingest manager cancels all ingest jobs in progress. */ @@ -264,8 +263,8 @@ public class IngestManager { this.dataSourceIngestThreadPool = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("IM-data-source-ingest-%d").build()); //NON-NLS this.startIngestJobsThreadPool = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("IM-start-ingest-jobs-%d").build()); //NON-NLS this.nextThreadId = new AtomicLong(0L); - this.jobsById = new ConcurrentHashMap<>(); - this.ingestJobStarters = new ConcurrentHashMap<>(); + this.jobsById = new HashMap<>(); + this.startIngestJobTasks = new ConcurrentHashMap<>(); this.servicesMonitor = ServicesMonitor.getInstance(); subscribeToServiceMonitorEvents(); @@ -329,7 +328,7 @@ public class IngestManager { public void propertyChange(PropertyChangeEvent evt) { if (evt.getNewValue().equals(ServicesMonitor.ServiceStatus.DOWN.toString())) { - // check whether a milti-user case is currently being processed + // check whether a multi-user case is currently being processed try { if (!Case.isCaseOpen() || Case.getCurrentCase().getCaseType() != Case.CaseType.MULTI_USER_CASE) { return; @@ -474,13 +473,13 @@ public class IngestManager { * @param dataSources The data sources to process. * @param settings The settings for the ingest job. */ - public synchronized void queueIngestJob(Collection dataSources, IngestJobSettings settings) { - if (this.jobCreationIsEnabled) { + public void queueIngestJob(Collection dataSources, IngestJobSettings settings) { + if (jobCreationIsEnabled) { IngestJob job = new IngestJob(dataSources, settings, RuntimeProperties.coreComponentsAreActive()); if (job.hasIngestPipeline()) { long taskId = nextThreadId.incrementAndGet(); Future task = startIngestJobsThreadPool.submit(new StartIngestJobTask(taskId, job)); - ingestJobStarters.put(taskId, task); + startIngestJobTasks.put(taskId, task); } } } @@ -544,20 +543,18 @@ public class IngestManager { ingestMonitor.start(); } - /** - * Add the job to the jobs map now so that isIngestRunning() will - * return true while the modules read global settings during start - * up. This works because the core global settings panels restrict - * changes while analysis is in progress. - */ - this.jobsById.put(job.getId(), job); + synchronized (jobsById) { + jobsById.put(job.getId(), job); + } List errors = job.start(); if (errors.isEmpty()) { this.fireIngestJobStarted(job.getId()); IngestManager.logger.log(Level.INFO, "Ingest job {0} started", job.getId()); //NON-NLS success = true; } else { - this.jobsById.remove(job.getId()); + synchronized (jobsById) { + this.jobsById.remove(job.getId()); + } for (IngestModuleError error : errors) { logger.log(Level.SEVERE, String.format("Error starting %s ingest module", error.getModuleDisplayName()), error.getModuleError()); //NON-NLS } @@ -599,13 +596,15 @@ public class IngestManager { synchronized void finishIngestJob(IngestJob job) { long jobId = job.getId(); - this.jobsById.remove(jobId); + synchronized (jobsById) { + jobsById.remove(jobId); + } if (!job.isCancelled()) { IngestManager.logger.log(Level.INFO, "Ingest job {0} completed", jobId); //NON-NLS - this.fireIngestJobCompleted(jobId); + fireIngestJobCompleted(jobId); } else { IngestManager.logger.log(Level.INFO, "Ingest job {0} cancelled", jobId); //NON-NLS - this.fireIngestJobCancelled(jobId); + fireIngestJobCancelled(jobId); } } @@ -615,7 +614,9 @@ public class IngestManager { * @return True or false. */ public boolean isIngestRunning() { - return !this.jobsById.isEmpty(); + synchronized (jobsById) { + return !jobsById.isEmpty(); + } } /** @@ -625,7 +626,7 @@ public class IngestManager { * instead. */ @Deprecated - public synchronized void cancelAllIngestJobs() { + public void cancelAllIngestJobs() { cancelAllIngestJobs(IngestJob.CancellationReason.USER_CANCELLED); } @@ -634,15 +635,21 @@ public class IngestManager { * * @param reason The cancellation reason. */ - public synchronized void cancelAllIngestJobs(IngestJob.CancellationReason reason) { - // Stop creating new ingest jobs. - for (Future handle : ingestJobStarters.values()) { + public void cancelAllIngestJobs(IngestJob.CancellationReason reason) { + /* + * Cancel the start job tasks. + */ + for (Future handle : startIngestJobTasks.values()) { handle.cancel(true); } - // Cancel all the jobs already created. - for (IngestJob job : this.jobsById.values()) { - job.cancel(reason); + /* + * Cancel the jobs in progress. + */ + synchronized (jobsById) { + for (IngestJob job : this.jobsById.values()) { + job.cancel(reason); + } } } @@ -903,8 +910,10 @@ public class IngestManager { */ List getIngestJobSnapshots() { List snapShots = new ArrayList<>(); - for (IngestJob job : this.jobsById.values()) { - snapShots.addAll(job.getDataSourceIngestJobSnapshots()); + synchronized (jobsById) { + for (IngestJob job : jobsById.values()) { + snapShots.addAll(job.getDataSourceIngestJobSnapshots()); + } } return snapShots; } @@ -941,7 +950,9 @@ public class IngestManager { public Void call() { try { if (Thread.currentThread().isInterrupted()) { - jobsById.remove(job.getId()); + synchronized (jobsById) { + jobsById.remove(job.getId()); + } return null; } @@ -953,7 +964,7 @@ public class IngestManager { if (progress != null) { progress.setDisplayName(NbBundle.getMessage(this.getClass(), "IngestManager.StartIngestJobsTask.run.cancelling", displayName)); } - Future handle = ingestJobStarters.remove(threadId); + Future handle = startIngestJobTasks.remove(threadId); handle.cancel(true); return true; } @@ -968,7 +979,7 @@ public class IngestManager { if (null != progress) { progress.finish(); } - ingestJobStarters.remove(threadId); + startIngestJobTasks.remove(threadId); } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java index 27b7f3ecf5..26f4fd6a11 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2015 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,11 +39,14 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Directory; /** - * Dialog box that allows a user to configure and run an ingest job on one or - * more data sources. + * + * A dialog box that allows a user to configure and execute analysis of one or + * more data sources with ingest modules or analysis of the contents of a + * directory with file-level ingest modules. */ public final class RunIngestModulesDialog extends JDialog { + private static final long serialVersionUID = 1L; private static final String TITLE = NbBundle.getMessage(RunIngestModulesDialog.class, "IngestDialog.title.text"); private final IngestType ingestType; private static Dimension DIMENSIONS = new Dimension(500, 300); @@ -51,13 +54,13 @@ public final class RunIngestModulesDialog extends JDialog { private IngestJobSettingsPanel ingestJobSettingsPanel; /** - * Construct a dialog box that allows a user to configure and run an ingest - * job on one or more data sources. + * Constructs a dialog box that allows a user to configure and execute + * analysis of one or more data sources with ingest modules. * * @param frame The dialog parent window. * @param title The title for the dialog. * @param modal True if the dialog should be modal, false otherwise. - * @param dataSources The data sources to be processed. + * @param dataSources The data sources to be analyzed. */ public RunIngestModulesDialog(JFrame frame, String title, boolean modal, List dataSources) { super(frame, title, modal); @@ -66,60 +69,26 @@ public final class RunIngestModulesDialog extends JDialog { } /** - * Construct a dialog box that allows a user to configure and run an ingest - * job on one or more data sources. + * Constructs a dialog box that allows a user to configure and execute + * analysis of one or more data sources with ingest modules. * * @param dataSources The data sources to be processed. */ public RunIngestModulesDialog(List dataSources) { this(new JFrame(TITLE), TITLE, true, dataSources); } - + + /** + * Constructs a dialog box that allows a user to configure and execute + * analysis of the contents of a directory with file-level ingest modules. + * + * @param dir + */ public RunIngestModulesDialog(Directory dir) { this.dataSources.add(dir); this.ingestType = IngestType.FILES_ONLY; } - /** - * Construct a dialog box that allows a user to configure and run an ingest - * job on one or more data sources. - * - * @param frame The dialog parent window. - * @param title The title for the dialog. - * @param modal True if the dialog should be modal, false otherwise. - * - * @deprecated - */ - @Deprecated - public RunIngestModulesDialog(JFrame frame, String title, boolean modal) { - super(frame, title, modal); - this.ingestType = IngestType.ALL_MODULES; - } - - /** - * Construct a dialog box that allows a user to configure and run an ingest - * job on one or more data sources. - * - * @deprecated - */ - @Deprecated - public RunIngestModulesDialog() { - this(new JFrame(TITLE), TITLE, true); - } - - /** - * Set the data sources to be processed. - * - * @param dataSources The data sources. - * - * @deprecated - */ - @Deprecated - public void setDataSources(List dataSources) { - this.dataSources.clear(); - this.dataSources.addAll(dataSources); - } - /** * Displays this dialog. */ @@ -139,7 +108,7 @@ public final class RunIngestModulesDialog extends JDialog { * Get the default or saved ingest job settings for this context and use * them to create and add an ingest job settings panel. */ - IngestJobSettings ingestJobSettings = new IngestJobSettings(RunIngestModulesDialog.class.getCanonicalName(), this.ingestType); + IngestJobSettings ingestJobSettings = new IngestJobSettings(RunIngestModulesDialog.class.getCanonicalName(), this.ingestType); RunIngestModulesDialog.showWarnings(ingestJobSettings); this.ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings); add(this.ingestJobSettingsPanel, BorderLayout.PAGE_START); @@ -227,4 +196,45 @@ public final class RunIngestModulesDialog extends JDialog { JOptionPane.showMessageDialog(null, warningMessage.toString()); } } + + /** + * Constructs a dialog box that allows a user to configure and execute + * analysis of one or more data sources with ingest modules. + * + * @param frame The dialog parent window. + * @param title The title for the dialog. + * @param modal True if the dialog should be modal, false otherwise. + * + * @deprecated + */ + @Deprecated + public RunIngestModulesDialog(JFrame frame, String title, boolean modal) { + super(frame, title, modal); + this.ingestType = IngestType.ALL_MODULES; + } + + /** + * Constructs a dialog box that allows a user to configure and run an ingest + * job on one or more data sources. + * + * @deprecated + */ + @Deprecated + public RunIngestModulesDialog() { + this(new JFrame(TITLE), TITLE, true); + } + + /** + * Sets the data sources to be processed. + * + * @param dataSources The data sources. + * + * @deprecated + */ + @Deprecated + public void setDataSources(List dataSources) { + this.dataSources.clear(); + this.dataSources.addAll(dataSources); + } + } diff --git a/Core/src/org/sleuthkit/autopsy/modules/UserArtifacts/UserArtifactIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/UserArtifacts/UserArtifactIngestModule.java index 5b510519ed..7b10bdbea9 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/UserArtifacts/UserArtifactIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/UserArtifacts/UserArtifactIngestModule.java @@ -49,26 +49,77 @@ public class UserArtifactIngestModule implements DataSourceIngestModule { FileManager manager = Case.getCurrentCase().getServices().getFileManager(); List file1 = manager.findFiles("Sunset.jpg"); //NON-NLS List file2 = manager.findFiles("Winter.jpg"); //NON-NLS - BlackboardArtifact art1; + List currArtifacts = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF); + BlackboardArtifact art1 = currArtifacts.size() == 0 ? null : currArtifacts.get(0); BlackboardArtifact art2; - if (!file1.isEmpty()) { - art1 = file1.get(0).newArtifact(type1.getTypeID()); - } else { - art1 = dataSource.newArtifact(type1.getTypeID()); + if (art1 == null) { + if (!file1.isEmpty()) { + art1 = file1.get(0).newArtifact(type1.getTypeID()); + } else { + art1 = dataSource.newArtifact(type1.getTypeID()); + } } if (!file2.isEmpty()) { art2 = file2.get(0).newArtifact(type2.getTypeID()); } else { art2 = dataSource.newArtifact(type2.getTypeID()); } - BlackboardAttribute.Type attributeType = Case.getCurrentCase().getServices().getBlackboard().addAttributeType("Test", TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.LONG, "2"); //NON-NLS - BlackboardAttribute.Type attributeType2 = Case.getCurrentCase().getServices().getBlackboard().addAttributeType("Test2", TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE, "3"); //NON-NLS + BlackboardAttribute.Type attributeType = Case.getCurrentCase().getSleuthkitCase().getAttributeType("Test8"); + if (attributeType == null) { + attributeType = Case.getCurrentCase().getServices().getBlackboard().addAttributeType("Test8", TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.LONG, "Header6"); + } + BlackboardAttribute.Type attributeType2 = Case.getCurrentCase().getSleuthkitCase().getAttributeType("Test9"); + if (attributeType2 == null) { + attributeType2 = Case.getCurrentCase().getServices().getBlackboard().addAttributeType("Test9", TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME, "Header7"); + + } + BlackboardAttribute.Type attributeType3 = Case.getCurrentCase().getSleuthkitCase().getAttributeType("Test0"); + if (attributeType3 == null) { + attributeType3 = Case.getCurrentCase().getServices().getBlackboard().addAttributeType("Test0", TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, "Header8"); + + } + BlackboardAttribute.Type attributeType4 = Case.getCurrentCase().getSleuthkitCase().getAttributeType("TestA"); + if (attributeType4 == null) { + attributeType4 = Case.getCurrentCase().getServices().getBlackboard().addAttributeType("TestA", TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.INTEGER, "Header9"); + + } + BlackboardAttribute.Type attributeType5 = Case.getCurrentCase().getSleuthkitCase().getAttributeType("TestB"); + if (attributeType5 == null) { + attributeType5 = Case.getCurrentCase().getServices().getBlackboard().addAttributeType("TestB", TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DOUBLE, "Header0"); + + } + BlackboardAttribute.Type attributeType6 = Case.getCurrentCase().getSleuthkitCase().getAttributeType("TestC"); + if (attributeType6 == null) { + attributeType6 = Case.getCurrentCase().getServices().getBlackboard().addAttributeType("TestC", TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE, "HeaderA"); + + } art1.addAttribute(new BlackboardAttribute(attributeType, - UserArtifactIngestModuleFactory.getModuleName(), -1L)); - progressBar.progress(1); + UserArtifactIngestModuleFactory.getModuleName(), 12345678L)); + art1.addAttribute(new BlackboardAttribute(attributeType2, + UserArtifactIngestModuleFactory.getModuleName(), 1457105587962L)); + art1.addAttribute(new BlackboardAttribute(attributeType3, + UserArtifactIngestModuleFactory.getModuleName(), "STRING VALUE TEST")); + art1.addAttribute(new BlackboardAttribute(attributeType4, + UserArtifactIngestModuleFactory.getModuleName(), 1234)); + art1.addAttribute(new BlackboardAttribute(attributeType5, + UserArtifactIngestModuleFactory.getModuleName(), 1234.5678D)); + byte[] bytes = new byte[2]; + bytes[0] = 12; + bytes[1] = 100; + art1.addAttribute(new BlackboardAttribute(attributeType6, + UserArtifactIngestModuleFactory.getModuleName(), bytes)); art2.addAttribute(new BlackboardAttribute(attributeType2, - UserArtifactIngestModuleFactory.getModuleName(), new byte[7])); - progressBar.progress(1); + UserArtifactIngestModuleFactory.getModuleName(), 1457105587962L)); + art2.addAttribute(new BlackboardAttribute(attributeType, + UserArtifactIngestModuleFactory.getModuleName(), 12345678L)); + art2.addAttribute(new BlackboardAttribute(attributeType3, + UserArtifactIngestModuleFactory.getModuleName(), "STRING VALUE TEST")); + art2.addAttribute(new BlackboardAttribute(attributeType4, + UserArtifactIngestModuleFactory.getModuleName(), 1234)); + art2.addAttribute(new BlackboardAttribute(attributeType5, + UserArtifactIngestModuleFactory.getModuleName(), 1234.5678D)); + art2.addAttribute(new BlackboardAttribute(attributeType6, + UserArtifactIngestModuleFactory.getModuleName(), bytes)); IngestServices.getInstance().postMessage(IngestMessage.createDataMessage( "name", // NON-NLS UserArtifactIngestModuleFactory.getModuleName(), @@ -84,9 +135,15 @@ public class UserArtifactIngestModule implements DataSourceIngestModule { @Override public void startUp(IngestJobContext context) throws IngestModuleException { try { - type1 = Case.getCurrentCase().getServices().getBlackboard().addArtifactType("This is", "a test"); //NON-NLS - type2 = Case.getCurrentCase().getServices().getBlackboard().addArtifactType("Another", "kinda test"); //NON-NLS - } catch (BlackboardException ex) { + type1 = Case.getCurrentCase().getSleuthkitCase().getArtifactType("FINAL TEST a"); + type2 = Case.getCurrentCase().getSleuthkitCase().getArtifactType("FINAL TEST b"); + if (type1 == null) { + type1 = Case.getCurrentCase().getServices().getBlackboard().addArtifactType("FINAL TEST a", "FINAL TEST a"); //NON-NLS + } + if (type2 == null) { + type2 = Case.getCurrentCase().getServices().getBlackboard().addArtifactType("FINAL TEST b", "FINAL TEST b"); //NON-NLS + } + } catch (BlackboardException | TskCoreException ex) { Logger.logMsg(Logger.ERROR, "Startup failed"); //NON-NLS } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/UserArtifacts/UserArtifactIngestModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/UserArtifacts/UserArtifactIngestModuleFactory.java index b63d9f928a..82ff77b269 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/UserArtifacts/UserArtifactIngestModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/UserArtifacts/UserArtifactIngestModuleFactory.java @@ -19,15 +19,17 @@ package org.sleuthkit.autopsy.modules.UserArtifacts; import org.openide.util.NbBundle; +import org.openide.util.lookup.ServiceProvider; import org.python.apache.xmlcommons.Version; import org.sleuthkit.autopsy.ingest.DataSourceIngestModule; +import org.sleuthkit.autopsy.ingest.IngestModuleFactory; import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; /** * Factory for test module that creates new artifact and attribute types. */ -//@ServiceProvider(service = IngestModuleFactory.class) +@ServiceProvider(service = IngestModuleFactory.class) public class UserArtifactIngestModuleFactory extends IngestModuleFactoryAdapter { static String getModuleName() { diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java index 7e0d220f11..b7f6529786 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java @@ -79,7 +79,7 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule } catch (SecurityException ex) { logger.log(Level.SEVERE, "Error initializing output dir: " + moduleDirAbsolute, ex); //NON-NLS services.postMessage(IngestMessage.createErrorMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), "Error initializing", "Error initializing output dir: " + moduleDirAbsolute)); //NON-NLS - throw new IngestModuleException(ex.getMessage()); + throw new IngestModuleException(ex.getMessage(), ex); } } @@ -87,7 +87,7 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule try { fileTypeDetector = new FileTypeDetector(); } catch (FileTypeDetector.FileTypeDetectorInitException ex) { - throw new IngestModuleException(ex.getMessage()); + throw new IngestModuleException(ex.getMessage(), ex); } // initialize the extraction modules. diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 44052df224..881e7c5fa4 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -133,7 +133,7 @@ class SevenZipExtractor { String details = NbBundle.getMessage(SevenZipExtractor.class, "EmbeddedFileExtractorIngestModule.ArchiveExtractor.init.errCantInitLib", e.getMessage()); services.postMessage(IngestMessage.createErrorMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details)); - throw new IngestModuleException(e.getMessage()); + throw new IngestModuleException(e.getMessage(), e); } } this.context = context; diff --git a/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java index de946ffd0f..b2ce0beca2 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java @@ -91,7 +91,7 @@ public final class ExifParserFileIngestModule implements FileIngestModule { try { fileTypeDetector = new FileTypeDetector(); } catch (FileTypeDetector.FileTypeDetectorInitException ex) { - throw new IngestModuleException(NbBundle.getMessage(this.getClass(), "ExifParserFileIngestModule.startUp.fileTypeDetectorInitializationException.msg")); + throw new IngestModuleException(NbBundle.getMessage(this.getClass(), "ExifParserFileIngestModule.startUp.fileTypeDetectorInitializationException.msg"), ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchIngestModule.java index e22e73ae26..c579c69014 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2014 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,13 +18,11 @@ */ package org.sleuthkit.autopsy.modules.fileextmismatch; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.logging.Level; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; @@ -40,7 +38,6 @@ import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; -import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskException; @@ -58,6 +55,7 @@ public class FileExtMismatchIngestModule implements FileIngestModule { private static final HashMap totalsForIngestJobs = new HashMap<>(); private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); private static Blackboard blackboard; + private FileTypeDetector detector; private static class IngestJobTotals { @@ -94,6 +92,11 @@ public class FileExtMismatchIngestModule implements FileIngestModule { FileExtMismatchXML xmlLoader = FileExtMismatchXML.getDefault(); SigTypeToExtMap = xmlLoader.load(); + try { + this.detector = new FileTypeDetector(); + } catch (FileTypeDetector.FileTypeDetectorInitException ex) { + throw new IngestModuleException("Could not create file type detector.", ex); + } } @@ -157,7 +160,7 @@ public class FileExtMismatchIngestModule implements FileIngestModule { if (settings.skipFilesWithNoExtension() && currActualExt.isEmpty()) { return false; } - String currActualSigType = abstractFile.getMIMEType(); + String currActualSigType = detector.getFileType(abstractFile); if (currActualSigType == null) { return false; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java index 0d82d62731..fdcf90eae5 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java @@ -35,10 +35,10 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; -import org.sleuthkit.datamodel.TskDataException; /** - * Detects the type of a file by an inspection of its contents. + * Detects the MIME type of a file by an inspection of its contents, using both + * user-defined type definitions and Tika. */ public class FileTypeDetector { @@ -49,11 +49,14 @@ public class FileTypeDetector { private static final Logger logger = Logger.getLogger(FileTypeDetector.class.getName()); /** - * Constructs an object that detects the type of a file by an inspection of - * its contents. + * Constructs an object that detects the MIME type of a file by an + * inspection of its contents, using both user-defined type definitions and + * Tika. * - * @throws FileTypeDetector.FileTypeDetectorInitException if an - * initialization error occurs. + * @throws FileTypeDetectorInitException if an initialization error occurs, + * e.g., user-defined file type + * definitions exist but cannot be + * loaded. */ public FileTypeDetector() throws FileTypeDetectorInitException { try { @@ -64,12 +67,26 @@ public class FileTypeDetector { } /** - * Determines whether or not a given MIME type is detectable by this - * detector. + * Gets the names of the user-defined MIME types. * - * @param mimeType The MIME type name, e.g. "text/html", to look up. + * @return A list of the user-defined MIME types. + */ + public List getUserDefinedTypes() { + List list = new ArrayList<>(); + if (userDefinedFileTypes != null) { + for (FileType fileType : userDefinedFileTypes) { + list.add(fileType.getMimeType()); + } + } + return list; + } + + /** + * Determines whether or not a given MIME type is detectable. * - * @return True if MIME type is detectable. + * @param mimeType The MIME type name (e.g., "text/html"). + * + * @return True if the given MIME type is detectable. */ public boolean isDetectable(String mimeType) { return isDetectableAsUserDefinedType(mimeType) || isDetectableByTika(mimeType); @@ -77,11 +94,11 @@ public class FileTypeDetector { /** * Determines whether or not a given MIME type is detectable as a - * user-defined file type. + * user-defined MIME type. * - * @param mimeType The MIME type name, e.g. "text/html", to look up. + * @param mimeType The MIME type name (e.g., "text/html"). * - * @return True if MIME type is detectable. + * @return True if the given MIME type is detectable. */ private boolean isDetectableAsUserDefinedType(String mimeType) { for (FileType fileType : userDefinedFileTypes) { @@ -95,9 +112,9 @@ public class FileTypeDetector { /** * Determines whether or not a given MIME type is detectable by Tika. * - * @param mimeType The MIME type name, e.g. "text/html", to look up. + * @param mimeType The MIME type name (e.g., "text/html"). * - * @return True if MIME type is detectable. + * @return True if the given MIME type is detectable. */ private boolean isDetectableByTika(String mimeType) { String[] split = mimeType.split("/"); @@ -112,59 +129,42 @@ public class FileTypeDetector { } /** - * Look up the MIME type of a file using the blackboard. If it is not - * already posted, detect the type of the file, posting it to the blackboard - * if detection succeeds. + * Gets the MIME type of a file, detecting it if it is not already known. If + * detection is necessary, the result is added to the case database. * - * @param file The file to test. + * @param file The file. * - * @return The MIME type name if detection was successful, null otherwise. + * @return A MIME type name. * - * @throws TskCoreException - */ - public String getFileType(AbstractFile file) throws TskCoreException { - String fileType = file.getMIMEType(); - if (null != fileType) { - return fileType; - } - return detectAndPostToBlackboard(file); - } - - /** - * Detect the MIME type of a file, posting it to the blackboard if detection - * succeeds. Note that this method should currently be called at most once - * per file. - * - * @param file The file to test. - * - * @return The MIME type name id detection was successful, null otherwise. - * - * @throws TskCoreException + * @throws TskCoreException if detection is required and there is a problem + * writing the result to the case database. */ @SuppressWarnings("deprecation") - public String detectAndPostToBlackboard(AbstractFile file) throws TskCoreException { - String mimeType = detect(file); + public String getFileType(AbstractFile file) throws TskCoreException { + String mimeType = file.getMIMEType(); if (null != mimeType) { - /** - * Add the file type attribute to the general info artifact. Note - * that no property change is fired for this blackboard posting - * because general info artifacts are different from other - * artifacts, e.g., they are not displayed in the results tree. - */ - try { - file.setMIMEType(mimeType); - BlackboardArtifact getInfoArt = file.getGenInfoArtifact(); - BlackboardAttribute batt = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG, FileTypeIdModuleFactory.getModuleName(), mimeType); - getInfoArt.addAttribute(batt); - } catch (TskDataException ex) { - //Swallowing exception so that the logs aren't clogged in the case that ingest is run multiple times. - } + return mimeType; } + + mimeType = detect(file); + Case.getCurrentCase().getSleuthkitCase().setFileMIMEType(file, mimeType); + + /* + * Add the file type attribute to the general info artifact. Note that + * no property change is fired for this blackboard posting because + * general info artifacts are different from other artifacts, e.g., they + * are not displayed in the results tree. + */ + BlackboardArtifact getInfoArt = file.getGenInfoArtifact(); + BlackboardAttribute batt = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG, FileTypeIdModuleFactory.getModuleName(), mimeType); + getInfoArt.addAttribute(batt); + return mimeType; } /** - * Detect the MIME type of a file. + * Detects the MIME type of a file. The result is not added to the case + * database. * * @param file The file to test. * @@ -173,9 +173,12 @@ public class FileTypeDetector { * @throws TskCoreException */ public String detect(AbstractFile file) throws TskCoreException { - // consistently mark non-regular files (refer TskData.TSK_FS_META_TYPE_ENUM), - // 0 sized files, unallocated, and unused blocks (refer TskData.TSK_DB_FILES_TYPE_ENUM) - // as octet-stream. + /* + * Consistently mark non-regular files (refer to + * TskData.TSK_FS_META_TYPE_ENUM), zero-sized files, unallocated space, + * and unused blocks (refer to TskData.TSK_DB_FILES_TYPE_ENUM) as + * octet-stream. + */ if (!file.isFile() || file.getSize() <= 0 || (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) || (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) @@ -183,8 +186,8 @@ public class FileTypeDetector { return MimeTypes.OCTET_STREAM; } - String fileType = detectUserDefinedType(file); - if (null == fileType) { + String mimeType = detectUserDefinedType(file); + if (null == mimeType) { try { byte buf[]; int len = file.read(buffer, 0, BUFFER_SIZE); @@ -195,23 +198,25 @@ public class FileTypeDetector { buf = buffer; } - String mimetype = tika.detect(buf, file.getName()); + String tikaType = tika.detect(buf, file.getName()); /** * Strip out any Tika enhancements to the MIME type name. */ - return mimetype.replace("tika-", ""); //NON-NLS + mimeType = tikaType.replace("tika-", ""); //NON-NLS } catch (Exception ignored) { - /** - * This exception is swallowed rather than propagated because - * files in images are not always consistent with their file - * system meta data making for read errors, and Tika can be a - * bit flaky at times, making this a best effort endeavor. + /* + * This exception is swallowed and not logged rather than + * propagated because files in data sources are not always + * consistent with their file system metadata, making for read + * errors, and Tika can be a bit flaky at times, making this a + * best effort endeavor. Default to octet-stream. */ + mimeType = MimeTypes.OCTET_STREAM; } } - return fileType; + return mimeType; } /** @@ -235,7 +240,7 @@ public class FileTypeDetector { BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, FileTypeIdModuleFactory.getModuleName(), fileType.getFilesSetName()); artifact.addAttribute(setNameAttribute); - /** + /* * Use the MIME type as the category, i.e., the rule that * determined this file belongs to the interesting files * set. @@ -259,6 +264,7 @@ public class FileTypeDetector { } public static class FileTypeDetectorInitException extends Exception { + private static final long serialVersionUID = 1L; FileTypeDetectorInitException(String message) { @@ -271,17 +277,22 @@ public class FileTypeDetector { } /** - * Gets the list of user defined file types (MIME types) + * Gets the MIME type of a file, detecting it if it is not already known. If + * detection is necessary, the result is added to the case database. * - * @return the List of user defined file types + * @param file The file. + * + * @return A MIME type name. + * + * @throws TskCoreException if detection is required and there is a problem + * writing the result to the case database. + * @deprecated Use getFileType instead and use AbstractFile.getMIMEType + * instead of querying the blackboard. */ - public List getUserDefinedTypes() { - List list = new ArrayList<>(); - if (userDefinedFileTypes != null) { - for (FileType fileType : userDefinedFileTypes) { - list.add(fileType.getMimeType()); - } - } - return list; + @Deprecated + @SuppressWarnings("deprecation") + public String detectAndPostToBlackboard(AbstractFile file) throws TskCoreException { + return getFileType(file); } + } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.form deleted file mode 100644 index 183425da42..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.form +++ /dev/null @@ -1,52 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.java deleted file mode 100644 index 658e0c00b9..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestJobSettingsPanel.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 - 2014 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.modules.filetypeid; - -import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; -import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; - -/** - * UI component used to set ingest job options for file type identifier ingest - * modules. - */ -class FileTypeIdIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPanel { - - private final FileTypeIdModuleSettings settings; - - FileTypeIdIngestJobSettingsPanel(FileTypeIdModuleSettings settings) { - this.settings = settings; - initComponents(); - customizeComponents(); - } - - /** - * @inheritDoc - */ - @Override - public IngestModuleIngestJobSettings getSettings() { - return settings; - } - - /** - * Does child component initialization in addition to that done by the - * Matisse generated code. - */ - private void customizeComponents() { - skipKnownCheckBox.setSelected(settings.skipKnownFiles()); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - skipKnownCheckBox = new javax.swing.JCheckBox(); - - skipKnownCheckBox.setSelected(true); - skipKnownCheckBox.setText(org.openide.util.NbBundle.getMessage(FileTypeIdIngestJobSettingsPanel.class, "FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.text")); // NOI18N - skipKnownCheckBox.setToolTipText(org.openide.util.NbBundle.getMessage(FileTypeIdIngestJobSettingsPanel.class, "FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.toolTipText")); // NOI18N - skipKnownCheckBox.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - skipKnownCheckBoxActionPerformed(evt); - } - }); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(10, 10, 10) - .addComponent(skipKnownCheckBox) - .addContainerGap(46, Short.MAX_VALUE)) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(11, 11, 11) - .addComponent(skipKnownCheckBox) - .addContainerGap(86, Short.MAX_VALUE)) - ); - }// //GEN-END:initComponents - - private void skipKnownCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_skipKnownCheckBoxActionPerformed - settings.setSkipKnownFiles(skipKnownCheckBox.isSelected()); - }//GEN-LAST:event_skipKnownCheckBoxActionPerformed - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JCheckBox skipKnownCheckBox; - // End of variables declaration//GEN-END:variables -} diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java index b3c09dfb81..3e6e35e8ae 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java @@ -27,7 +27,6 @@ import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestMessage; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.TskData.FileKnown; import org.sleuthkit.autopsy.ingest.IngestModule.ProcessResult; import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; @@ -38,7 +37,6 @@ import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; public class FileTypeIdIngestModule implements FileIngestModule { private static final Logger logger = Logger.getLogger(FileTypeIdIngestModule.class.getName()); - private final FileTypeIdModuleSettings settings; private long jobId; private static final HashMap totalsForIngestJobs = new HashMap<>(); private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); @@ -66,11 +64,8 @@ public class FileTypeIdIngestModule implements FileIngestModule { /** * Creates an ingest module that detects the type of a file based on * signature (magic) values. Posts results to the blackboard. - * - * @param settings The ingest module settings. */ - FileTypeIdIngestModule(FileTypeIdModuleSettings settings) { - this.settings = settings; + FileTypeIdIngestModule() { } /** @@ -83,7 +78,7 @@ public class FileTypeIdIngestModule implements FileIngestModule { try { fileTypeDetector = new FileTypeDetector(); } catch (FileTypeDetector.FileTypeDetectorInitException ex) { - throw new IngestModuleException(NbBundle.getMessage(this.getClass(), "FileTypeIdIngestModule.startUp.fileTypeDetectorInitializationException.msg")); + throw new IngestModuleException(NbBundle.getMessage(this.getClass(), "FileTypeIdIngestModule.startUp.fileTypeDetectorInitializationException.msg"), ex); } } @@ -93,13 +88,6 @@ public class FileTypeIdIngestModule implements FileIngestModule { @Override public ProcessResult process(AbstractFile file) { - /** - * Skip known files if configured to do so. - */ - if (settings.skipKnownFiles() && (file.getKnown() == FileKnown.KNOWN)) { - return ProcessResult.OK; - } - /** * Attempt to detect the file type. Do it within an exception firewall, * so that any issues with reading file content or complaints from tika @@ -153,7 +141,7 @@ public class FileTypeIdIngestModule implements FileIngestModule { * Update the match time total and increment number of files processed for * this ingest job. * - * @param jobId The ingest job identifier. + * @param jobId The ingest job identifier. * @param matchTimeInc Amount of time to add. */ private static synchronized void addToTotals(long jobId, long matchTimeInc) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java index 38823ca03d..78ccd986a0 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleFactory.java @@ -26,7 +26,6 @@ import org.sleuthkit.autopsy.ingest.IngestModuleFactory; import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; -import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; /** * A factory that creates file ingest modules that determine the types of files. @@ -92,35 +91,6 @@ public class FileTypeIdModuleFactory extends IngestModuleFactoryAdapter { return globalSettingsPanel; } - /** - * @inheritDoc - */ - @Override - public IngestModuleIngestJobSettings getDefaultIngestJobSettings() { - return new FileTypeIdModuleSettings(); - } - - /** - * @inheritDoc - */ - @Override - public boolean hasIngestJobSettingsPanel() { - return true; - } - - /** - * @inheritDoc - */ - @Override - public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) { - assert settings instanceof FileTypeIdModuleSettings; - if (!(settings instanceof FileTypeIdModuleSettings)) { - throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), - "FileTypeIdModuleFactory.getIngestJobSettingsPanel.exception.msg")); - } - return new FileTypeIdIngestJobSettingsPanel((FileTypeIdModuleSettings) settings); - } - /** * @inheritDoc */ @@ -134,11 +104,6 @@ public class FileTypeIdModuleFactory extends IngestModuleFactoryAdapter { */ @Override public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) { - assert settings instanceof FileTypeIdModuleSettings; - if (!(settings instanceof FileTypeIdModuleSettings)) { - throw new IllegalArgumentException( - NbBundle.getMessage(this.getClass(), "FileTypeIdModuleFactory.createFileIngestModule.exception.msg")); - } - return new FileTypeIdIngestModule((FileTypeIdModuleSettings) settings); + return new FileTypeIdIngestModule(); } -} +} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java deleted file mode 100755 index 8d8e4150d5..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2014 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.modules.filetypeid; - -import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; - -/** - * Ingest job options for the file type identifier ingest module instances. - */ -// TODO: This class does not need to be public. -public class FileTypeIdModuleSettings implements IngestModuleIngestJobSettings { - - private static final long serialVersionUID = 1L; - private boolean skipKnownFiles = true; - private boolean skipSmallFiles = false; // No longer used. - - FileTypeIdModuleSettings() { - } - - FileTypeIdModuleSettings(boolean skipKnownFiles) { - this.skipKnownFiles = skipKnownFiles; - } - - /** - * @inheritDoc - */ - @Override - public long getVersionNumber() { - return serialVersionUID; - } - - void setSkipKnownFiles(boolean enabled) { - skipKnownFiles = enabled; - } - - boolean skipKnownFiles() { - return skipKnownFiles; - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java index 5dd48f58f2..8f2dbaabca 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/UserDefinedFileTypesManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -59,7 +59,6 @@ import org.xml.sax.SAXException; final class UserDefinedFileTypesManager { private static final Logger logger = Logger.getLogger(UserDefinedFileTypesManager.class.getName()); - private static final String FILE_TYPE_DEFINITIONS_SCHEMA_FILE = "FileTypes.xsd"; //NON-NLS private static final String USER_DEFINED_TYPE_DEFINITIONS_FILE = "UserFileTypeDefinitions.xml"; //NON-NLS private static final String FILE_TYPES_TAG_NAME = "FileTypes"; //NON-NLS private static final String FILE_TYPE_TAG_NAME = "FileType"; //NON-NLS @@ -72,7 +71,6 @@ final class UserDefinedFileTypesManager { private static final String INTERESTING_FILES_SET_TAG_NAME = "InterestingFileSset"; //NON-NLS private static final String ALERT_ATTRIBUTE = "alert"; //NON-NLS private static final String ENCODING_FOR_XML_FILE = "UTF-8"; //NON-NLS - private static final String ASCII_ENCODING = "US-ASCII"; //NON-NLS private static UserDefinedFileTypesManager instance; /** @@ -181,7 +179,7 @@ final class UserDefinedFileTypesManager { private void loadPredefinedFileTypes() throws UserDefinedFileTypesException { byte[] byteArray; FileType fileType; - + try { // Add rule for xml fileType = new FileType("text/xml", new Signature(" newFileTypes) throws UserDefinedFileTypesException { try { @@ -317,7 +314,7 @@ final class UserDefinedFileTypesManager { * Writes a set of file type definitions to an XML file. * * @param fileTypes A collection of file types. - * @param filePath The path to the destination file. + * @param filePath The path to the destination file. * * @throws ParserConfigurationException * @throws IOException @@ -340,7 +337,7 @@ final class UserDefinedFileTypesManager { * Creates an XML representation of a file type. * * @param fileType The file type object. - * @param doc The WC3 DOM object to use to create the XML. + * @param doc The WC3 DOM object to use to create the XML. * * @return An XML element. */ @@ -356,9 +353,9 @@ final class UserDefinedFileTypesManager { /** * Add a MIME type child element to a file type XML element. * - * @param fileType The file type to use as a content source. + * @param fileType The file type to use as a content source. * @param fileTypeElem The parent file type element. - * @param doc The WC3 DOM object to use to create the XML. + * @param doc The WC3 DOM object to use to create the XML. */ private static void addMimeTypeElement(FileType fileType, Element fileTypeElem, Document doc) { Element typeNameElem = doc.createElement(MIME_TYPE_TAG_NAME); @@ -369,9 +366,9 @@ final class UserDefinedFileTypesManager { /** * Add a signature child element to a file type XML element. * - * @param fileType The file type to use as a content source. + * @param fileType The file type to use as a content source. * @param fileTypeElem The parent file type element. - * @param doc The WC3 DOM object to use to create the XML. + * @param doc The WC3 DOM object to use to create the XML. */ private static void addSignatureElement(FileType fileType, Element fileTypeElem, Document doc) { Signature signature = fileType.getSignature(); @@ -393,9 +390,9 @@ final class UserDefinedFileTypesManager { /** * Add an interesting files set element to a file type XML element. * - * @param fileType The file type to use as a content source. + * @param fileType The file type to use as a content source. * @param fileTypeElem The parent file type element. - * @param doc The WC3 DOM object to use to create the XML. + * @param doc The WC3 DOM object to use to create the XML. */ private static void addInterestingFilesSetElement(FileType fileType, Element fileTypeElem, Document doc) { if (!fileType.getFilesSetName().isEmpty()) { @@ -408,13 +405,20 @@ final class UserDefinedFileTypesManager { /** * Add an alert attribute to a file type XML element. * - * @param fileType The file type to use as a content source. + * @param fileType The file type to use as a content source. * @param fileTypeElem The parent file type element. */ private static void addAlertAttribute(FileType fileType, Element fileTypeElem) { fileTypeElem.setAttribute(ALERT_ATTRIBUTE, Boolean.toString(fileType.alertOnMatch())); } + /** + * Private constructor suppresses creation of instanmces of this utility + * class. + */ + private XmlWriter() { + } + } /** @@ -432,7 +436,17 @@ final class UserDefinedFileTypesManager { */ private static List readFileTypes(String filePath) throws IOException, ParserConfigurationException, SAXException { List fileTypes = new ArrayList<>(); - Document doc = XMLUtil.loadDocument(filePath, UserDefinedFileTypesManager.class, FILE_TYPE_DEFINITIONS_SCHEMA_FILE); + /* + * RC: Commenting out the loadDocument overload that validates + * against the XSD is a temp fix for a failure to provide an upgrade + * path when the RelativeToStart attribute was added to the + * Signature element. The upgrade path can be supplied, but the plan + * is to replace the use of XML with object serialization for the + * settings, so it may not be worth the effort. + */ + // private static final String FILE_TYPE_DEFINITIONS_SCHEMA_FILE = "FileTypes.xsd"; //NON-NLS + // Document doc = XMLUtil.loadDocument(filePath, UserDefinedFileTypesManager.class, FILE_TYPE_DEFINITIONS_SCHEMA_FILE); + Document doc = XMLUtil.loadDocument(filePath); if (doc != null) { Element fileTypesElem = doc.getDocumentElement(); if (fileTypesElem != null && fileTypesElem.getNodeName().equals(FILE_TYPES_TAG_NAME)) { @@ -496,14 +510,16 @@ final class UserDefinedFileTypesManager { Element offsetElem = (Element) signatureElem.getElementsByTagName(OFFSET_TAG_NAME).item(0); String offsetString = offsetElem.getTextContent(); long offset = DatatypeConverter.parseLong(offsetString); - - String relativeString = offsetElem.getAttribute(RELATIVE_ATTRIBUTE); - if(relativeString == null || relativeString.equals("")) - return new Signature(signatureBytes, offset, signatureType); - - boolean isRelative = DatatypeConverter.parseBoolean(relativeString); - return new Signature(signatureBytes, offset, signatureType, isRelative); + boolean isRelativeToStart; + String relativeString = offsetElem.getAttribute(RELATIVE_ATTRIBUTE); + if (null == relativeString || relativeString.equals("")) { + isRelativeToStart = true; + } else { + isRelativeToStart = DatatypeConverter.parseBoolean(relativeString); + } + + return new Signature(signatureBytes, offset, signatureType, isRelativeToStart); } /** @@ -538,7 +554,7 @@ final class UserDefinedFileTypesManager { /** * Gets the text content of a single child element. * - * @param elem The parent element. + * @param elem The parent element. * @param tagName The tag name of the child element. * * @return The text content or null if the tag doesn't exist. @@ -546,21 +562,29 @@ final class UserDefinedFileTypesManager { private static String getChildElementTextContent(Element elem, String tagName) { NodeList childElems = elem.getElementsByTagName(tagName); Node childNode = childElems.item(0); - if(childNode == null) + if (childNode == null) { return null; + } Element childElem = (Element) childNode; return childElem.getTextContent(); } + /** + * Private constructor suppresses creation of instanmces of this utility + * class. + */ + private XmlReader() { + } + } /** * Logs an exception, bundles the exception with a simple message in a * uniform exception type, and throws the wrapper exception. * - * @param ex The exception to wrap. + * @param ex The exception to wrap. * @param messageKey A key into the bundle file that maps to the desired - * message. + * message. * * @throws * org.sleuthkit.autopsy.modules.filetypeid.UserDefinedFileTypesManager.UserDefinedFileTypesException @@ -578,6 +602,8 @@ final class UserDefinedFileTypesManager { */ static class UserDefinedFileTypesException extends Exception { + private static final long serialVersionUID = 1L; + UserDefinedFileTypesException(String message) { super(message); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java index f848838d02..16ae16e4bd 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java @@ -152,7 +152,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { // Initialize job totals initTotalsForIngestJob(jobId); } catch (SecurityException | IOException | UnsupportedOperationException ex) { - throw new IngestModule.IngestModuleException(NbBundle.getMessage(PhotoRecCarverFileIngestModule.class, "cannotCreateOutputDir.message", ex.getLocalizedMessage())); + throw new IngestModule.IngestModuleException(NbBundle.getMessage(PhotoRecCarverFileIngestModule.class, "cannotCreateOutputDir.message", ex.getLocalizedMessage()), ex); } } } @@ -396,7 +396,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { } catch (FileAlreadyExistsException ex) { // No worries. } catch (IOException | SecurityException | UnsupportedOperationException ex) { - throw new IngestModule.IngestModuleException(NbBundle.getMessage(PhotoRecCarverFileIngestModule.class, "cannotCreateOutputDir.message", ex.getLocalizedMessage())); + throw new IngestModule.IngestModuleException(NbBundle.getMessage(PhotoRecCarverFileIngestModule.class, "cannotCreateOutputDir.message", ex.getLocalizedMessage()), ex); } return path; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAccountObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAccountObj.java index eaec84d5d1..d2a6b19551 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAccountObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAccountObj.java @@ -115,15 +115,15 @@ class EvalAccountObj extends EvaluatableObject { boolean foundSIDMatch = false; for (BlackboardAttribute attr : art.getAttributes()) { - if ((attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID()) + if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID()) && (haveHomeDir)) { foundHomeDirMatch = compareStringObject(userAccountObj.getHomeDirectory(), attr.getValueString()); } - if ((attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME.getTypeID()) + if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME.getTypeID()) && (haveUsername)) { foundUsernameMatch = compareStringObject(userAccountObj.getUsername(), attr.getValueString()); } - if ((attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID.getTypeID()) + if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID.getTypeID()) && (haveSID) && (winUserObj != null)) { foundSIDMatch = compareStringObject(winUserObj.getSecurityID(), attr.getValueString()); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAddressObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAddressObj.java index 2df8ffe93e..faaac1dc4e 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAddressObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalAddressObj.java @@ -117,7 +117,7 @@ class EvalAddressObj extends EvaluatableObject { for (BlackboardArtifact art : artList) { for (BlackboardAttribute attr : art.getAttributes()) { - if (attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) { + if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) { if (compareStringObject(addressStr, obj.getAddressValue().getCondition(), obj.getAddressValue().getApplyCondition(), attr.getValueString())) { finalHits.add(art); diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalDomainObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalDomainObj.java index 03a8041c1f..2dd6c7f680 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalDomainObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalDomainObj.java @@ -80,7 +80,7 @@ class EvalDomainObj extends EvaluatableObject { for (BlackboardArtifact art : artList) { for (BlackboardAttribute attr : art.getAttributes()) { - if (attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) { + if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) { String url = attr.getValueString(); // Check whether the domain name is a substring of the URL (regardless diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalNetworkShareObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalNetworkShareObj.java index 98c0d9d95a..843f19c293 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalNetworkShareObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalNetworkShareObj.java @@ -98,11 +98,11 @@ class EvalNetworkShareObj extends EvaluatableObject { boolean foundLocalPathMatch = false; for (BlackboardAttribute attr : art.getAttributes()) { - if ((attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REMOTE_PATH.getTypeID()) + if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REMOTE_PATH.getTypeID()) && (obj.getNetname() != null)) { foundRemotePathMatch = compareStringObject(obj.getNetname(), attr.getValueString()); } - if ((attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCAL_PATH.getTypeID()) + if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCAL_PATH.getTypeID()) && (obj.getLocalPath() != null)) { foundLocalPathMatch = compareStringObject(obj.getLocalPath(), attr.getValueString()); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURIObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURIObj.java index d7ce6b8c7e..c5e598b034 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURIObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURIObj.java @@ -108,7 +108,7 @@ class EvalURIObj extends EvaluatableObject { for (BlackboardArtifact art : artList) { for (BlackboardAttribute attr : art.getAttributes()) { - if (attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) { + if (attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) { String modifiedAttrString = attr.getValueString(); if (modifiedAttrString != null) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURLHistoryObj.java b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURLHistoryObj.java index 416784dd81..f6a6b67075 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURLHistoryObj.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/EvalURLHistoryObj.java @@ -152,7 +152,7 @@ class EvalURLHistoryObj extends EvaluatableObject { boolean foundBrowserNameMatch = false; for (BlackboardAttribute attr : art.getAttributes()) { - if ((attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL.getTypeID()) + if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL.getTypeID()) && (haveURL)) { if (entry.getURL().getValue() instanceof AnyURIObjectPropertyType) { foundURLMatch = compareStringObject(entry.getURL().getValue().getValue().toString(), @@ -163,12 +163,12 @@ class EvalURLHistoryObj extends EvaluatableObject { addWarning("Non-AnyURIObjectPropertyType found in URL value field"); //NON-NLS } } - if ((attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID()) + if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID()) && (haveHostname)) { foundHostnameMatch = compareStringObject(entry.getHostname().getHostnameValue(), attr.getValueString()); } - if ((attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REFERRER.getTypeID()) + if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REFERRER.getTypeID()) && (haveReferrer)) { if (entry.getReferrerURL().getValue() instanceof AnyURIObjectPropertyType) { foundReferrerMatch = compareStringObject(entry.getReferrerURL().getValue().getValue().toString(), @@ -179,17 +179,17 @@ class EvalURLHistoryObj extends EvaluatableObject { addWarning("Non-AnyURIObjectPropertyType found in URL value field"); //NON-NLS } } - if ((attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE.getTypeID()) + if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE.getTypeID()) && (havePageTitle)) { foundPageTitleMatch = compareStringObject(entry.getPageTitle(), attr.getValueString()); } - if ((attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME.getTypeID()) + if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME.getTypeID()) && (haveUserProfile)) { foundUserProfileMatch = compareStringObject(entry.getUserProfileName(), attr.getValueString()); } - if ((attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID()) + if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID()) && (haveBrowserName)) { foundBrowserNameMatch = compareStringObject(obj.getBrowserInformation().getName(), null, null, attr.getValueString()); @@ -240,7 +240,7 @@ class EvalURLHistoryObj extends EvaluatableObject { boolean foundBrowserNameMatch = false; for (BlackboardAttribute attr : art.getAttributes()) { - if ((attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID()) + if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID()) && (haveBrowserName)) { foundBrowserNameMatch = compareStringObject(obj.getBrowserInformation().getName(), null, null, attr.getValueString()); diff --git a/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.form b/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.form index c4bd675f90..76a6f6cec7 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.form +++ b/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.form @@ -87,7 +87,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java b/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java index a75ab43848..bfdc9deca9 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java +++ b/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.EnumMap; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; @@ -40,15 +41,14 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.TskCoreException; public class ArtifactSelectionDialog extends javax.swing.JDialog { private ArtifactModel model; private ArtifactRenderer renderer; - private Map artifactStates; - private List artifacts; + private Map artifactTypeSelections; + private List artifactTypes; /** * Creates new form ArtifactSelectionDialog @@ -61,27 +61,31 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog { } /** - * Populate the list of artifacts with all important artifacts. + * Populate the list of artifact types with all important artifact types. */ @SuppressWarnings("deprecation") private void populateList() { try { - ArrayList doNotReport = new ArrayList<>(); - doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO); - doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_TOOL_OUTPUT); // output is too unstructured for table review. + ArrayList doNotReport = new ArrayList<>(); + doNotReport.add(new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO.getTypeID(), + BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO.getLabel(), + BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO.getDisplayName())); + doNotReport.add(new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getTypeID(), + BlackboardArtifact.ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getLabel(), + BlackboardArtifact.ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getDisplayName())); // output is too unstructured for table review - artifacts = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTypesInUse(); - artifacts.removeAll(doNotReport); - Collections.sort(artifacts, new Comparator() { + artifactTypes = Case.getCurrentCase().getSleuthkitCase().getArtifactTypesInUse(); + artifactTypes.removeAll(doNotReport); + Collections.sort(artifactTypes, new Comparator() { @Override - public int compare(ARTIFACT_TYPE o1, ARTIFACT_TYPE o2) { + public int compare(BlackboardArtifact.Type o1, BlackboardArtifact.Type o2) { return o1.getDisplayName().compareTo(o2.getDisplayName()); } }); - artifactStates = new EnumMap<>(BlackboardArtifact.ARTIFACT_TYPE.class); - for (BlackboardArtifact.ARTIFACT_TYPE type : artifacts) { - artifactStates.put(type, Boolean.TRUE); + artifactTypeSelections = new HashMap<>(); + for (BlackboardArtifact.Type type : artifactTypes) { + artifactTypeSelections.put(type, Boolean.TRUE); } } catch (TskCoreException ex) { Logger.getLogger(ArtifactSelectionDialog.class.getName()).log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage()); //NON-NLS @@ -99,17 +103,19 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog { @Override public void mousePressed(MouseEvent evt) { int index = artifactList.locationToIndex(evt.getPoint()); - BlackboardArtifact.ARTIFACT_TYPE type = model.getElementAt(index); - artifactStates.put(type, !artifactStates.get(type)); + BlackboardArtifact.Type type = model.getElementAt(index); + artifactTypeSelections.put(type, !artifactTypeSelections.get(type)); artifactList.repaint(); } }); } /** - * Display this dialog, and return the selected artifacts. + * Display this dialog, and return the selected artifactTypes. + * + * @return The state of artifact types displayed */ - Map display() { + Map display() { this.setTitle(NbBundle.getMessage(this.getClass(), "ArtifactSelectionDialog.dlgTitle.text")); Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); // set the popUp window / JFrame @@ -120,7 +126,7 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog { setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); this.setVisible(true); - return artifactStates; + return artifactTypeSelections; } /** @@ -215,20 +221,20 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog { }//GEN-LAST:event_okButtonActionPerformed private void selectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectAllButtonActionPerformed - for (ARTIFACT_TYPE type : artifacts) { - artifactStates.put(type, Boolean.TRUE); + for (BlackboardArtifact.Type type : artifactTypes) { + artifactTypeSelections.put(type, Boolean.TRUE); } artifactList.repaint(); }//GEN-LAST:event_selectAllButtonActionPerformed private void deselectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deselectAllButtonActionPerformed - for (ARTIFACT_TYPE type : artifacts) { - artifactStates.put(type, Boolean.FALSE); + for (BlackboardArtifact.Type type : artifactTypes) { + artifactTypeSelections.put(type, Boolean.FALSE); } artifactList.repaint(); }//GEN-LAST:event_deselectAllButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JList artifactList; + private javax.swing.JList artifactList; private javax.swing.JScrollPane artifactScrollPane; private javax.swing.JButton deselectAllButton; private javax.swing.JButton okButton; @@ -236,16 +242,16 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog { private javax.swing.JLabel titleLabel; // End of variables declaration//GEN-END:variables - private class ArtifactModel implements ListModel { + private class ArtifactModel implements ListModel { @Override public int getSize() { - return artifacts.size(); + return artifactTypes.size(); } @Override - public ARTIFACT_TYPE getElementAt(int index) { - return artifacts.get(index); + public BlackboardArtifact.Type getElementAt(int index) { + return artifactTypes.get(index); } @Override @@ -257,13 +263,13 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog { } } - private class ArtifactRenderer extends JCheckBox implements ListCellRenderer { + private class ArtifactRenderer extends JCheckBox implements ListCellRenderer { @Override - public Component getListCellRendererComponent(JList list, ARTIFACT_TYPE value, int index, boolean isSelected, boolean cellHasFocus) { + public Component getListCellRendererComponent(JList list, BlackboardArtifact.Type value, int index, boolean isSelected, boolean cellHasFocus) { if (value != null) { setEnabled(list.isEnabled()); - setSelected(artifactStates.get(value)); + setSelected(artifactTypeSelections.get(value)); setFont(list.getFont()); setBackground(list.getBackground()); setForeground(list.getForeground()); diff --git a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties index 5e74024afe..d535c310f4 100644 --- a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties @@ -71,8 +71,6 @@ ReportGenerator.artifactTable.taggedResults.text=Contains results that were tagg ReportGenerator.progress.processing=Now processing {0}... ReportGenerator.msgShow.skippingArtType.title=Skipping artifact type {0} in reports ReportGenerator.msgShow.skippingArtType.msg=Unknown columns to report on -ReportGenerator.msgShow.skippingArtRow.title=Skipping artifact rows for type {0} in reports -ReportGenerator.msgShow.skippingArtRow.msg=Unknown columns to report on ReportGenerator.makeContTagTab.taggedFiles.msg=Contains files that were tagged with one of the following\: ReportGenerator.makeBbArtTagTab.taggedRes.msg=This report only includes results tagged with\: ReportGenerator.tagTable.header.resultType=Result Type diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 13aaf200dc..17bf5b511a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -41,6 +42,9 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.JDialog; @@ -66,6 +70,7 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.datamodel.BlackboardAttribute.Type; /** * Instances of this class use GeneralReportModules, TableReportModules and @@ -83,6 +88,7 @@ class ReportGenerator { private Map tableProgress; private Map generalProgress; private Map fileProgress; + private Map> columnHeaderMap; private String reportPath; private ReportGenerationPanel panel = new ReportGenerationPanel(); @@ -132,18 +138,19 @@ class ReportGenerator { tableProgress = new HashMap<>(); fileProgress = new HashMap<>(); setupProgressPanels(tableModuleStates, generalModuleStates, fileListModuleStates); + this.columnHeaderMap = new HashMap<>(); } /** * Create a ReportProgressPanel for each report generation module selected * by the user. * - * @param tableModuleStates The enabled/disabled state of each - * TableReportModule - * @param generalModuleStates The enabled/disabled state of each - * GeneralReportModule + * @param tableModuleStates The enabled/disabled state of each + * TableReportModule + * @param generalModuleStates The enabled/disabled state of each + * GeneralReportModule * @param fileListModuleStates The enabled/disabled state of each - * FileReportModule + * FileReportModule */ private void setupProgressPanels(Map tableModuleStates, Map generalModuleStates, Map fileListModuleStates) { if (null != tableModuleStates) { @@ -235,11 +242,11 @@ class ReportGenerator { * Run the TableReportModules using a SwingWorker. * * @param artifactTypeSelections the enabled/disabled state of the artifact - * types to be included in the report - * @param tagSelections the enabled/disabled state of the tag names to be - * included in the report + * types to be included in the report + * @param tagSelections the enabled/disabled state of the tag names + * to be included in the report */ - public void generateTableReports(Map artifactTypeSelections, Map tagNameSelections) { + public void generateTableReports(Map artifactTypeSelections, Map tagNameSelections) { if (!tableProgress.isEmpty() && null != artifactTypeSelections) { TableReportsWorker worker = new TableReportsWorker(artifactTypeSelections, tagNameSelections); worker.execute(); @@ -250,7 +257,7 @@ class ReportGenerator { * Run the FileReportModules using a SwingWorker. * * @param enabledInfo the Information that should be included about each - * file in the report. + * file in the report. */ public void generateFileListReports(Map enabledInfo) { if (!fileProgress.isEmpty() && null != enabledInfo) { @@ -420,19 +427,19 @@ class ReportGenerator { private class TableReportsWorker extends SwingWorker { private List tableModules = new ArrayList<>(); - private List artifactTypes = new ArrayList<>(); + private List artifactTypes = new ArrayList<>(); private HashSet tagNamesFilter = new HashSet<>(); private List images = new ArrayList<>(); - TableReportsWorker(Map artifactTypeSelections, Map tagNameSelections) { + TableReportsWorker(Map artifactTypeSelections, Map tagNameSelections) { // Get the report modules selected by the user. for (Entry entry : tableProgress.entrySet()) { tableModules.add(entry.getKey()); } // Get the artifact types selected by the user. - for (Entry entry : artifactTypeSelections.entrySet()) { + for (Entry entry : artifactTypeSelections.entrySet()) { if (entry.getValue()) { artifactTypes.add(entry.getKey()); } @@ -457,7 +464,7 @@ class ReportGenerator { module.startReport(reportPath); progress.start(); progress.setIndeterminate(false); - progress.setMaximumProgress(ARTIFACT_TYPE.values().length + 2); // +2 for content and blackboard artifact tags + progress.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags } } @@ -492,7 +499,7 @@ class ReportGenerator { } // Add a table to the report for every enabled blackboard artifact type. - for (ARTIFACT_TYPE type : artifactTypes) { + for (BlackboardArtifact.Type type : artifactTypes) { // Check for cancellaton. removeCancelledTableReportModules(); if (tableModules.isEmpty()) { @@ -506,62 +513,61 @@ class ReportGenerator { } // Keyword hits and hashset hit artifacts get special handling. - if (type.equals(ARTIFACT_TYPE.TSK_KEYWORD_HIT)) { + if (type.getTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { writeKeywordHits(tableModules, comment.toString(), tagNamesFilter); continue; - } else if (type.equals(ARTIFACT_TYPE.TSK_HASHSET_HIT)) { + } else if (type.getTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { writeHashsetHits(tableModules, comment.toString(), tagNamesFilter); continue; } - List unsortedArtifacts = getFilteredArtifacts(type, tagNamesFilter); + List artifactList = getFilteredArtifacts(type, tagNamesFilter); - if (unsortedArtifacts.isEmpty()) { + if (artifactList.isEmpty()) { continue; } - // The most efficient way to sort all the Artifacts is to add them to a List, and then - // sort that List based off a Comparator. Adding to a TreeMap/Set/List sorts the list - // each time an element is added, which adds unnecessary overhead if we only need it sorted once. - Collections.sort(unsortedArtifacts); - - // Get the column headers appropriate for the artifact type. /* - * @@@ BC: Seems like a better design here would be to have a - * method that takes in the artifact as an argument and returns - * the attributes. We then use that to make the headers and to - * make each row afterwards so that we don't have - * artifact-specific logic in both getArtifactTableCoumnHeaders - * and ArtifactData.getRow() + Gets all of the attribute types of this artifact type by adding + all of the types to a set */ - List columnHeaders = getArtifactTableColumnHeaders(type.getTypeID()); - if (columnHeaders == null) { - // @@@ Hack to prevent system from hanging. Better solution is to merge all attributes into a single column or analyze the artifacts to find out how many are needed. + Set attrTypeSet = new TreeSet<>((Type o1, Type o2) -> o1.getDisplayName().compareTo(o2.getDisplayName())); + for (ArtifactData data : artifactList) { + List attributes = data.getAttributes(); + for (BlackboardAttribute attribute : attributes) { + attrTypeSet.add(attribute.getAttributeType()); + } + } + // Get the columns appropriate for the artifact type. This is + // used to get the data that will be in the cells below based on + // type, and display the column headers. + List columns = getArtifactTableColumns(type.getTypeID(), attrTypeSet); + if (columns.isEmpty()) { continue; } + ReportGenerator.this.columnHeaderMap.put(type.getTypeID(), columns); + + // The artifact list is sorted now, as getting the row data is + // dependent on having the columns, which is necessary for + // sorting. + Collections.sort(artifactList); + List columnHeaderNames = new ArrayList<>(); + for (Column currColumn : columns) { + columnHeaderNames.add(currColumn.getColumnHeader()); + } for (TableReportModule module : tableModules) { module.startDataType(type.getDisplayName(), comment.toString()); - module.startTable(columnHeaders); + module.startTable(columnHeaderNames); } - - boolean msgSent = false; - for (ArtifactData artifactData : unsortedArtifacts) { + for (ArtifactData artifactData : artifactList) { // Add the row data to all of the reports. for (TableReportModule module : tableModules) { - // Get the row data for this type of artifact. + // Get the row data for this artifact, and has the + // module add it. List rowData = artifactData.getRow(); if (rowData.isEmpty()) { - if (msgSent == false) { - MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), - "ReportGenerator.msgShow.skippingArtRow.title", - type), - NbBundle.getMessage(this.getClass(), - "ReportGenerator.msgShow.skippingArtRow.msg"), - MessageNotifyUtil.MessageType.ERROR); - msgSent = true; - } continue; } @@ -870,15 +876,15 @@ class ReportGenerator { * Get a List of the artifacts and data of the given type that pass the * given Tag Filter. * - * @param type The artifact type to get + * @param type The artifact type to get * @param tagNamesFilter The tag names that should be included. * * @return a list of the filtered tags. */ - private List getFilteredArtifacts(ARTIFACT_TYPE type, HashSet tagNamesFilter) { + private List getFilteredArtifacts(BlackboardArtifact.Type type, HashSet tagNamesFilter) { List artifacts = new ArrayList<>(); try { - for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(type)) { + for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(type.getTypeID())) { List tags = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact); HashSet uniqueTagNames = new HashSet<>(); for (BlackboardArtifactTag tag : tags) { @@ -1046,7 +1052,10 @@ class ReportGenerator { currentKeyword = keyword; for (TableReportModule module : tableModules) { module.addSetElement(currentKeyword); - module.startTable(getArtifactTableColumnHeaders(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())); + List columnHeaderNames = new ArrayList<>(); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")); + module.startTable(columnHeaderNames); } } @@ -1178,7 +1187,10 @@ class ReportGenerator { currentSet = set; for (TableReportModule module : tableModules) { module.startSet(currentSet); - module.startTable(getArtifactTableColumnHeaders(ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID())); + List columnHeaderNames = new ArrayList<>(); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size")); + module.startTable(columnHeaderNames); tableProgress.get(module).updateStatusLabel( NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), currentSet)); @@ -1203,335 +1215,523 @@ class ReportGenerator { } /** - * For a given artifact type ID, return the list of the row titles we're + * For a given artifact type ID, return the list of the columns that we are * reporting on. * - * @param artifactTypeId artifact type ID + * @param artifactTypeId artifact type ID + * @param attributeTypeSet The set of attributeTypeSet available for this + * artifact type * * @return List row titles */ - private List getArtifactTableColumnHeaders(int artifactTypeId) { - ArrayList columnHeaders; + private List getArtifactTableColumns(int artifactTypeId, Set attributeTypeSet) { + ArrayList columns = new ArrayList<>(); - BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactTypeId); - switch (type) { - case TSK_WEB_BOOKMARK: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.title"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateCreated"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_WEB_COOKIE: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.value"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_WEB_HISTORY: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.referrer"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.title"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.urlDomainDecoded"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_WEB_DOWNLOAD: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dest"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.sourceUrl"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_RECENT_OBJECT: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.path"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_INSTALLED_PROG: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.progName"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.instDateTime"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_KEYWORD_HIT: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_HASHSET_HIT: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size")})); - break; - case TSK_DEVICE_ATTACHED: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devMake"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devModel"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceId"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_WEB_SEARCH_QUERY: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.text"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.domain"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.progName"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_METADATA_EXIF: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTaken"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devManufacturer"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devModel"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_CONTACT: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumber"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumHome"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumOffice"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumMobile"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.email"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_MESSAGE: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.msgType"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.direction"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.readStatus"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromPhoneNum"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromEmail"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toPhoneNum"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toEmail"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.subject"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.text"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_CALLLOG: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromPhoneNum"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toPhoneNum"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.direction"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_CALENDAR_ENTRY: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.calendarEntryType"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.description"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.startDateTime"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.endDateTime"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.location"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_SPEED_DIAL_ENTRY: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.shortCut"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumber"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_BLUETOOTH_PAIRING: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceName"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceAddress"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_GPS_TRACKPOINT: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_GPS_BOOKMARK: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_GPS_LAST_KNOWN_LOCATION: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_GPS_SEARCH: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_SERVICE_ACCOUNT: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.category"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userId"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.password"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.appName"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.appPath"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.description"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.replytoAddress"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.mailServer"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_ENCRYPTION_DETECTED: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_EXT_MISMATCH_DETECTED: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.extension.text"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.mimeType.text"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.path")})); - break; - case TSK_OS_INFO: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.processorArchitecture.text"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.osName.text"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.osInstallDate.text"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")})); - break; - case TSK_EMAIL_MSG: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailTo"), //TSK_EMAIL_TO - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailFrom"), //TSK_EMAIL_FROM - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSubject"), //TSK_SUBJECT - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskDateTimeSent"), //TSK_DATETIME_SENT - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskDateTimeRcvd"), //TSK_DATETIME_RCVD - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskPath"), //TSK_PATH - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailCc"), //TSK_EMAIL_CC - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailBcc"), //TSK_EMAIL_BCC - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskMsgId")})); //TSK_MSG_ID - break; - case TSK_INTERESTING_FILE_HIT: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSetName"), //TSK_SET_NAME - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskInterestingFilesCategory"), //TSK_CATEGORY - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskPath")})); //TSK_PATH - break; - case TSK_GPS_ROUTE: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskGpsRouteCategory"), //TSK_CATEGORY - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), //TSK_DATETIME - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitudeEnd"), //TSK_GEO_LATITUDE_END - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitudeEnd"), //TSK_GEO_LONGITUDE_END - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitudeStart"), //TSK_GEO_LATITUDE_START - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitudeStart"), //TSK_GEO_LONGITUDE_START - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), //TSK_NAME - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.location"), //TSK_LOCATION - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program")}));//TSK_PROG_NAME - break; - case TSK_INTERESTING_ARTIFACT_HIT: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSetName"), //TSK_SET_NAME - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.associatedArtifact"), //TSK_ASSOCIATED_ARTIFACT - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program")})); //TSK_PROG_NAME - break; - case TSK_PROG_RUN: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), //TSK_PROG_NAME - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.associatedArtifact"), //TSK_ASSOCIATED_ARTIFACT - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), //TSK_DATETIME - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.count")})); //TSK_COUNT - break; + // Long switch statement to retain ordering of attribute types that are + // attached to pre-defined artifact types. + if (ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL))); - case TSK_OS_ACCOUNT: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userName"), //TSK_USER_NAME - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userId")})); //TSK_USER_ID - break; + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.title"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_TITLE))); - case TSK_REMOTE_DRIVE: - columnHeaders = new ArrayList<>(Arrays.asList(new String[]{ - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.localPath"), //TSK_LOCAL_PATH - NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.remotePath")})); //TSK_REMOTE_PATH - break; - default: - return null; - } - columnHeaders.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateCreated"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED))); - return columnHeaders; - } + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); - /** - * Map all BlackboardAttributes' values in a list of BlackboardAttributes to - * each attribute's attribute type ID, using module's dateToString method - * for date/time conversions if a module is supplied. - * - * @param attList list of BlackboardAttributes to be mapped - * @param module the TableReportModule the mapping is for - * - * @return Map of the BlackboardAttributes mapped to their - * attribute type ID - */ - public Map getMappedAttributes(List attList, TableReportModule... module) { - Map attributes = new HashMap<>(); - int size = ATTRIBUTE_TYPE.values().length; - for (int n = 0; n <= size; n++) { - attributes.put(n, ""); - } - for (BlackboardAttribute tempatt : attList) { - String value = ""; - Integer type = tempatt.getAttributeTypeID(); - if (type.equals(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID()) - || type.equals(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID()) - || type.equals(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID()) - || type.equals(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED.getTypeID()) - || type.equals(ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID()) - || type.equals(ATTRIBUTE_TYPE.TSK_DATETIME_RCVD.getTypeID()) - || type.equals(ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID()) - || type.equals(ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID())) { - if (module.length > 0) { - value = module[0].dateToString(tempatt.getValueLong()); - } else { - SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); - value = sdf.format(new java.util.Date((tempatt.getValueLong() * 1000))); - } - } else { - value = tempatt.getDisplayString(); + } else if (ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.value"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_VALUE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.referrer"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_REFERRER))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.title"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_TITLE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.urlDomainDecoded"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL_DECODED))); + + } else if (ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dest"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.sourceUrl"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.path"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.progName"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.instDateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() == artifactTypeId) { + columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview"))); + + } else if (ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() == artifactTypeId) { + columns.add(new SourceFileColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file"))); + + columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size"))); + + } else if (ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devMake"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devModel"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceId"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_ID))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.text"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_TEXT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.domain"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.progName"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTaken"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devManufacturer"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devModel"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); + + } else if (ARTIFACT_TYPE.TSK_CONTACT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumber"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumHome"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_HOME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumOffice"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_OFFICE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumMobile"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_MOBILE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.email"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL))); + + } else if (ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.msgType"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.direction"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DIRECTION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.readStatus"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_READ_STATUS))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromPhoneNum"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromEmail"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_FROM))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toPhoneNum"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toEmail"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_TO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.subject"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SUBJECT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.text"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_TEXT))); + + } else if (ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromPhoneNum"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toPhoneNum"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_START))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.direction"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DIRECTION))); + + } else if (ARTIFACT_TYPE.TSK_CALENDAR_ENTRY.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.calendarEntryType"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CALENDAR_ENTRY_TYPE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.description"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DESCRIPTION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.startDateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_START))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.endDateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_END))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.location"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_LOCATION))); + + } else if (ARTIFACT_TYPE.TSK_SPEED_DIAL_ENTRY.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.shortCut"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SHORTCUT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME_PERSON))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumber"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))); + + } else if (ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceName"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceAddress"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DEVICE_ID))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (ARTIFACT_TYPE.TSK_GPS_BOOKMARK.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_LOCATION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_LOCATION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (ARTIFACT_TYPE.TSK_GPS_SEARCH.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_LOCATION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.category"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CATEGORY))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userId"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_ID))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.password"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PASSWORD))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.appName"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.appPath"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.description"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DESCRIPTION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.replytoAddress"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_REPLYTO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.mailServer"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SERVER_NAME))); + + } else if (ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); + + } else if (ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() == artifactTypeId) { + columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file"))); + + columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.extension.text"))); + + columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.mimeType.text"))); + + columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.path"))); + + } else if (ARTIFACT_TYPE.TSK_OS_INFO.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.processorArchitecture.text"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROCESSOR_ARCHITECTURE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.osName.text"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.osInstallDate.text"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailTo"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_TO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailFrom"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_FROM))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSubject"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SUBJECT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskDateTimeSent"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_SENT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskDateTimeRcvd"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_RCVD))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskPath"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailCc"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_CC))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailBcc"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_EMAIL_BCC))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskMsgId"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_MSG_ID))); + + } else if (ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSetName"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskInterestingFilesCategory"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CATEGORY))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskPath"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH))); + + } else if (ARTIFACT_TYPE.TSK_GPS_ROUTE.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskGpsRouteCategory"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CATEGORY))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitudeEnd"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitudeEnd"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitudeStart"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitudeStart"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.location"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_LOCATION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSetName"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.associatedArtifact"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.associatedArtifact"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.count"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_COUNT))); + + } else if (ARTIFACT_TYPE.TSK_OS_ACCOUNT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userName"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userId"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_ID))); + + } else if (ARTIFACT_TYPE.TSK_REMOTE_DRIVE.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.localPath"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_LOCAL_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.remotePath"), + new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_REMOTE_PATH))); + } else { + // This is the case that it is a custom type. The reason an else is + // necessary is to make sure that the source file column is added + for (BlackboardAttribute.Type type : attributeTypeSet) { + columns.add(new AttributeColumn(type.getDisplayName(), type)); } + columns.add(new SourceFileColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile"))); + columns.add(new TaggedResultsColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags"))); - if (value == null) { - value = ""; - } - value = EscapeUtil.escapeHtml(value); - attributes.put(type, value); + // Short circuits to guarantee that the attribute types aren't added + // twice. + return columns; } - return attributes; + // If it is an attribute column, it removes the attribute type of that + // column from the set, so types are not reported more than once. + for (Column column : columns) { + attributeTypeSet = column.removeTypeFromSet(attributeTypeSet); + } + // Now uses the remaining types in the set to construct columns + for (BlackboardAttribute.Type type : attributeTypeSet) { + columns.add(new AttributeColumn(type.getDisplayName(), type)); + } + // Source file column is added here for ordering purposes. + if (artifactTypeId == ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_CONTACT.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_CALENDAR_ENTRY.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_SPEED_DIAL_ENTRY.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_GPS_BOOKMARK.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_GPS_SEARCH.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() + || artifactTypeId == ARTIFACT_TYPE.TSK_OS_INFO.getTypeID()) { + columns.add(new SourceFileColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile"))); + } + columns.add(new TaggedResultsColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags"))); + + return columns; } /** @@ -1570,6 +1770,7 @@ class ReportGenerator { logger.log(Level.WARNING, "Failed to get Abstract File by ID.", ex); //NON-NLS } return ""; + } /** @@ -1611,7 +1812,8 @@ class ReportGenerator { /** * Compares ArtifactData objects by the first attribute they have in - * common in their List. + * common in their List. Should only be used on two + * artifacts of the same type * * If all attributes are the same, they are assumed duplicates and are * compared by their artifact id. Should only be used with attributes of @@ -1627,22 +1829,32 @@ class ReportGenerator { return compare; } } - // If all attributes are the same, they're most likely duplicates so sort by artifact ID return ((Long) this.getArtifactID()).compareTo((Long) otherArtifactData.getArtifactID()); } /** * Get the values for each row in the table report. + * + * the value types of custom artifacts + * + * @return A list of string representing the data for this artifact. */ public List getRow() { if (rowData == null) { try { rowData = getOrderedRowDataAsStrings(); - // replace null values if attribute was not defined - for (int i = 0; i < rowData.size(); i++) { - if (rowData.get(i) == null) { - rowData.set(i, ""); + // If else is done so that row data is not set before + // columns are added to the hash map. + if (rowData.size() > 0) { + // replace null values if attribute was not defined + for (int i = 0; i < rowData.size(); i++) { + if (rowData.get(i) == null) { + rowData.set(i, ""); + } } + } else { + rowData = null; + return new ArrayList<>(); } } catch (TskCoreException ex) { errorList.add( @@ -1659,274 +1871,67 @@ class ReportGenerator { * correct order to be written to the report. * * @return List row values. Values could be null if attribute is - * not defined in artifact + * not defined in artifact * * @throws TskCoreException */ private List getOrderedRowDataAsStrings() throws TskCoreException { - Map mappedAttributes = getMappedAttributes(); + List orderedRowData = new ArrayList<>(); - BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(getArtifact().getArtifactTypeID()); - switch (type) { - case TSK_WEB_BOOKMARK: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_TITLE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_WEB_COOKIE: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_VALUE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_WEB_HISTORY: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_REFERRER.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_TITLE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_WEB_DOWNLOAD: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PATH.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_RECENT_OBJECT: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PATH.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_INSTALLED_PROG: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_DEVICE_ATTACHED: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_ID.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_WEB_SEARCH_QUERY: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_TEXT.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_METADATA_EXIF: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_CONTACT: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_HOME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_OFFICE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_MOBILE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_EMAIL.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_MESSAGE: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DIRECTION.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_READ_STATUS.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_EMAIL_FROM.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_EMAIL_TO.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_SUBJECT.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_TEXT.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_CALLLOG: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DIRECTION.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_CALENDAR_ENTRY: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_CALENDAR_ENTRY_TYPE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_SPEED_DIAL_ENTRY: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_SHORTCUT.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_NAME_PERSON.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_BLUETOOTH_PAIRING: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_ID.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_GPS_TRACKPOINT: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_GPS_BOOKMARK: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_GPS_LAST_KNOWN_LOCATION: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_GPS_SEARCH: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_SERVICE_ACCOUNT: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_CATEGORY.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_USER_ID.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PASSWORD.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PATH.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_EMAIL_REPLYTO.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_SERVER_NAME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_TOOL_OUTPUT: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_TEXT.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_ENCRYPTION_DETECTED: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_EXT_MISMATCH_DETECTED: - AbstractFile file = skCase.getAbstractFileById(getObjectID()); - if (file != null) { - orderedRowData.add(file.getName()); - orderedRowData.add(file.getNameExtension()); - String mimeType = file.getMIMEType(); - if(mimeType == null) { - orderedRowData.add(""); - } - else { - orderedRowData.add(mimeType); - } - orderedRowData.add(file.getUniquePath()); + if (ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() == getArtifact().getArtifactTypeID()) { + AbstractFile file = skCase.getAbstractFileById(getObjectID()); + if (file != null) { + orderedRowData.add(file.getName()); + orderedRowData.add(file.getNameExtension()); + String mimeType = file.getMIMEType(); + if (mimeType == null) { + orderedRowData.add(""); } else { - // Make empty rows to make sure the formatting is correct - orderedRowData.add(null); - orderedRowData.add(null); - orderedRowData.add(null); - orderedRowData.add(null); + orderedRowData.add(mimeType); } - break; - case TSK_OS_INFO: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PROCESSOR_ARCHITECTURE.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - orderedRowData.add(getFileUniquePath(getObjectID())); - break; - case TSK_EMAIL_MSG: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_EMAIL_TO.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_EMAIL_FROM.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_SUBJECT.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_RCVD.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PATH.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_MSG_ID.getTypeID())); - break; - case TSK_INTERESTING_FILE_HIT: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_CATEGORY.getTypeID())); - String pathToShow = mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PATH.getTypeID()); - if (pathToShow.isEmpty()) { - pathToShow = getFileUniquePath(getObjectID()); + orderedRowData.add(file.getUniquePath()); + } else { + // Make empty rows to make sure the formatting is correct + orderedRowData.add(null); + orderedRowData.add(null); + orderedRowData.add(null); + orderedRowData.add(null); + } + orderedRowData.add(makeCommaSeparatedList(getTags())); + + } else if (ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == getArtifact().getArtifactTypeID()) { + String[] attributeDataArray = new String[3]; + // Array is used so that the order of the attributes is + // maintained. + for (BlackboardAttribute attr : attributes) { + if (attr.getAttributeType().equals(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME))) { + attributeDataArray[0] = attr.getDisplayString(); + } else if (attr.getAttributeType().equals(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CATEGORY))) { + attributeDataArray[1] = attr.getDisplayString(); + } else if (attr.getAttributeType().equals(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH))) { + String pathToShow = attr.getDisplayString(); + if (pathToShow.isEmpty()) { + pathToShow = getFileUniquePath(getObjectID()); + } + attributeDataArray[2] = pathToShow; } - orderedRowData.add(pathToShow); - break; - case TSK_GPS_ROUTE: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_CATEGORY.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - break; - case TSK_INTERESTING_ARTIFACT_HIT: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - break; - case TSK_PROG_RUN: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_COUNT.getTypeID())); - break; - case TSK_OS_ACCOUNT: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_USER_NAME.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_USER_ID.getTypeID())); - break; - case TSK_REMOTE_DRIVE: - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_LOCAL_PATH.getTypeID())); - orderedRowData.add(mappedAttributes.get(ATTRIBUTE_TYPE.TSK_REMOTE_PATH.getTypeID())); - break; + } + orderedRowData.addAll(Arrays.asList(attributeDataArray)); + orderedRowData.add(makeCommaSeparatedList(getTags())); + + } else { + if (ReportGenerator.this.columnHeaderMap.containsKey(this.artifact.getArtifactTypeID())) { + + for (Column currColumn : ReportGenerator.this.columnHeaderMap.get(this.artifact.getArtifactTypeID())) { + String cellData = currColumn.getCellData(this); + orderedRowData.add(cellData); + } + } + orderedRowData.add(makeCommaSeparatedList(getTags())); } - orderedRowData.add(makeCommaSeparatedList(getTags())); return orderedRowData; } - - /** - * Returns a mapping of Attribute Type ID to the String representation - * of an Attribute Value. - */ - private Map getMappedAttributes() { - return ReportGenerator.this.getMappedAttributes(attributes); - } } /** @@ -1955,6 +1960,133 @@ class ReportGenerator { } return uniqueTagNames; + } + private interface Column { + + String getColumnHeader(); + + String getCellData(ArtifactData artData); + + Set removeTypeFromSet(Set types); + } + + private class AttributeColumn implements Column { + + private String columnHeader; + private BlackboardAttribute.Type attributeType; + + /** + * Constructs an ArtifactCell + * + * @param columnHeader The header text of this column + * @param attributeType The attribute type associated with this column + */ + AttributeColumn(String columnHeader, BlackboardAttribute.Type attributeType) { + this.columnHeader = Objects.requireNonNull(columnHeader); + this.attributeType = attributeType; + } + + @Override + public String getColumnHeader() { + return this.columnHeader; + } + + @Override + public String getCellData(ArtifactData artData) { + List attributes = artData.getAttributes(); + for (BlackboardAttribute attribute : attributes) { + if (attribute.getAttributeType().equals(this.attributeType)) { + return attribute.getDisplayString(); + } + } + return ""; + } + + @Override + public Set removeTypeFromSet(Set types) { + types.remove(this.attributeType); + return types; + } + } + + private class SourceFileColumn implements Column { + + private String columnHeader; + + SourceFileColumn(String columnHeader) { + this.columnHeader = columnHeader; + } + + @Override + public String getColumnHeader() { + return this.columnHeader; + } + + @Override + public String getCellData(ArtifactData artData) { + return getFileUniquePath(artData.getObjectID()); + /*else if (this.columnHeader.equals(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags"))) { + return makeCommaSeparatedList(artData.getTags()); + } + return "";*/ + } + + @Override + public Set removeTypeFromSet(Set types) { + // This column doesn't have a type, so nothing to remove + return types; + } + } + + private class TaggedResultsColumn implements Column { + + private String columnHeader; + + TaggedResultsColumn(String columnHeader) { + this.columnHeader = columnHeader; + } + + @Override + public String getColumnHeader() { + return this.columnHeader; + } + + @Override + public String getCellData(ArtifactData artData) { + return makeCommaSeparatedList(artData.getTags()); + } + + @Override + public Set removeTypeFromSet(Set types) { + // This column doesn't have a type, so nothing to remove + return types; + } + } + + private class HeaderOnlyColumn implements Column { + + private String columnHeader; + + HeaderOnlyColumn(String columnHeader) { + this.columnHeader = columnHeader; + } + + @Override + public String getColumnHeader() { + return columnHeader; + } + + @Override + public String getCellData(ArtifactData artData) { + throw new UnsupportedOperationException("Cannot get cell data of unspecified column"); + } + + @Override + public Set removeTypeFromSet(Set types) { + // This column doesn't have a type, so nothing to remove + return types; + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index d7a7014022..196f770ca7 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -262,7 +262,6 @@ class ReportHTML implements TableReportModule { break; } } else { // no defined artifact found for this dataType - logger.log(Level.WARNING, "useDataTypeIcon: no artifact found for data type = " + dataType); //NON-NLS in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/star.png"); //NON-NLS iconFileName = "star.png"; //NON-NLS iconFilePath = path + File.separator + iconFileName; @@ -984,8 +983,8 @@ class ReportHTML implements TableReportModule { StringBuilder head = new StringBuilder(); head.append("\n\n").append( //NON-NLS NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.title")).append("\n"); //NON-NLS - head.append("