From f5fae2c1c63486fb877db34369a897248e74f50d Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Mon, 2 May 2016 16:20:33 -0400 Subject: [PATCH 01/39] Started moving to one report in reports code. --- .../autopsy/report/ReportGenerator.java | 412 ++++++++---------- .../autopsy/report/ReportVisualPanel1.java | 24 +- .../autopsy/report/ReportWizardAction.java | 6 +- .../autopsy/report/ReportWizardPanel1.java | 15 +- 4 files changed, 209 insertions(+), 248 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 1f49588837..c0c72447d6 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -34,7 +34,6 @@ 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; @@ -53,7 +52,6 @@ import javax.swing.SwingWorker; import org.openide.filesystems.FileUtil; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; @@ -66,13 +64,13 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; +import org.sleuthkit.datamodel.BlackboardAttribute.Type; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; 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 @@ -87,9 +85,10 @@ class ReportGenerator { private Case currentCase = Case.getCurrentCase(); private SleuthkitCase skCase = currentCase.getSleuthkitCase(); - private Map tableProgress; - private Map generalProgress; - private Map fileProgress; + private TableReportModule tableReportModule; + private GeneralReportModule generalReportModule; + private FileReportModule fileReportModule; + private ReportProgressPanel progressPanel; private Map> columnHeaderMap; private String reportPath; @@ -117,7 +116,7 @@ class ReportGenerator { } } - ReportGenerator(Map tableModuleStates, Map generalModuleStates, Map fileListModuleStates) { + ReportGenerator(TableReportModule tableModuleStates, GeneralReportModule generalModuleStates, FileReportModule fileListModuleStates) { // Create the root reports directory path of the form: /Reports/ / DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss"); Date date = new Date(); @@ -136,9 +135,6 @@ class ReportGenerator { } // Initialize the progress panels - generalProgress = new HashMap<>(); - tableProgress = new HashMap<>(); - fileProgress = new HashMap<>(); setupProgressPanels(tableModuleStates, generalModuleStates, fileListModuleStates); this.columnHeaderMap = new HashMap<>(); } @@ -147,53 +143,44 @@ class ReportGenerator { * Create a ReportProgressPanel for each report generation module selected * by the user. * - * @param tableModuleStates The enabled/disabled state of each + * @param tableModule 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 */ - private void setupProgressPanels(Map tableModuleStates, Map generalModuleStates, Map fileListModuleStates) { - if (null != tableModuleStates) { - for (Entry entry : tableModuleStates.entrySet()) { - if (entry.getValue()) { - TableReportModule module = entry.getKey(); - String reportFilePath = module.getRelativeFilePath(); - if (!reportFilePath.isEmpty()) { - tableProgress.put(module, panel.addReport(module.getName(), reportPath + reportFilePath)); - } else { - tableProgress.put(module, panel.addReport(module.getName(), null)); - } - } + private void setupProgressPanels(TableReportModule tableModule, GeneralReportModule generalModule, FileReportModule fileListModule) { + if (null != tableModule) { + String reportFilePath = tableModule.getRelativeFilePath(); + if (!reportFilePath.isEmpty()) { + this.tableReportModule = tableModule; + this.progressPanel = panel.addReport(tableModule.getName(), reportPath + reportFilePath); + } else { + this.tableReportModule = tableModule; + this.progressPanel = panel.addReport(tableModule.getName(), null); } } - if (null != generalModuleStates) { - for (Entry entry : generalModuleStates.entrySet()) { - if (entry.getValue()) { - GeneralReportModule module = entry.getKey(); - String reportFilePath = module.getRelativeFilePath(); - if (!reportFilePath.isEmpty()) { - generalProgress.put(module, panel.addReport(module.getName(), reportPath + reportFilePath)); - } else { - generalProgress.put(module, panel.addReport(module.getName(), null)); - } - } + if (null != generalModule) { + String reportFilePath = generalModule.getRelativeFilePath(); + if (!reportFilePath.isEmpty()) { + this.generalReportModule = generalModule; + this.progressPanel = panel.addReport(generalModule.getName(), reportPath + reportFilePath); + } else { + this.generalReportModule = generalModule; + this.progressPanel = panel.addReport(generalModule.getName(), null); } } - if (null != fileListModuleStates) { - for (Entry entry : fileListModuleStates.entrySet()) { - if (entry.getValue()) { - FileReportModule module = entry.getKey(); - String reportFilePath = module.getRelativeFilePath(); - if (!reportFilePath.isEmpty()) { - fileProgress.put(module, panel.addReport(module.getName(), reportPath + reportFilePath)); - } else { - fileProgress.put(module, panel.addReport(module.getName(), null)); - } - } + if (null != fileListModule) { + String reportFilePath = fileListModule.getRelativeFilePath(); + if (!reportFilePath.isEmpty()) { + fileReportModule = fileListModule; + this.progressPanel = panel.addReport(fileListModule.getName(), reportPath + reportFilePath); + } else { + fileReportModule = fileListModule; + this.progressPanel = panel.addReport(fileListModule.getName(), null); } } } @@ -249,7 +236,7 @@ class ReportGenerator { * to be included in the report */ public void generateTableReports(Map artifactTypeSelections, Map tagNameSelections) { - if (!tableProgress.isEmpty() && null != artifactTypeSelections) { + if (tableReportModule != null && null != artifactTypeSelections) { TableReportsWorker worker = new TableReportsWorker(artifactTypeSelections, tagNameSelections); worker.execute(); } @@ -262,7 +249,7 @@ class ReportGenerator { * file in the report. */ public void generateFileListReports(Map enabledInfo) { - if (!fileProgress.isEmpty() && null != enabledInfo) { + if (fileReportModule != null && null != enabledInfo) { List enabled = new ArrayList<>(); for (Entry e : enabledInfo.entrySet()) { if (e.getValue()) { @@ -271,6 +258,7 @@ class ReportGenerator { } FileReportsWorker worker = new FileReportsWorker(enabled); worker.execute(); + } } @@ -281,11 +269,8 @@ class ReportGenerator { @Override protected Integer doInBackground() throws Exception { - for (Entry entry : generalProgress.entrySet()) { - GeneralReportModule module = entry.getKey(); - if (generalProgress.get(module).getStatus() != ReportStatus.CANCELED) { - module.generateReport(reportPath, generalProgress.get(module)); - } + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + generalReportModule.generateReport(reportPath, progressPanel); } return 0; } @@ -316,68 +301,54 @@ class ReportGenerator { private class FileReportsWorker extends SwingWorker { private List enabledInfo = Arrays.asList(FileReportDataTypes.values()); - private List fileModules = new ArrayList<>(); FileReportsWorker(List enabled) { enabledInfo = enabled; - for (Entry entry : fileProgress.entrySet()) { - fileModules.add(entry.getKey()); - } } @Override protected Integer doInBackground() throws Exception { - for (FileReportModule module : fileModules) { - ReportProgressPanel progress = fileProgress.get(module); - if (progress.getStatus() != ReportStatus.CANCELED) { - progress.start(); - progress.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.queryingDb.text")); - } + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + progressPanel.start(); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.queryingDb.text")); } List files = getFiles(); int numFiles = files.size(); - for (FileReportModule module : fileModules) { - module.startReport(reportPath); - module.startTable(enabledInfo); - fileProgress.get(module).setIndeterminate(false); - fileProgress.get(module).setMaximumProgress(numFiles); + if (fileReportModule != null) { + fileReportModule.startReport(reportPath); + fileReportModule.startTable(enabledInfo); } + progressPanel.setIndeterminate(false); + progressPanel.setMaximumProgress(numFiles); int i = 0; // Add files to report. for (AbstractFile file : files) { // Check to see if any reports have been cancelled. - if (fileModules.isEmpty()) { + if (fileReportModule == null) { break; } // Remove cancelled reports, add files to report otherwise. - Iterator iter = fileModules.iterator(); - while (iter.hasNext()) { - FileReportModule module = iter.next(); - ReportProgressPanel progress = fileProgress.get(module); - if (progress.getStatus() == ReportStatus.CANCELED) { - iter.remove(); - } else { - module.addRow(file, enabledInfo); - progress.increment(); - } + if (progressPanel.getStatus() == ReportStatus.CANCELED) { + fileReportModule = null; + } else { + fileReportModule.addRow(file, enabledInfo); + progressPanel.increment(); + } - if ((i % 100) == 0) { - progress.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingFile.text", - file.getName())); - } + if ((i % 100) == 0) { + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingFile.text", + file.getName())); } i++; } - for (FileReportModule module : fileModules) { - module.endTable(); - module.endReport(); - fileProgress.get(module).complete(ReportStatus.COMPLETE); - } + fileReportModule.endTable(); + fileReportModule.endReport(); + progressPanel.complete(ReportStatus.COMPLETE); return 0; } @@ -428,17 +399,12 @@ class ReportGenerator { */ private class TableReportsWorker extends SwingWorker { - private List tableModules = new ArrayList<>(); private List artifactTypes = new ArrayList<>(); private HashSet tagNamesFilter = new HashSet<>(); private List images = new ArrayList<>(); 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()) { @@ -460,16 +426,13 @@ class ReportGenerator { @Override protected Integer doInBackground() throws Exception { // Start the progress indicators for each active TableReportModule. - for (TableReportModule module : tableModules) { - ReportProgressPanel progress = tableProgress.get(module); - if (progress.getStatus() != ReportStatus.CANCELED) { - module.startReport(reportPath); - progress.start(); - progress.setIndeterminate(false); - progress.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags - } + if (progressPanel.getStatus() == ReportStatus.CANCELED) { + } else { + tableReportModule.startReport(reportPath); + progressPanel.start(); + progressPanel.setIndeterminate(false); + progressPanel.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags } - // report on the blackboard results makeBlackboardArtifactTables(); @@ -481,10 +444,8 @@ class ReportGenerator { makeThumbnailTable(); // finish progress, wrap up - for (TableReportModule module : tableModules) { - tableProgress.get(module).complete(ReportStatus.COMPLETE); - module.endReport(); - } + progressPanel.complete(ReportStatus.COMPLETE); + tableReportModule.endReport(); return 0; } @@ -504,22 +465,20 @@ class ReportGenerator { for (BlackboardArtifact.Type type : artifactTypes) { // Check for cancellaton. removeCancelledTableReportModules(); - if (tableModules.isEmpty()) { + if (tableReportModule == null) { return; } - for (TableReportModule module : tableModules) { - tableProgress.get(module).updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - type.getDisplayName())); - } + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + type.getDisplayName())); // Keyword hits and hashset hit artifacts get special handling. if (type.getTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - writeKeywordHits(tableModules, comment.toString(), tagNamesFilter); + writeKeywordHits(tableReportModule, comment.toString(), tagNamesFilter); continue; } else if (type.getTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { - writeHashsetHits(tableModules, comment.toString(), tagNamesFilter); + writeHashsetHits(tableReportModule, comment.toString(), tagNamesFilter); continue; } @@ -558,30 +517,22 @@ class ReportGenerator { columnHeaderNames.add(currColumn.getColumnHeader()); } - for (TableReportModule module : tableModules) { - module.startDataType(type.getDisplayName(), comment.toString()); - module.startTable(columnHeaderNames); - } + tableReportModule.startDataType(type.getDisplayName(), comment.toString()); + tableReportModule.startTable(columnHeaderNames); for (ArtifactData artifactData : artifactList) { - // Add the row data to all of the reports. - for (TableReportModule module : tableModules) { - - // Get the row data for this artifact, and has the - // module add it. - List rowData = artifactData.getRow(); - if (rowData.isEmpty()) { - continue; - } - - module.addRow(rowData); + // Get the row data for this artifact, and has the + // module add it. + List rowData = artifactData.getRow(); + if (rowData.isEmpty()) { + continue; } + + tableReportModule.addRow(rowData); } // Finish up this data type - for (TableReportModule module : tableModules) { - tableProgress.get(module).increment(); - module.endTable(); - module.endDataType(); - } + progressPanel.increment(); + tableReportModule.endTable(); + tableReportModule.endDataType(); } } @@ -592,7 +543,7 @@ class ReportGenerator { private void makeContentTagsTables() { // Check for cancellaton. removeCancelledTableReportModules(); - if (tableModules.isEmpty()) { + if (tableReportModule == null) { return; } @@ -607,37 +558,35 @@ class ReportGenerator { } // Tell the modules reporting on content tags is beginning. - for (TableReportModule module : tableModules) { - // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. - // @@@ Alos Using the obsolete ARTIFACT_TYPE.TSK_TAG_FILE is also an expedient hack. - tableProgress.get(module).updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName())); - ArrayList columnHeaders = new ArrayList<>(Arrays.asList( - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.tag"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.file"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.comment"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeModified"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeChanged"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeAccessed"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeCreated"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.size"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.hash"))); + // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. + // @@@ Alos Using the obsolete ARTIFACT_TYPE.TSK_TAG_FILE is also an expedient hack. + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName())); + ArrayList columnHeaders = new ArrayList<>(Arrays.asList( + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.tag"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.file"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.comment"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeModified"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeChanged"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeAccessed"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeCreated"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.size"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.hash"))); - StringBuilder comment = new StringBuilder(); - if (!tagNamesFilter.isEmpty()) { - comment.append( - NbBundle.getMessage(this.getClass(), "ReportGenerator.makeContTagTab.taggedFiles.msg")); - comment.append(makeCommaSeparatedList(tagNamesFilter)); - } - if (module instanceof ReportHTML) { - ReportHTML htmlReportModule = (ReportHTML) module; - htmlReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); - htmlReportModule.startContentTagsTable(columnHeaders); - } else { - module.startDataType(ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); - module.startTable(columnHeaders); - } + StringBuilder comment = new StringBuilder(); + if (!tagNamesFilter.isEmpty()) { + comment.append( + NbBundle.getMessage(this.getClass(), "ReportGenerator.makeContTagTab.taggedFiles.msg")); + comment.append(makeCommaSeparatedList(tagNamesFilter)); + } + if (tableReportModule instanceof ReportHTML) { + ReportHTML htmlReportModule = (ReportHTML) tableReportModule; + htmlReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); + htmlReportModule.startContentTagsTable(columnHeaders); + } else { + tableReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); + tableReportModule.startTable(columnHeaders); } // Give the modules the rows for the content tags. @@ -667,14 +616,12 @@ class ReportGenerator { rowData.add(Long.toString(file.getSize())); rowData.add(file.getMd5Hash()); } - for (TableReportModule module : tableModules) { - // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. - if (module instanceof ReportHTML) { - ReportHTML htmlReportModule = (ReportHTML) module; - htmlReportModule.addRowWithTaggedContentHyperlink(rowData, tag); - } else { - module.addRow(rowData); - } + // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. + if (tableReportModule instanceof ReportHTML) { + ReportHTML htmlReportModule = (ReportHTML) tableReportModule; + htmlReportModule.addRowWithTaggedContentHyperlink(rowData, tag); + } else { + tableReportModule.addRow(rowData); } // see if it is for an image so that we later report on it @@ -682,11 +629,9 @@ class ReportGenerator { } // The the modules content tags reporting is ended. - for (TableReportModule module : tableModules) { - tableProgress.get(module).increment(); - module.endTable(); - module.endDataType(); - } + progressPanel.increment(); + tableReportModule.endTable(); + tableReportModule.endDataType(); } @Override @@ -715,7 +660,7 @@ class ReportGenerator { private void makeBlackboardArtifactTagsTables() { // Check for cancellaton. removeCancelledTableReportModules(); - if (tableModules.isEmpty()) { + if (tableReportModule == null) { return; } @@ -730,8 +675,7 @@ class ReportGenerator { // Tell the modules reporting on blackboard artifact tags data type is beginning. // @@@ Using the obsolete ARTIFACT_TYPE.TSK_TAG_ARTIFACT is an expedient hack. - for (TableReportModule module : tableModules) { - tableProgress.get(module).updateStatusLabel( + progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName())); StringBuilder comment = new StringBuilder(); @@ -746,7 +690,7 @@ class ReportGenerator { NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.tag"), NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.comment"), NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.srcFile")))); - } + // Give the modules the rows for the content tags. for (BlackboardArtifactTag tag : tags) { @@ -784,14 +728,9 @@ class ReportGenerator { } void removeCancelledTableReportModules() { - Iterator iter = tableModules.iterator(); - while (iter.hasNext()) { - TableReportModule module = iter.next(); - if (tableProgress.get(module).getStatus() == ReportStatus.CANCELED) { - iter.remove(); + if (progressPanel.getStatus() == ReportStatus.CANCELED) { + tableReportModule = null; } - } - } /** * Make a report for the files that were previously found to be images. @@ -876,7 +815,7 @@ class ReportGenerator { } } - /// @@@ Should move the methods specific to TableReportsWorker into that scope. +/// @@@ Should move the methods specific to TableReportsWorker into that scope. private Boolean failsTagFilter(HashSet tagNames, HashSet tagsNamesFilter) { if (null == tagsNamesFilter || tagsNamesFilter.isEmpty()) { return false; @@ -942,11 +881,16 @@ class ReportGenerator { orderByClause = "ORDER BY list ASC"; //NON-NLS } String keywordListQuery - = "SELECT att.value_text AS list " + //NON-NLS - "FROM blackboard_attributes AS att, blackboard_artifacts AS art " + //NON-NLS - "WHERE att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " + //NON-NLS - "AND art.artifact_type_id = " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + " " + //NON-NLS - "AND att.artifact_id = art.artifact_id " + //NON-NLS + = "SELECT att.value_text AS list " + + //NON-NLS + "FROM blackboard_attributes AS att, blackboard_artifacts AS art " + + //NON-NLS + "WHERE att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " + + //NON-NLS + "AND art.artifact_type_id = " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + " " + + //NON-NLS + "AND att.artifact_id = art.artifact_id " + + //NON-NLS "GROUP BY list " + orderByClause; //NON-NLS try (CaseDbQuery dbQuery = skCase.executeQuery(keywordListQuery)) { @@ -985,16 +929,26 @@ class ReportGenerator { } // Query for keywords, grouped by list String keywordsQuery - = "SELECT art.artifact_id, art.obj_id, att1.value_text AS keyword, att2.value_text AS preview, att3.value_text AS list, f.name AS name, f.parent_path AS parent_path " + //NON-NLS - "FROM blackboard_artifacts AS art, blackboard_attributes AS att1, blackboard_attributes AS att2, blackboard_attributes AS att3, tsk_files AS f " + //NON-NLS - "WHERE (att1.artifact_id = art.artifact_id) " + //NON-NLS - "AND (att2.artifact_id = art.artifact_id) " + //NON-NLS - "AND (att3.artifact_id = art.artifact_id) " + //NON-NLS - "AND (f.obj_id = art.obj_id) " + //NON-NLS - "AND (att1.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID() + ") " + //NON-NLS - "AND (att2.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW.getTypeID() + ") " + //NON-NLS - "AND (att3.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " + //NON-NLS - "AND (art.artifact_type_id = " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ") " + //NON-NLS + = "SELECT art.artifact_id, art.obj_id, att1.value_text AS keyword, att2.value_text AS preview, att3.value_text AS list, f.name AS name, f.parent_path AS parent_path " + + //NON-NLS + "FROM blackboard_artifacts AS art, blackboard_attributes AS att1, blackboard_attributes AS att2, blackboard_attributes AS att3, tsk_files AS f " + + //NON-NLS + "WHERE (att1.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (att2.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (att3.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (f.obj_id = art.obj_id) " + + //NON-NLS + "AND (att1.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID() + ") " + + //NON-NLS + "AND (att2.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW.getTypeID() + ") " + + //NON-NLS + "AND (att3.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " + + //NON-NLS + "AND (art.artifact_type_id = " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ") " + + //NON-NLS orderByClause; //NON-NLS try (CaseDbQuery dbQuery = skCase.executeQuery(keywordsQuery)) { @@ -1106,11 +1060,16 @@ class ReportGenerator { orderByClause = "ORDER BY att.value_text ASC"; //NON-NLS } String hashsetsQuery - = "SELECT att.value_text AS list " + //NON-NLS - "FROM blackboard_attributes AS att, blackboard_artifacts AS art " + //NON-NLS - "WHERE att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " + //NON-NLS - "AND art.artifact_type_id = " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + " " + //NON-NLS - "AND att.artifact_id = art.artifact_id " + //NON-NLS + = "SELECT att.value_text AS list " + + //NON-NLS + "FROM blackboard_attributes AS att, blackboard_artifacts AS art " + + //NON-NLS + "WHERE att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " + + //NON-NLS + "AND art.artifact_type_id = " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + " " + + //NON-NLS + "AND att.artifact_id = art.artifact_id " + + //NON-NLS "GROUP BY list " + orderByClause; //NON-NLS try (CaseDbQuery dbQuery = skCase.executeQuery(hashsetsQuery)) { @@ -1143,12 +1102,18 @@ class ReportGenerator { orderByClause = "ORDER BY att.value_text ASC, f.parent_path ASC, f.name ASC, size ASC"; //NON-NLS } String hashsetHitsQuery - = "SELECT art.artifact_id, art.obj_id, att.value_text AS setname, f.name AS name, f.size AS size, f.parent_path AS parent_path " + //NON-NLS - "FROM blackboard_artifacts AS art, blackboard_attributes AS att, tsk_files AS f " + //NON-NLS - "WHERE (att.artifact_id = art.artifact_id) " + //NON-NLS - "AND (f.obj_id = art.obj_id) " + //NON-NLS - "AND (att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " + //NON-NLS - "AND (art.artifact_type_id = " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ") " + //NON-NLS + = "SELECT art.artifact_id, art.obj_id, att.value_text AS setname, f.name AS name, f.size AS size, f.parent_path AS parent_path " + + //NON-NLS + "FROM blackboard_artifacts AS art, blackboard_attributes AS att, tsk_files AS f " + + //NON-NLS + "WHERE (att.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (f.obj_id = art.obj_id) " + + //NON-NLS + "AND (att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " + + //NON-NLS + "AND (art.artifact_type_id = " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ") " + + //NON-NLS orderByClause; //NON-NLS try (CaseDbQuery dbQuery = skCase.executeQuery(hashsetHitsQuery)) { @@ -1948,13 +1913,11 @@ class ReportGenerator { orderedRowData.addAll(Arrays.asList(attributeDataArray)); orderedRowData.add(makeCommaSeparatedList(getTags())); - } else { - if (ReportGenerator.this.columnHeaderMap.containsKey(this.artifact.getArtifactTypeID())) { + } 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); - } + for (Column currColumn : ReportGenerator.this.columnHeaderMap.get(this.artifact.getArtifactTypeID())) { + String cellData = currColumn.getCellData(this); + orderedRowData.add(cellData); } } @@ -1976,7 +1939,8 @@ class ReportGenerator { private HashSet getUniqueTagNames(long artifactId) throws TskCoreException { HashSet uniqueTagNames = new HashSet<>(); - String query = "SELECT display_name, artifact_id FROM tag_names AS tn, blackboard_artifact_tags AS bat " + //NON-NLS + String query = "SELECT display_name, artifact_id FROM tag_names AS tn, blackboard_artifact_tags AS bat " + + //NON-NLS "WHERE tn.tag_name_id = bat.tag_name_id AND bat.artifact_id = " + artifactId; //NON-NLS try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java index 7c2bc5193c..502c3162a3 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java @@ -137,8 +137,8 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener { // Make sure that the report module has a valid non-null name. private boolean moduleIsValid(ReportModule module) { - return module.getName() != null && !module.getName().isEmpty() - && module.getRelativeFilePath() != null; + return module.getName() != null && !module.getName().isEmpty() + && module.getRelativeFilePath() != null; } private void popupWarning(ReportModule module) { @@ -163,13 +163,13 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener { * * @return */ - Map getTableModuleStates() { + TableReportModule getTableModule() { Map reportModuleStates = new LinkedHashMap<>(); ReportModule mod = getSelectedModule(); if (tableModules.contains(mod)) { - reportModuleStates.put((TableReportModule) mod, Boolean.TRUE); + return (TableReportModule) mod; } - return reportModuleStates; + return null; } /** @@ -177,13 +177,12 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener { * * @return */ - Map getGeneralModuleStates() { - Map reportModuleStates = new LinkedHashMap<>(); + GeneralReportModule getGeneralModule() { ReportModule mod = getSelectedModule(); if (generalModules.contains(mod)) { - reportModuleStates.put((GeneralReportModule) mod, Boolean.TRUE); + return (GeneralReportModule) mod; } - return reportModuleStates; + return null; } /** @@ -191,13 +190,12 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener { * * @return */ - Map getFileModuleStates() { - Map reportModuleStates = new LinkedHashMap<>(); + FileReportModule getFileModule() { ReportModule mod = getSelectedModule(); if (fileModules.contains(mod)) { - reportModuleStates.put((FileReportModule) mod, Boolean.TRUE); + return (FileReportModule) mod; } - return reportModuleStates; + return null; } /** diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java index bf51dfee86..0e350e12d1 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java @@ -65,9 +65,9 @@ public final class ReportWizardAction extends CallableSystemAction implements Pr wiz.setTitle(NbBundle.getMessage(ReportWizardAction.class, "ReportWizardAction.reportWiz.title")); if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) { @SuppressWarnings("unchecked") - ReportGenerator generator = new ReportGenerator((Map) wiz.getProperty("tableModuleStates"), //NON-NLS - (Map) wiz.getProperty("generalModuleStates"), //NON-NLS - (Map) wiz.getProperty("fileModuleStates")); //NON-NLS + ReportGenerator generator = new ReportGenerator((TableReportModule) wiz.getProperty("tableModule"), //NON-NLS + (GeneralReportModule) wiz.getProperty("generalModule"), //NON-NLS + (FileReportModule) wiz.getProperty("fileModule")); //NON-NLS generator.generateTableReports((Map) wiz.getProperty("artifactStates"), (Map) wiz.getProperty("tagStates")); //NON-NLS generator.generateFileListReports((Map) wiz.getProperty("fileReportOptions")); //NON-NLS generator.generateGeneralReports(); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java index 9231a9685a..9677f7d6f5 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.report; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collection; -import java.util.Map; import java.util.prefs.Preferences; import javax.swing.JButton; import javax.swing.event.ChangeListener; @@ -108,17 +107,17 @@ class ReportWizardPanel1 implements WizardDescriptor.FinishablePanel tables = getComponent().getTableModuleStates(); - Map generals = getComponent().getGeneralModuleStates(); - wiz.putProperty("tableModuleStates", tables); //NON-NLS - wiz.putProperty("generalModuleStates", generals); //NON-NLS - wiz.putProperty("fileModuleStates", getComponent().getFileModuleStates()); //NON-NLS + TableReportModule module = getComponent().getTableModule(); + GeneralReportModule general = getComponent().getGeneralModule(); + wiz.putProperty("tableModule", module); //NON-NLS + wiz.putProperty("generalModule", general); //NON-NLS + wiz.putProperty("fileModule", getComponent().getFileModule()); //NON-NLS // Store preferences that WizardIterator will use to determine what // panels need to be shown Preferences prefs = NbPreferences.forModule(ReportWizardPanel1.class); - prefs.putBoolean("tableModule", any(tables.values())); //NON-NLS - prefs.putBoolean("generalModule", any(generals.values())); //NON-NLS + prefs.putBoolean("tableModuleState", module != null); //NON-NLS + prefs.putBoolean("generalModule", general != null); //NON-NLS } /** From c29f106d3eee2312bf8f7e8d85fff78c9e75e504 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 3 May 2016 10:21:28 -0400 Subject: [PATCH 02/39] Working towards a working cancellation policy. --- .../modules/stix/STIXReportModule.java | 48 ++-- .../autopsy/report/ReportGenerator.java | 219 +++++++----------- .../sleuthkit/autopsy/report/ReportKML.java | 25 +- .../autopsy/report/ReportVisualPanel1.java | 3 - 4 files changed, 129 insertions(+), 166 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java index 2762f21e26..ab42938cca 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java @@ -18,48 +18,45 @@ */ package org.sleuthkit.autopsy.modules.stix; -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.List; -import java.util.logging.Level; import java.io.BufferedWriter; +import java.io.File; import java.io.FileWriter; +import java.io.IOException; import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; import javax.swing.JPanel; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import javax.xml.namespace.QName; - import org.mitre.cybox.cybox_2.ObjectType; import org.mitre.cybox.cybox_2.Observable; import org.mitre.cybox.cybox_2.ObservableCompositionType; +import org.mitre.cybox.cybox_2.OperatorTypeEnum; +import org.mitre.cybox.objects.AccountObjectType; +import org.mitre.cybox.objects.Address; +import org.mitre.cybox.objects.DomainName; +import org.mitre.cybox.objects.EmailMessage; +import org.mitre.cybox.objects.FileObjectType; +import org.mitre.cybox.objects.SystemObjectType; +import org.mitre.cybox.objects.URIObjectType; +import org.mitre.cybox.objects.URLHistory; +import org.mitre.cybox.objects.WindowsNetworkShare; +import org.mitre.cybox.objects.WindowsRegistryKey; import org.mitre.stix.common_1.IndicatorBaseType; import org.mitre.stix.indicator_2.Indicator; import org.mitre.stix.stix_1.STIXPackage; - -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.report.GeneralReportModule; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.report.ReportProgressPanel; -import org.sleuthkit.datamodel.TskCoreException; - -import org.mitre.cybox.cybox_2.OperatorTypeEnum; -import org.mitre.cybox.objects.Address; -import org.mitre.cybox.objects.FileObjectType; -import org.mitre.cybox.objects.URIObjectType; -import org.mitre.cybox.objects.EmailMessage; -import org.mitre.cybox.objects.WindowsNetworkShare; -import org.mitre.cybox.objects.AccountObjectType; -import org.mitre.cybox.objects.SystemObjectType; -import org.mitre.cybox.objects.URLHistory; -import org.mitre.cybox.objects.DomainName; -import org.mitre.cybox.objects.WindowsRegistryKey; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.report.GeneralReportModule; +import org.sleuthkit.autopsy.report.ReportProgressPanel; import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus; +import org.sleuthkit.datamodel.TskCoreException; /** * @@ -180,6 +177,9 @@ public class STIXReportModule implements GeneralReportModule { // Process each STIX file for (File file : stixFiles) { + if (progressPanel.getStatus() == ReportStatus.CANCELED) { + return; + } try { processFile(file.getAbsolutePath(), progressPanel); } catch (TskCoreException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index c0c72447d6..7e4896b531 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -223,8 +223,10 @@ class ReportGenerator { * Run the GeneralReportModules using a SwingWorker. */ public void generateGeneralReports() { - GeneralReportsWorker worker = new GeneralReportsWorker(); - worker.execute(); + if (this.generalReportModule != null) { + GeneralReportsWorker worker = new GeneralReportsWorker(); + worker.execute(); + } } /** @@ -675,22 +677,21 @@ class ReportGenerator { // Tell the modules reporting on blackboard artifact tags data type is beginning. // @@@ Using the obsolete ARTIFACT_TYPE.TSK_TAG_ARTIFACT is an expedient hack. - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName())); - StringBuilder comment = new StringBuilder(); - if (!tagNamesFilter.isEmpty()) { - comment.append( - NbBundle.getMessage(this.getClass(), "ReportGenerator.makeBbArtTagTab.taggedRes.msg")); - comment.append(makeCommaSeparatedList(tagNamesFilter)); - } - module.startDataType(ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName(), comment.toString()); - module.startTable(new ArrayList<>(Arrays.asList( - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.resultType"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.tag"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.comment"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.srcFile")))); - + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName())); + StringBuilder comment = new StringBuilder(); + if (!tagNamesFilter.isEmpty()) { + comment.append( + NbBundle.getMessage(this.getClass(), "ReportGenerator.makeBbArtTagTab.taggedRes.msg")); + comment.append(makeCommaSeparatedList(tagNamesFilter)); + } + tableReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName(), comment.toString()); + tableReportModule.startTable(new ArrayList<>(Arrays.asList( + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.resultType"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.tag"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.comment"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.srcFile")))); // Give the modules the rows for the content tags. for (BlackboardArtifactTag tag : tags) { @@ -699,21 +700,17 @@ class ReportGenerator { } List row; - for (TableReportModule module : tableModules) { - row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName(), tag.getComment(), tag.getContent().getName())); - module.addRow(row); - } + row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName(), tag.getComment(), tag.getContent().getName())); + tableReportModule.addRow(row); // check if the tag is an image that we should later make a thumbnail for checkIfTagHasImage(tag); } // The the modules blackboard artifact tags reporting is ended. - for (TableReportModule module : tableModules) { - tableProgress.get(module).increment(); - module.endTable(); - module.endDataType(); - } + progressPanel.increment(); + tableReportModule.endTable(); + tableReportModule.endDataType(); } /** @@ -728,35 +725,35 @@ class ReportGenerator { } void removeCancelledTableReportModules() { - if (progressPanel.getStatus() == ReportStatus.CANCELED) { - tableReportModule = null; - } + if (progressPanel.getStatus() == ReportStatus.CANCELED) { + tableReportModule = null; + } + } /** * Make a report for the files that were previously found to be images. */ private void makeThumbnailTable() { - for (TableReportModule module : tableModules) { - tableProgress.get(module).updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.createdThumb.text")); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.createdThumb.text")); - if (module instanceof ReportHTML) { - ReportHTML htmlModule = (ReportHTML) module; - htmlModule.startDataType( - NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.name"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.desc")); - List emptyHeaders = new ArrayList<>(); - for (int i = 0; i < ReportHTML.THUMBNAIL_COLUMNS; i++) { - emptyHeaders.add(""); - } - htmlModule.startTable(emptyHeaders); - - htmlModule.addThumbnailRows(images); - - htmlModule.endTable(); - htmlModule.endDataType(); + if (tableReportModule instanceof ReportHTML) { + ReportHTML htmlModule = (ReportHTML) tableReportModule; + htmlModule.startDataType( + NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.name"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.desc")); + List emptyHeaders = new ArrayList<>(); + for (int i = 0; i < ReportHTML.THUMBNAIL_COLUMNS; i++) { + emptyHeaders.add(""); } + htmlModule.startTable(emptyHeaders); + + htmlModule.addThumbnailRows(images); + + htmlModule.endTable(); + htmlModule.endDataType(); } + } /** @@ -867,7 +864,7 @@ class ReportGenerator { * @param tableModules modules to report on */ @SuppressWarnings("deprecation") - private void writeKeywordHits(List tableModules, String comment, HashSet tagNamesFilter) { + private void writeKeywordHits(TableReportModule tableModule, String comment, HashSet tagNamesFilter) { // Query for keyword lists-only so that we can tell modules what lists // will exist for their index. @@ -905,13 +902,11 @@ class ReportGenerator { } // Make keyword data type and give them set index - for (TableReportModule module : tableModules) { - module.startDataType(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), comment); - module.addSetIndex(lists); - tableProgress.get(module).updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName())); - } + tableModule.startDataType(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), comment); + tableModule.addSetIndex(lists); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName())); } catch (TskCoreException | SQLException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryKWLists")); logger.log(Level.SEVERE, "Failed to query keyword lists: ", ex); //NON-NLS @@ -958,16 +953,9 @@ class ReportGenerator { String currentList = ""; while (resultSet.next()) { // Check to see if all the TableReportModules have been canceled - if (tableModules.isEmpty()) { + if (progressPanel.getStatus() == ReportStatus.CANCELED) { break; } - Iterator iter = tableModules.iterator(); - while (iter.hasNext()) { - TableReportModule module = iter.next(); - if (tableProgress.get(module).getStatus() == ReportStatus.CANCELED) { - iter.remove(); - } - } // Get any tags that associated with this artifact and apply the tag filter. HashSet uniqueTagNames = getUniqueTagNames(resultSet.getLong("artifact_id")); //NON-NLS @@ -997,49 +985,37 @@ class ReportGenerator { if ((!list.equals(currentList) && !list.isEmpty()) || (list.isEmpty() && !currentList.equals( NbBundle.getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs")))) { if (!currentList.isEmpty()) { - for (TableReportModule module : tableModules) { - module.endTable(); - module.endSet(); - } + tableModule.endTable(); + tableModule.endSet(); } currentList = list.isEmpty() ? NbBundle .getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs") : list; currentKeyword = ""; // reset the current keyword because it's a new list - for (TableReportModule module : tableModules) { - module.startSet(currentList); - tableProgress.get(module).updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", - ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), currentList)); - } + tableModule.startSet(currentList); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), currentList)); } if (!keyword.equals(currentKeyword)) { if (!currentKeyword.equals("")) { - for (TableReportModule module : tableModules) { - module.endTable(); - } + tableModule.endTable(); } currentKeyword = keyword; - for (TableReportModule module : tableModules) { - module.addSetElement(currentKeyword); - List columnHeaderNames = new ArrayList<>(); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); - module.startTable(columnHeaderNames); - } + tableModule.addSetElement(currentKeyword); + List columnHeaderNames = new ArrayList<>(); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); + tableModule.startTable(columnHeaderNames); } String previewreplace = EscapeUtil.escapeHtml(preview); - for (TableReportModule module : tableModules) { - module.addRow(Arrays.asList(new String[]{previewreplace.replaceAll(" tableModules, String comment, HashSet tagNamesFilter) { + private void writeHashsetHits(TableReportModule tableModule, String comment, HashSet tagNamesFilter) { String orderByClause; if (currentCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS @@ -1080,13 +1056,11 @@ class ReportGenerator { lists.add(listsRs.getString("list")); //NON-NLS } - for (TableReportModule module : tableModules) { - module.startDataType(ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), comment); - module.addSetIndex(lists); - tableProgress.get(module).updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName())); - } + tableModule.startDataType(ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), comment); + tableModule.addSetIndex(lists); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName())); } catch (TskCoreException | SQLException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryHashsetLists")); logger.log(Level.SEVERE, "Failed to query hashset lists: ", ex); //NON-NLS @@ -1122,16 +1096,9 @@ class ReportGenerator { String currentSet = ""; while (resultSet.next()) { // Check to see if all the TableReportModules have been canceled - if (tableModules.isEmpty()) { + if (progressPanel.getStatus() == ReportStatus.CANCELED) { break; } - Iterator iter = tableModules.iterator(); - while (iter.hasNext()) { - TableReportModule module = iter.next(); - if (tableProgress.get(module).getStatus() == ReportStatus.CANCELED) { - iter.remove(); - } - } // Get any tags that associated with this artifact and apply the tag filter. HashSet uniqueTagNames = getUniqueTagNames(resultSet.getLong("artifact_id")); //NON-NLS @@ -1160,36 +1127,28 @@ class ReportGenerator { // If the sets aren't the same, we've started a new set if (!set.equals(currentSet)) { if (!currentSet.isEmpty()) { - for (TableReportModule module : tableModules) { - module.endTable(); - module.endSet(); - } + tableModule.endTable(); + tableModule.endSet(); } currentSet = set; - for (TableReportModule module : tableModules) { - module.startSet(currentSet); - List columnHeaderNames = new ArrayList<>(); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); - module.startTable(columnHeaderNames); - tableProgress.get(module).updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", - ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), currentSet)); - } + tableModule.startSet(currentSet); + List columnHeaderNames = new ArrayList<>(); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); + tableModule.startTable(columnHeaderNames); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", + ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), currentSet)); } // Add a row for this hit to every module - for (TableReportModule module : tableModules) { - module.addRow(Arrays.asList(new String[]{uniquePath, size, tagsList})); - } + tableModule.addRow(Arrays.asList(new String[]{uniquePath, size, tagsList})); } // Finish the current data type - for (TableReportModule module : tableModules) { - tableProgress.get(module).increment(); - module.endDataType(); - } + progressPanel.increment(); + tableModule.endDataType(); } catch (TskCoreException | SQLException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryHashsetHits")); logger.log(Level.SEVERE, "Failed to query hashsets hits: ", ex); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java index abdd7dee96..d8bb02508a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java @@ -19,14 +19,6 @@ */ package org.sleuthkit.autopsy.report; -import javax.swing.JPanel; - -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.datamodel.*; -import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.datamodel.BlackboardArtifact; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; @@ -37,12 +29,18 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.logging.Level; +import javax.swing.JPanel; +import org.apache.commons.lang.StringEscapeUtils; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.Namespace; import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter; -import org.apache.commons.lang.StringEscapeUtils; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.datamodel.*; /** * Generates a KML file based on geo coordinates store in blackboard. @@ -85,6 +83,9 @@ class ReportKML implements GeneralReportModule { currentCase = Case.getCurrentCase(); skCase = currentCase.getSleuthkitCase(); + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + return; + } progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.loading")); // Check if ingest has finished String ingestwarning = ""; @@ -98,6 +99,9 @@ class ReportKML implements GeneralReportModule { // Why not just print the coordinates as we find them and make some utility methods to do the printing? // Should pull out time values for all of these points and store in TimeSpan element try { + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + return; + } try (BufferedWriter out = new BufferedWriter(new FileWriter(reportPath2))) { double lat = 0; // temp latitude @@ -108,6 +112,9 @@ class ReportKML implements GeneralReportModule { File f; for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)) { + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + return; + } lat = 0; lon = 0; geoPath = ""; diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java index 502c3162a3..93acae830a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java @@ -24,9 +24,7 @@ import java.util.ArrayList; import java.util.Collections; import static java.util.Collections.swap; import java.util.Comparator; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.logging.Level; import javax.swing.JList; import javax.swing.JPanel; @@ -164,7 +162,6 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener { * @return */ TableReportModule getTableModule() { - Map reportModuleStates = new LinkedHashMap<>(); ReportModule mod = getSelectedModule(); if (tableModules.contains(mod)) { return (TableReportModule) mod; From 25f954c4d361f00bfaf13ed1f1fae9a67380d71e Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 3 May 2016 12:01:17 -0400 Subject: [PATCH 03/39] Updated cancellation policy. --- .../autopsy/report/ReportGenerator.java | 58 +++++++------------ .../sleuthkit/autopsy/report/ReportKML.java | 7 --- 2 files changed, 22 insertions(+), 43 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 7e4896b531..6228a5b96d 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -318,7 +318,7 @@ class ReportGenerator { List files = getFiles(); int numFiles = files.size(); - if (fileReportModule != null) { + if (progressPanel.getStatus() != ReportStatus.CANCELED) { fileReportModule.startReport(reportPath); fileReportModule.startTable(enabledInfo); } @@ -329,12 +329,8 @@ class ReportGenerator { // Add files to report. for (AbstractFile file : files) { // Check to see if any reports have been cancelled. - if (fileReportModule == null) { - break; - } - // Remove cancelled reports, add files to report otherwise. if (progressPanel.getStatus() == ReportStatus.CANCELED) { - fileReportModule = null; + return 0; } else { fileReportModule.addRow(file, enabledInfo); progressPanel.increment(); @@ -428,22 +424,28 @@ class ReportGenerator { @Override protected Integer doInBackground() throws Exception { // Start the progress indicators for each active TableReportModule. - if (progressPanel.getStatus() == ReportStatus.CANCELED) { - } else { - tableReportModule.startReport(reportPath); - progressPanel.start(); - progressPanel.setIndeterminate(false); - progressPanel.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags - } + tableReportModule.startReport(reportPath); + progressPanel.start(); + progressPanel.setIndeterminate(false); + progressPanel.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags // report on the blackboard results - makeBlackboardArtifactTables(); + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + makeBlackboardArtifactTables(); + } // report on the tagged files and artifacts - makeContentTagsTables(); - makeBlackboardArtifactTagsTables(); + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + makeContentTagsTables(); + } - // report on the tagged images - makeThumbnailTable(); + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + makeBlackboardArtifactTagsTables(); + } + + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + // report on the tagged images + makeThumbnailTable(); + } // finish progress, wrap up progressPanel.complete(ReportStatus.COMPLETE); @@ -466,8 +468,8 @@ class ReportGenerator { // Add a table to the report for every enabled blackboard artifact type. for (BlackboardArtifact.Type type : artifactTypes) { // Check for cancellaton. - removeCancelledTableReportModules(); - if (tableReportModule == null) { + + if (progressPanel.getStatus() == ReportStatus.CANCELED) { return; } @@ -543,11 +545,6 @@ class ReportGenerator { */ @SuppressWarnings("deprecation") private void makeContentTagsTables() { - // Check for cancellaton. - removeCancelledTableReportModules(); - if (tableReportModule == null) { - return; - } // Get the content tags. List tags; @@ -660,11 +657,6 @@ class ReportGenerator { */ @SuppressWarnings("deprecation") private void makeBlackboardArtifactTagsTables() { - // Check for cancellaton. - removeCancelledTableReportModules(); - if (tableReportModule == null) { - return; - } List tags; try { @@ -724,12 +716,6 @@ class ReportGenerator { return tagNamesFilter.isEmpty() || tagNamesFilter.contains(tagName); } - void removeCancelledTableReportModules() { - if (progressPanel.getStatus() == ReportStatus.CANCELED) { - tableReportModule = null; - } - } - /** * Make a report for the files that were previously found to be images. */ diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java index d8bb02508a..f1542566fe 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java @@ -82,10 +82,6 @@ class ReportKML implements GeneralReportModule { String reportPath2 = baseReportDir + "ReportKML.txt"; //NON-NLS currentCase = Case.getCurrentCase(); skCase = currentCase.getSleuthkitCase(); - - if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { - return; - } progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.loading")); // Check if ingest has finished String ingestwarning = ""; @@ -99,9 +95,6 @@ class ReportKML implements GeneralReportModule { // Why not just print the coordinates as we find them and make some utility methods to do the printing? // Should pull out time values for all of these points and store in TimeSpan element try { - if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { - return; - } try (BufferedWriter out = new BufferedWriter(new FileWriter(reportPath2))) { double lat = 0; // temp latitude From 0e4717f1904cc24a1da62fb8fd3f1ced8cfcf849 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 3 May 2016 13:42:10 -0400 Subject: [PATCH 04/39] Added documentation. --- .../autopsy/report/ReportGenerator.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 6228a5b96d..4175831392 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -85,9 +85,16 @@ class ReportGenerator { private Case currentCase = Case.getCurrentCase(); private SleuthkitCase skCase = currentCase.getSleuthkitCase(); + /** + * Only one of the ReportModules below should be non-null for a given report + * generator. + */ private TableReportModule tableReportModule; private GeneralReportModule generalReportModule; private FileReportModule fileReportModule; + /** + * Progress panel that can be used to check for cancellation. + */ private ReportProgressPanel progressPanel; private Map> columnHeaderMap; @@ -101,8 +108,6 @@ class ReportGenerator { /** * Displays the list of errors during report generation in user-friendly * way. MessageNotifyUtil used to display bubble notification. - * - * @param listOfErrors List of strings explaining the errors. */ private void displayReportErrors() { if (!errorList.isEmpty()) { @@ -143,14 +148,14 @@ class ReportGenerator { * Create a ReportProgressPanel for each report generation module selected * by the user. * - * @param tableModule 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 + * @param tableModule The TableReportModule + * @param generalModule The GeneralReportModule + * @param fileListModule The FileReportModule */ private void setupProgressPanels(TableReportModule tableModule, GeneralReportModule generalModule, FileReportModule fileListModule) { + /* + * Sets ups the progress panels based upon which one is null. + */ if (null != tableModule) { String reportFilePath = tableModule.getRelativeFilePath(); if (!reportFilePath.isEmpty()) { @@ -847,7 +852,7 @@ class ReportGenerator { /** * Write the keyword hits to the provided TableReportModules. * - * @param tableModules modules to report on + * @param tableModule module to report on */ @SuppressWarnings("deprecation") private void writeKeywordHits(TableReportModule tableModule, String comment, HashSet tagNamesFilter) { @@ -1011,7 +1016,7 @@ class ReportGenerator { /** * Write the hash set hits to the provided TableReportModules. * - * @param tableModules modules to report on + * @param tableModule module to report on */ @SuppressWarnings("deprecation") private void writeHashsetHits(TableReportModule tableModule, String comment, HashSet tagNamesFilter) { From f0b262b9aec2c27048cfdb7ea1ab2b8632e12489 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 3 May 2016 14:21:57 -0400 Subject: [PATCH 05/39] Updated documentation. --- .../sleuthkit/autopsy/report/ReportGenerator.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 4175831392..93e853ff92 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -121,7 +121,15 @@ class ReportGenerator { } } - ReportGenerator(TableReportModule tableModuleStates, GeneralReportModule generalModuleStates, FileReportModule fileListModuleStates) { + /** + * Creates a report generator. Only one of the passed arguments should be + * non-null. + * + * @param tableModule The table report module + * @param generalModule The general report module + * @param fileListModule The file report module + */ + ReportGenerator(TableReportModule tableModule, GeneralReportModule generalModule, FileReportModule fileListModule) { // Create the root reports directory path of the form: /Reports/ / DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss"); Date date = new Date(); @@ -140,7 +148,7 @@ class ReportGenerator { } // Initialize the progress panels - setupProgressPanels(tableModuleStates, generalModuleStates, fileListModuleStates); + setupProgressPanels(tableModule, generalModule, fileListModule); this.columnHeaderMap = new HashMap<>(); } From e060d843c4aac0cd831f7e2763a089d151c8eed5 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 3 May 2016 15:35:03 -0400 Subject: [PATCH 06/39] Fixed save configuration problem. --- Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java b/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java index 9677f7d6f5..b5e3a80034 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportWizardPanel1.java @@ -116,7 +116,7 @@ class ReportWizardPanel1 implements WizardDescriptor.FinishablePanel Date: Wed, 11 May 2016 10:08:16 -0400 Subject: [PATCH 07/39] Used anonymous swing workers to generate reports, finished cleanup. --- .../autopsy/report/ReportGenerator.java | 2002 ++--------------- .../autopsy/report/ReportWizardAction.java | 16 +- .../autopsy/report/TableReportGenerator.java | 1680 ++++++++++++++ 3 files changed, 1849 insertions(+), 1849 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 93e853ff92..fd33d20c7a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -26,24 +26,14 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; -import java.sql.ResultSet; -import java.sql.SQLException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -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; @@ -52,29 +42,18 @@ import javax.swing.SwingWorker; import org.openide.filesystems.FileUtil; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.EscapeUtil; -import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; -import org.sleuthkit.datamodel.BlackboardArtifactTag; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; -import org.sleuthkit.datamodel.BlackboardAttribute.Type; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; /** * Instances of this class use GeneralReportModules, TableReportModules and - * FileReportModules to generate a report. If desired, displayProgressPanels() + * FileReportModules to generate a report. If desired, displayProgressPanel() * can be called to show report generation progress using ReportProgressPanel * objects displayed using a dialog box. */ @@ -96,7 +75,6 @@ class ReportGenerator { * Progress panel that can be used to check for cancellation. */ private ReportProgressPanel progressPanel; - private Map> columnHeaderMap; private String reportPath; private ReportGenerationPanel panel = new ReportGenerationPanel(); @@ -117,7 +95,6 @@ class ReportGenerator { } MessageNotifyUtil.Notify.error( NbBundle.getMessage(this.getClass(), "ReportGenerator.notifyErr.errsDuringRptGen"), errorString); - return; } } @@ -125,8 +102,8 @@ class ReportGenerator { * Creates a report generator. Only one of the passed arguments should be * non-null. * - * @param tableModule The table report module - * @param generalModule The general report module + * @param tableModule The table report module + * @param generalModule The general report module * @param fileListModule The file report module */ ReportGenerator(TableReportModule tableModule, GeneralReportModule generalModule, FileReportModule fileListModule) { @@ -148,61 +125,13 @@ class ReportGenerator { } // Initialize the progress panels - setupProgressPanels(tableModule, generalModule, fileListModule); - this.columnHeaderMap = new HashMap<>(); - } - - /** - * Create a ReportProgressPanel for each report generation module selected - * by the user. - * - * @param tableModule The TableReportModule - * @param generalModule The GeneralReportModule - * @param fileListModule The FileReportModule - */ - private void setupProgressPanels(TableReportModule tableModule, GeneralReportModule generalModule, FileReportModule fileListModule) { - /* - * Sets ups the progress panels based upon which one is null. - */ - if (null != tableModule) { - String reportFilePath = tableModule.getRelativeFilePath(); - if (!reportFilePath.isEmpty()) { - this.tableReportModule = tableModule; - this.progressPanel = panel.addReport(tableModule.getName(), reportPath + reportFilePath); - } else { - this.tableReportModule = tableModule; - this.progressPanel = panel.addReport(tableModule.getName(), null); - } - } - - if (null != generalModule) { - String reportFilePath = generalModule.getRelativeFilePath(); - if (!reportFilePath.isEmpty()) { - this.generalReportModule = generalModule; - this.progressPanel = panel.addReport(generalModule.getName(), reportPath + reportFilePath); - } else { - this.generalReportModule = generalModule; - this.progressPanel = panel.addReport(generalModule.getName(), null); - } - } - - if (null != fileListModule) { - String reportFilePath = fileListModule.getRelativeFilePath(); - if (!reportFilePath.isEmpty()) { - fileReportModule = fileListModule; - this.progressPanel = panel.addReport(fileListModule.getName(), reportPath + reportFilePath); - } else { - fileReportModule = fileListModule; - this.progressPanel = panel.addReport(fileListModule.getName(), null); - } - } } /** * Display the progress panels to the user, and add actions to close the * parent dialog. */ - public void displayProgressPanels() { + public void displayProgressPanel() { final JDialog dialog = new JDialog(new JFrame(), true); dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); dialog.setTitle(NbBundle.getMessage(this.getClass(), "ReportGenerator.displayProgress.title.text")); @@ -235,10 +164,41 @@ class ReportGenerator { /** * Run the GeneralReportModules using a SwingWorker. */ - public void generateGeneralReports() { - if (this.generalReportModule != null) { - GeneralReportsWorker worker = new GeneralReportsWorker(); + void generateGeneralReport(GeneralReportModule generalReportModule) { + if (generalReportModule != null) { + String reportFilePath = generalReportModule.getRelativeFilePath(); + if (!reportFilePath.isEmpty()) { + this.progressPanel = panel.addReport(generalReportModule.getName(), reportPath + reportFilePath); + } else { + this.progressPanel = panel.addReport(generalReportModule.getName(), null); + } + SwingWorker worker = new SwingWorker() { + @Override + protected Integer doInBackground() throws Exception { + generalReportModule.generateReport(reportPath, progressPanel); + return 1; + } + + @Override + protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + MessageNotifyUtil.Notify.show( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), + MessageNotifyUtil.MessageType.ERROR); + logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS + } // catch and ignore if we were cancelled + catch (java.util.concurrent.CancellationException ex) { + } finally { + displayReportErrors(); + errorList.clear(); + } + } + }; worker.execute(); + displayProgressPanel(); } } @@ -250,10 +210,45 @@ class ReportGenerator { * @param tagSelections the enabled/disabled state of the tag names * to be included in the report */ - public void generateTableReports(Map artifactTypeSelections, Map tagNameSelections) { - if (tableReportModule != null && null != artifactTypeSelections) { - TableReportsWorker worker = new TableReportsWorker(artifactTypeSelections, tagNameSelections); + void generateTableReport(TableReportModule tableReport, Map artifactTypeSelections, Map tagNameSelections) { + if (tableReport != null && null != artifactTypeSelections) { + String reportFilePath = tableReport.getRelativeFilePath(); + if (!reportFilePath.isEmpty()) { + this.progressPanel = panel.addReport(tableReport.getName(), reportPath + reportFilePath); + } else { + this.progressPanel = panel.addReport(tableReport.getName(), null); + } + SwingWorker worker = new SwingWorker() { + @Override + protected Integer doInBackground() throws Exception { + tableReport.startReport(reportPath); + TableReportGenerator generator = new TableReportGenerator(artifactTypeSelections, tagNameSelections, progressPanel, tableReport); + generator.execute(); + tableReport.endReport(); + errorList = generator.getErrorList(); + return 1; + } + + @Override + protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + MessageNotifyUtil.Notify.show( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), + MessageNotifyUtil.MessageType.ERROR); + logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS + } // catch and ignore if we were cancelled + catch (java.util.concurrent.CancellationException ex) { + } finally { + displayReportErrors(); + errorList.clear(); + } + } + }; worker.execute(); + displayProgressPanel(); } } @@ -263,7 +258,7 @@ class ReportGenerator { * @param enabledInfo the Information that should be included about each * file in the report. */ - public void generateFileListReports(Map enabledInfo) { + void generateFileListReport(FileReportModule fileReportModule, Map enabledInfo) { if (fileReportModule != null && null != enabledInfo) { List enabled = new ArrayList<>(); for (Entry e : enabledInfo.entrySet()) { @@ -271,1777 +266,96 @@ class ReportGenerator { enabled.add(e.getKey()); } } - FileReportsWorker worker = new FileReportsWorker(enabled); + String reportFilePath = fileReportModule.getRelativeFilePath(); + if (!reportFilePath.isEmpty()) { + this.progressPanel = panel.addReport(fileReportModule.getName(), reportPath + reportFilePath); + } else { + this.progressPanel = panel.addReport(fileReportModule.getName(), null); + } + SwingWorker worker = new SwingWorker() { + @Override + protected Integer doInBackground() throws Exception { + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + progressPanel.start(); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.queryingDb.text")); + } + + List files = getFiles(); + int numFiles = files.size(); + if (progressPanel.getStatus() != ReportStatus.CANCELED) { + fileReportModule.startReport(reportPath); + fileReportModule.startTable(enabled); + } + progressPanel.setIndeterminate(false); + progressPanel.setMaximumProgress(numFiles); + + int i = 0; + // Add files to report. + for (AbstractFile file : files) { + // Check to see if any reports have been cancelled. + if (progressPanel.getStatus() == ReportStatus.CANCELED) { + return 0; + } else { + fileReportModule.addRow(file, enabled); + progressPanel.increment(); + } + + if ((i % 100) == 0) { + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingFile.text", + file.getName())); + } + i++; + } + + fileReportModule.endTable(); + fileReportModule.endReport(); + progressPanel.complete(ReportStatus.COMPLETE); + return 1; + } + + @Override + protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + MessageNotifyUtil.Notify.show( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), + MessageNotifyUtil.MessageType.ERROR); + logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS + } // catch and ignore if we were cancelled + catch (java.util.concurrent.CancellationException ex) { + } finally { + displayReportErrors(); + errorList.clear(); + } + } + }; worker.execute(); - + displayProgressPanel(); } } /** - * SwingWorker to run GeneralReportModules. - */ - private class GeneralReportsWorker extends SwingWorker { - - @Override - protected Integer doInBackground() throws Exception { - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - generalReportModule.generateReport(reportPath, progressPanel); - } - return 0; - } - - @Override - protected void done() { - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - MessageNotifyUtil.Notify.show( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), - MessageNotifyUtil.MessageType.ERROR); - logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS - } // catch and ignore if we were cancelled - catch (java.util.concurrent.CancellationException ex) { - } finally { - displayReportErrors(); - errorList.clear(); - } - } - - } - - /** - * SwingWorker to run FileReportModules. - */ - private class FileReportsWorker extends SwingWorker { - - private List enabledInfo = Arrays.asList(FileReportDataTypes.values()); - - FileReportsWorker(List enabled) { - enabledInfo = enabled; - } - - @Override - protected Integer doInBackground() throws Exception { - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - progressPanel.start(); - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.queryingDb.text")); - } - - List files = getFiles(); - int numFiles = files.size(); - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - fileReportModule.startReport(reportPath); - fileReportModule.startTable(enabledInfo); - } - progressPanel.setIndeterminate(false); - progressPanel.setMaximumProgress(numFiles); - - int i = 0; - // Add files to report. - for (AbstractFile file : files) { - // Check to see if any reports have been cancelled. - if (progressPanel.getStatus() == ReportStatus.CANCELED) { - return 0; - } else { - fileReportModule.addRow(file, enabledInfo); - progressPanel.increment(); - } - - if ((i % 100) == 0) { - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingFile.text", - file.getName())); - } - i++; - } - - fileReportModule.endTable(); - fileReportModule.endReport(); - progressPanel.complete(ReportStatus.COMPLETE); - - return 0; - } - - /** - * Get all files in the image. - * - * @return - */ - private List getFiles() { - List absFiles; - try { - SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); - absFiles = skCase.findAllFilesWhere("meta_type != " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()); //NON-NLS - return absFiles; - } catch (TskCoreException ex) { - MessageNotifyUtil.Notify.show( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), - MessageNotifyUtil.MessageType.ERROR); - logger.log(Level.SEVERE, "failed to generate reports. Unable to get all files in the image.", ex); //NON-NLS - return Collections.emptyList(); - } - } - - @Override - protected void done() { - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - MessageNotifyUtil.Notify.show( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), - MessageNotifyUtil.MessageType.ERROR); - logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS - } // catch and ignore if we were cancelled - catch (java.util.concurrent.CancellationException ex) { - } finally { - displayReportErrors(); - errorList.clear(); - } - } - } - - /** - * SwingWorker to run TableReportModules to report on blackboard artifacts, - * content tags, and blackboard artifact tags. - */ - private class TableReportsWorker extends SwingWorker { - - private List artifactTypes = new ArrayList<>(); - private HashSet tagNamesFilter = new HashSet<>(); - - private List images = new ArrayList<>(); - - TableReportsWorker(Map artifactTypeSelections, Map tagNameSelections) { - - // Get the artifact types selected by the user. - for (Entry entry : artifactTypeSelections.entrySet()) { - if (entry.getValue()) { - artifactTypes.add(entry.getKey()); - } - } - - // Get the tag names selected by the user and make a tag names filter. - if (null != tagNameSelections) { - for (Entry entry : tagNameSelections.entrySet()) { - if (entry.getValue() == true) { - tagNamesFilter.add(entry.getKey()); - } - } - } - } - - @Override - protected Integer doInBackground() throws Exception { - // Start the progress indicators for each active TableReportModule. - tableReportModule.startReport(reportPath); - progressPanel.start(); - progressPanel.setIndeterminate(false); - progressPanel.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags - // report on the blackboard results - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - makeBlackboardArtifactTables(); - } - - // report on the tagged files and artifacts - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - makeContentTagsTables(); - } - - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - makeBlackboardArtifactTagsTables(); - } - - if (progressPanel.getStatus() != ReportStatus.CANCELED) { - // report on the tagged images - makeThumbnailTable(); - } - - // finish progress, wrap up - progressPanel.complete(ReportStatus.COMPLETE); - tableReportModule.endReport(); - - return 0; - } - - /** - * Generate the tables for the selected blackboard artifacts - */ - private void makeBlackboardArtifactTables() { - // Make a comment string describing the tag names filter in effect. - StringBuilder comment = new StringBuilder(); - if (!tagNamesFilter.isEmpty()) { - comment.append(NbBundle.getMessage(this.getClass(), "ReportGenerator.artifactTable.taggedResults.text")); - comment.append(makeCommaSeparatedList(tagNamesFilter)); - } - - // Add a table to the report for every enabled blackboard artifact type. - for (BlackboardArtifact.Type type : artifactTypes) { - // Check for cancellaton. - - if (progressPanel.getStatus() == ReportStatus.CANCELED) { - return; - } - - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - type.getDisplayName())); - - // Keyword hits and hashset hit artifacts get special handling. - if (type.getTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - writeKeywordHits(tableReportModule, comment.toString(), tagNamesFilter); - continue; - } else if (type.getTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { - writeHashsetHits(tableReportModule, comment.toString(), tagNamesFilter); - continue; - } - - List artifactList = getFilteredArtifacts(type, tagNamesFilter); - - if (artifactList.isEmpty()) { - continue; - } - - /* - Gets all of the attribute types of this artifact type by adding - all of the types to a set - */ - 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()); - } - - tableReportModule.startDataType(type.getDisplayName(), comment.toString()); - tableReportModule.startTable(columnHeaderNames); - for (ArtifactData artifactData : artifactList) { - // Get the row data for this artifact, and has the - // module add it. - List rowData = artifactData.getRow(); - if (rowData.isEmpty()) { - continue; - } - - tableReportModule.addRow(rowData); - } - // Finish up this data type - progressPanel.increment(); - tableReportModule.endTable(); - tableReportModule.endDataType(); - } - } - - /** - * Make table for tagged files - */ - @SuppressWarnings("deprecation") - private void makeContentTagsTables() { - - // Get the content tags. - List tags; - try { - tags = Case.getCurrentCase().getServices().getTagsManager().getAllContentTags(); - } catch (TskCoreException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetContentTags")); - logger.log(Level.SEVERE, "failed to get content tags", ex); //NON-NLS - return; - } - - // Tell the modules reporting on content tags is beginning. - // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. - // @@@ Alos Using the obsolete ARTIFACT_TYPE.TSK_TAG_FILE is also an expedient hack. - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName())); - ArrayList columnHeaders = new ArrayList<>(Arrays.asList( - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.tag"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.file"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.comment"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeModified"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeChanged"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeAccessed"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeCreated"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.size"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.hash"))); - - StringBuilder comment = new StringBuilder(); - if (!tagNamesFilter.isEmpty()) { - comment.append( - NbBundle.getMessage(this.getClass(), "ReportGenerator.makeContTagTab.taggedFiles.msg")); - comment.append(makeCommaSeparatedList(tagNamesFilter)); - } - if (tableReportModule instanceof ReportHTML) { - ReportHTML htmlReportModule = (ReportHTML) tableReportModule; - htmlReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); - htmlReportModule.startContentTagsTable(columnHeaders); - } else { - tableReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); - tableReportModule.startTable(columnHeaders); - } - - // Give the modules the rows for the content tags. - for (ContentTag tag : tags) { - // skip tags that we are not reporting on - if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) { - continue; - } - - String fileName; - try { - fileName = tag.getContent().getUniquePath(); - } catch (TskCoreException ex) { - fileName = tag.getContent().getName(); - } - - ArrayList rowData = new ArrayList<>(Arrays.asList(tag.getName().getDisplayName(), fileName, tag.getComment())); - Content content = tag.getContent(); - if (content instanceof AbstractFile) { - AbstractFile file = (AbstractFile) content; - - // Add metadata about the file to HTML output - rowData.add(file.getMtimeAsDate()); - rowData.add(file.getCtimeAsDate()); - rowData.add(file.getAtimeAsDate()); - rowData.add(file.getCrtimeAsDate()); - rowData.add(Long.toString(file.getSize())); - rowData.add(file.getMd5Hash()); - } - // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. - if (tableReportModule instanceof ReportHTML) { - ReportHTML htmlReportModule = (ReportHTML) tableReportModule; - htmlReportModule.addRowWithTaggedContentHyperlink(rowData, tag); - } else { - tableReportModule.addRow(rowData); - } - - // see if it is for an image so that we later report on it - checkIfTagHasImage(tag); - } - - // The the modules content tags reporting is ended. - progressPanel.increment(); - tableReportModule.endTable(); - tableReportModule.endDataType(); - } - - @Override - protected void done() { - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - MessageNotifyUtil.Notify.show( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), - MessageNotifyUtil.MessageType.ERROR); - logger.log(Level.SEVERE, "failed to generate reports", ex.getCause()); //NON-NLS - logger.log(Level.SEVERE, "failed to generate reports", ex); //NON-NLS - } // catch and ignore if we were cancelled - catch (java.util.concurrent.CancellationException ex) { - } finally { - displayReportErrors(); - errorList.clear(); - } - } - - /** - * Generate the tables for the tagged artifacts - */ - @SuppressWarnings("deprecation") - private void makeBlackboardArtifactTagsTables() { - - List tags; - try { - tags = Case.getCurrentCase().getServices().getTagsManager().getAllBlackboardArtifactTags(); - } catch (TskCoreException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBArtifactTags")); - logger.log(Level.SEVERE, "failed to get blackboard artifact tags", ex); //NON-NLS - return; - } - - // Tell the modules reporting on blackboard artifact tags data type is beginning. - // @@@ Using the obsolete ARTIFACT_TYPE.TSK_TAG_ARTIFACT is an expedient hack. - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName())); - StringBuilder comment = new StringBuilder(); - if (!tagNamesFilter.isEmpty()) { - comment.append( - NbBundle.getMessage(this.getClass(), "ReportGenerator.makeBbArtTagTab.taggedRes.msg")); - comment.append(makeCommaSeparatedList(tagNamesFilter)); - } - tableReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName(), comment.toString()); - tableReportModule.startTable(new ArrayList<>(Arrays.asList( - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.resultType"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.tag"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.comment"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.srcFile")))); - - // Give the modules the rows for the content tags. - for (BlackboardArtifactTag tag : tags) { - if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) { - continue; - } - - List row; - row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName(), tag.getComment(), tag.getContent().getName())); - tableReportModule.addRow(row); - - // check if the tag is an image that we should later make a thumbnail for - checkIfTagHasImage(tag); - } - - // The the modules blackboard artifact tags reporting is ended. - progressPanel.increment(); - tableReportModule.endTable(); - tableReportModule.endDataType(); - } - - /** - * Test if the user requested that this tag be reported on - * - * @param tagName - * - * @return true if it should be reported on - */ - private boolean passesTagNamesFilter(String tagName) { - return tagNamesFilter.isEmpty() || tagNamesFilter.contains(tagName); - } - - /** - * Make a report for the files that were previously found to be images. - */ - private void makeThumbnailTable() { - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.createdThumb.text")); - - if (tableReportModule instanceof ReportHTML) { - ReportHTML htmlModule = (ReportHTML) tableReportModule; - htmlModule.startDataType( - NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.name"), - NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.desc")); - List emptyHeaders = new ArrayList<>(); - for (int i = 0; i < ReportHTML.THUMBNAIL_COLUMNS; i++) { - emptyHeaders.add(""); - } - htmlModule.startTable(emptyHeaders); - - htmlModule.addThumbnailRows(images); - - htmlModule.endTable(); - htmlModule.endDataType(); - } - - } - - /** - * Analyze artifact associated with tag and add to internal list if it - * is associated with an image. - * - * @param artifactTag - */ - private void checkIfTagHasImage(BlackboardArtifactTag artifactTag) { - AbstractFile file; - try { - file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(artifactTag.getArtifact().getObjectID()); - } catch (TskCoreException ex) { - errorList.add( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.errGetContentFromBBArtifact")); - logger.log(Level.WARNING, "Error while getting content from a blackboard artifact to report on.", ex); //NON-NLS - return; - } - - if (file != null) { - checkIfFileIsImage(file); - } - } - - /** - * Analyze file that tag is associated with and determine if it is an - * image and should have a thumbnail reported for it. Images are added - * to internal list. - * - * @param contentTag - */ - private void checkIfTagHasImage(ContentTag contentTag) { - Content c = contentTag.getContent(); - if (c instanceof AbstractFile == false) { - return; - } - checkIfFileIsImage((AbstractFile) c); - } - - /** - * If file is an image file, add it to the internal 'images' list. - * - * @param file - */ - private void checkIfFileIsImage(AbstractFile file) { - - if (file.isDir() - || file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS - || file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) { - return; - } - - if (ImageUtils.thumbnailSupported(file)) { - images.add(file); - } - } - } - -/// @@@ Should move the methods specific to TableReportsWorker into that scope. - private Boolean failsTagFilter(HashSet tagNames, HashSet tagsNamesFilter) { - if (null == tagsNamesFilter || tagsNamesFilter.isEmpty()) { - return false; - } - - HashSet filteredTagNames = new HashSet<>(tagNames); - filteredTagNames.retainAll(tagsNamesFilter); - return filteredTagNames.isEmpty(); - } - - /** - * Get a List of the artifacts and data of the given type that pass the - * given Tag Filter. + * Get all files in the image. * - * @param type The artifact type to get - * @param tagNamesFilter The tag names that should be included. - * - * @return a list of the filtered tags. + * @return */ - private List getFilteredArtifacts(BlackboardArtifact.Type type, HashSet tagNamesFilter) { - List artifacts = new ArrayList<>(); + private List getFiles() { + List absFiles; try { - for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(type.getTypeID())) { - List tags = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact); - HashSet uniqueTagNames = new HashSet<>(); - for (BlackboardArtifactTag tag : tags) { - uniqueTagNames.add(tag.getName().getDisplayName()); - } - if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { - continue; - } - try { - artifacts.add(new ArtifactData(artifact, skCase.getBlackboardAttributes(artifact), uniqueTagNames)); - } catch (TskCoreException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBAttribs")); - logger.log(Level.SEVERE, "Failed to get Blackboard Attributes when generating report.", ex); //NON-NLS - } - } + SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); + absFiles = skCase.findAllFilesWhere("meta_type != " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()); //NON-NLS + return absFiles; } catch (TskCoreException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBArtifacts")); - logger.log(Level.SEVERE, "Failed to get Blackboard Artifacts when generating report.", ex); //NON-NLS - } - return artifacts; - } - - /** - * Write the keyword hits to the provided TableReportModules. - * - * @param tableModule module to report on - */ - @SuppressWarnings("deprecation") - private void writeKeywordHits(TableReportModule tableModule, String comment, HashSet tagNamesFilter) { - - // Query for keyword lists-only so that we can tell modules what lists - // will exist for their index. - // @@@ There is a bug in here. We should use the tags in the below code - // so that we only report the lists that we will later provide with real - // hits. If no keyord hits are tagged, then we make the page for nothing. - String orderByClause; - if (currentCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { - orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS - } else { - orderByClause = "ORDER BY list ASC"; //NON-NLS - } - String keywordListQuery - = "SELECT att.value_text AS list " - + //NON-NLS - "FROM blackboard_attributes AS att, blackboard_artifacts AS art " - + //NON-NLS - "WHERE att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " - + //NON-NLS - "AND art.artifact_type_id = " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + " " - + //NON-NLS - "AND att.artifact_id = art.artifact_id " - + //NON-NLS - "GROUP BY list " + orderByClause; //NON-NLS - - try (CaseDbQuery dbQuery = skCase.executeQuery(keywordListQuery)) { - ResultSet listsRs = dbQuery.getResultSet(); - List lists = new ArrayList<>(); - while (listsRs.next()) { - String list = listsRs.getString("list"); //NON-NLS - if (list.isEmpty()) { - list = NbBundle.getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs"); - } - lists.add(list); - } - - // Make keyword data type and give them set index - tableModule.startDataType(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), comment); - tableModule.addSetIndex(lists); - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName())); - } catch (TskCoreException | SQLException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryKWLists")); - logger.log(Level.SEVERE, "Failed to query keyword lists: ", ex); //NON-NLS - return; - } - - if (currentCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { - orderByClause = "ORDER BY convert_to(att3.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS - + "convert_to(att1.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS - + "convert_to(f.parent_path, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS - + "convert_to(f.name, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS - + "convert_to(att2.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS - } else { - orderByClause = "ORDER BY list ASC, keyword ASC, parent_path ASC, name ASC, preview ASC"; //NON-NLS - } - // Query for keywords, grouped by list - String keywordsQuery - = "SELECT art.artifact_id, art.obj_id, att1.value_text AS keyword, att2.value_text AS preview, att3.value_text AS list, f.name AS name, f.parent_path AS parent_path " - + //NON-NLS - "FROM blackboard_artifacts AS art, blackboard_attributes AS att1, blackboard_attributes AS att2, blackboard_attributes AS att3, tsk_files AS f " - + //NON-NLS - "WHERE (att1.artifact_id = art.artifact_id) " - + //NON-NLS - "AND (att2.artifact_id = art.artifact_id) " - + //NON-NLS - "AND (att3.artifact_id = art.artifact_id) " - + //NON-NLS - "AND (f.obj_id = art.obj_id) " - + //NON-NLS - "AND (att1.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID() + ") " - + //NON-NLS - "AND (att2.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW.getTypeID() + ") " - + //NON-NLS - "AND (att3.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " - + //NON-NLS - "AND (art.artifact_type_id = " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ") " - + //NON-NLS - orderByClause; //NON-NLS - - try (CaseDbQuery dbQuery = skCase.executeQuery(keywordsQuery)) { - ResultSet resultSet = dbQuery.getResultSet(); - - String currentKeyword = ""; - String currentList = ""; - while (resultSet.next()) { - // Check to see if all the TableReportModules have been canceled - if (progressPanel.getStatus() == ReportStatus.CANCELED) { - break; - } - - // Get any tags that associated with this artifact and apply the tag filter. - HashSet uniqueTagNames = getUniqueTagNames(resultSet.getLong("artifact_id")); //NON-NLS - if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { - continue; - } - String tagsList = makeCommaSeparatedList(uniqueTagNames); - - Long objId = resultSet.getLong("obj_id"); //NON-NLS - String keyword = resultSet.getString("keyword"); //NON-NLS - String preview = resultSet.getString("preview"); //NON-NLS - String list = resultSet.getString("list"); //NON-NLS - String uniquePath = ""; - - try { - AbstractFile f = skCase.getAbstractFileById(objId); - if (f != null) { - uniquePath = skCase.getAbstractFileById(objId).getUniquePath(); - } - } catch (TskCoreException ex) { - errorList.add( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileByID")); - logger.log(Level.WARNING, "Failed to get Abstract File by ID.", ex); //NON-NLS - } - - // If the lists aren't the same, we've started a new list - if ((!list.equals(currentList) && !list.isEmpty()) || (list.isEmpty() && !currentList.equals( - NbBundle.getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs")))) { - if (!currentList.isEmpty()) { - tableModule.endTable(); - tableModule.endSet(); - } - currentList = list.isEmpty() ? NbBundle - .getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs") : list; - currentKeyword = ""; // reset the current keyword because it's a new list - tableModule.startSet(currentList); - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", - ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), currentList)); - } - if (!keyword.equals(currentKeyword)) { - if (!currentKeyword.equals("")) { - tableModule.endTable(); - } - currentKeyword = keyword; - tableModule.addSetElement(currentKeyword); - List columnHeaderNames = new ArrayList<>(); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); - tableModule.startTable(columnHeaderNames); - } - - String previewreplace = EscapeUtil.escapeHtml(preview); - tableModule.addRow(Arrays.asList(new String[]{previewreplace.replaceAll(" tagNamesFilter) { - String orderByClause; - if (currentCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { - orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS - } else { - orderByClause = "ORDER BY att.value_text ASC"; //NON-NLS - } - String hashsetsQuery - = "SELECT att.value_text AS list " - + //NON-NLS - "FROM blackboard_attributes AS att, blackboard_artifacts AS art " - + //NON-NLS - "WHERE att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " - + //NON-NLS - "AND art.artifact_type_id = " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + " " - + //NON-NLS - "AND att.artifact_id = art.artifact_id " - + //NON-NLS - "GROUP BY list " + orderByClause; //NON-NLS - - try (CaseDbQuery dbQuery = skCase.executeQuery(hashsetsQuery)) { - // Query for hashsets - ResultSet listsRs = dbQuery.getResultSet(); - List lists = new ArrayList<>(); - while (listsRs.next()) { - lists.add(listsRs.getString("list")); //NON-NLS - } - - tableModule.startDataType(ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), comment); - tableModule.addSetIndex(lists); - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", - ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName())); - } catch (TskCoreException | SQLException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryHashsetLists")); - logger.log(Level.SEVERE, "Failed to query hashset lists: ", ex); //NON-NLS - return; - } - - if (currentCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { - orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS - + "convert_to(f.parent_path, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS - + "convert_to(f.name, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS - + "size ASC NULLS FIRST"; //NON-NLS - } else { - orderByClause = "ORDER BY att.value_text ASC, f.parent_path ASC, f.name ASC, size ASC"; //NON-NLS - } - String hashsetHitsQuery - = "SELECT art.artifact_id, art.obj_id, att.value_text AS setname, f.name AS name, f.size AS size, f.parent_path AS parent_path " - + //NON-NLS - "FROM blackboard_artifacts AS art, blackboard_attributes AS att, tsk_files AS f " - + //NON-NLS - "WHERE (att.artifact_id = art.artifact_id) " - + //NON-NLS - "AND (f.obj_id = art.obj_id) " - + //NON-NLS - "AND (att.attribute_type_id = " + ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " - + //NON-NLS - "AND (art.artifact_type_id = " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ") " - + //NON-NLS - orderByClause; //NON-NLS - - try (CaseDbQuery dbQuery = skCase.executeQuery(hashsetHitsQuery)) { - // Query for hashset hits - ResultSet resultSet = dbQuery.getResultSet(); - String currentSet = ""; - while (resultSet.next()) { - // Check to see if all the TableReportModules have been canceled - if (progressPanel.getStatus() == ReportStatus.CANCELED) { - break; - } - - // Get any tags that associated with this artifact and apply the tag filter. - HashSet uniqueTagNames = getUniqueTagNames(resultSet.getLong("artifact_id")); //NON-NLS - if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { - continue; - } - String tagsList = makeCommaSeparatedList(uniqueTagNames); - - Long objId = resultSet.getLong("obj_id"); //NON-NLS - String set = resultSet.getString("setname"); //NON-NLS - String size = resultSet.getString("size"); //NON-NLS - String uniquePath = ""; - - try { - AbstractFile f = skCase.getAbstractFileById(objId); - if (f != null) { - uniquePath = skCase.getAbstractFileById(objId).getUniquePath(); - } - } catch (TskCoreException ex) { - errorList.add( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileFromID")); - logger.log(Level.WARNING, "Failed to get Abstract File from ID.", ex); //NON-NLS - return; - } - - // If the sets aren't the same, we've started a new set - if (!set.equals(currentSet)) { - if (!currentSet.isEmpty()) { - tableModule.endTable(); - tableModule.endSet(); - } - currentSet = set; - tableModule.startSet(currentSet); - List columnHeaderNames = new ArrayList<>(); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size")); - columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); - tableModule.startTable(columnHeaderNames); - progressPanel.updateStatusLabel( - NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", - ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), currentSet)); - } - - // Add a row for this hit to every module - tableModule.addRow(Arrays.asList(new String[]{uniquePath, size, tagsList})); - } - - // Finish the current data type - progressPanel.increment(); - tableModule.endDataType(); - } catch (TskCoreException | SQLException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryHashsetHits")); - logger.log(Level.SEVERE, "Failed to query hashsets hits: ", ex); //NON-NLS - } - } - - /** - * For a given artifact type ID, return the list of the columns that we are - * reporting on. - * - * @param artifactTypeId artifact type ID - * @param attributeTypeSet The set of attributeTypeSet available for this - * artifact type - * - * @return List row titles - */ - private List getArtifactTableColumns(int artifactTypeId, Set attributeTypeSet) { - ArrayList columns = new ArrayList<>(); - - // 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))); - - 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.dateCreated"), - new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED))); - - 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_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"))); - - // Short circuits to guarantee that the attribute types aren't added - // twice. - return columns; - } - // 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; - } - - /** - * Converts a collection of strings into a single string of comma-separated - * items - * - * @param items A collection of strings - * - * @return A string of comma-separated items - */ - private String makeCommaSeparatedList(Collection items) { - String list = ""; - for (Iterator iterator = items.iterator(); iterator.hasNext();) { - list += iterator.next() + (iterator.hasNext() ? ", " : ""); - } - return list; - } - - /** - * Given a tsk_file's obj_id, return the unique path of that file. - * - * @param objId tsk_file obj_id - * - * @return String unique path - */ - private String getFileUniquePath(Content content) { - try { - if (content != null) { - return content.getUniquePath(); - } else { - return ""; - } - } catch (TskCoreException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileByID")); - logger.log(Level.WARNING, "Failed to get Abstract File by ID.", ex); //NON-NLS - } - return ""; - - } - - /** - * Container class that holds data about an Artifact to eliminate duplicate - * calls to the Sleuthkit database. - */ - private class ArtifactData implements Comparable { - - private BlackboardArtifact artifact; - private List attributes; - private HashSet tags; - private List rowData = null; - private Content content; - - ArtifactData(BlackboardArtifact artifact, List attrs, HashSet tags) { - this.artifact = artifact; - this.attributes = attrs; - this.tags = tags; - try { - this.content = Case.getCurrentCase().getSleuthkitCase().getContentById(artifact.getObjectID()); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Could not get content from database"); - } - } - - public BlackboardArtifact getArtifact() { - return artifact; - } - - public List getAttributes() { - return attributes; - } - - public HashSet getTags() { - return tags; - } - - public long getArtifactID() { - return artifact.getArtifactID(); - } - - public long getObjectID() { - return artifact.getObjectID(); - } - - /** - * @return the content - */ - public Content getContent() { - return content; - } - - /** - * Compares ArtifactData objects by the first attribute they have in - * 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 - * the same type. - */ - @Override - public int compareTo(ArtifactData otherArtifactData) { - List thisRow = getRow(); - List otherRow = otherArtifactData.getRow(); - for (int i = 0; i < thisRow.size(); i++) { - int compare = thisRow.get(i).compareTo(otherRow.get(i)); - if (compare != 0) { - return compare; - } - } - 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(); - // 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( - NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.coreExceptionWhileGenRptRow")); - logger.log(Level.WARNING, "Core exception while generating row data for artifact report.", ex); //NON-NLS - rowData = Collections.emptyList(); - } - } - return rowData; - } - - /** - * Get a list of Strings with all the row values for the Artifact in the - * correct order to be written to the report. - * - * @return List row values. Values could be null if attribute is - * not defined in artifact - * - * @throws TskCoreException - */ - private List getOrderedRowDataAsStrings() throws TskCoreException { - - List orderedRowData = new ArrayList<>(); - if (ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() == getArtifact().getArtifactTypeID()) { - if (content != null && content instanceof AbstractFile) { - AbstractFile file = (AbstractFile) content; - 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()); - } 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(content); - } - attributeDataArray[2] = pathToShow; - } - } - 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); - } - } - - return orderedRowData; - } - - } - - /** - * Get any tags associated with an artifact - * - * @param artifactId - * - * @return hash set of tag display names - * - * @throws SQLException - */ - @SuppressWarnings("deprecation") - private HashSet getUniqueTagNames(long artifactId) throws TskCoreException { - HashSet uniqueTagNames = new HashSet<>(); - - String query = "SELECT display_name, artifact_id FROM tag_names AS tn, blackboard_artifact_tags AS bat " - + //NON-NLS - "WHERE tn.tag_name_id = bat.tag_name_id AND bat.artifact_id = " + artifactId; //NON-NLS - - try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { - ResultSet tagNameRows = dbQuery.getResultSet(); - while (tagNameRows.next()) { - uniqueTagNames.add(tagNameRows.getString("display_name")); //NON-NLS - } - } catch (TskCoreException | SQLException ex) { - throw new TskCoreException("Error getting tag names for artifact: ", ex); - } - - 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)) { - if (attribute.getAttributeType().getValueType() != BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) { - return attribute.getDisplayString(); - } else { - return ContentUtils.getStringTime(attribute.getValueLong(), artData.getContent()); - } - } - } - 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.getContent()); - /*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; + MessageNotifyUtil.Notify.show( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorTitle"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.errors.reportErrorText") + ex.getLocalizedMessage(), + MessageNotifyUtil.MessageType.ERROR); + logger.log(Level.SEVERE, "failed to generate reports. Unable to get all files in the image.", ex); //NON-NLS + return Collections.emptyList(); } } } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java index 0e350e12d1..3c274c919f 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java @@ -1,4 +1,4 @@ - /* +/* * * Autopsy Forensic Browser * @@ -68,10 +68,16 @@ public final class ReportWizardAction extends CallableSystemAction implements Pr ReportGenerator generator = new ReportGenerator((TableReportModule) wiz.getProperty("tableModule"), //NON-NLS (GeneralReportModule) wiz.getProperty("generalModule"), //NON-NLS (FileReportModule) wiz.getProperty("fileModule")); //NON-NLS - generator.generateTableReports((Map) wiz.getProperty("artifactStates"), (Map) wiz.getProperty("tagStates")); //NON-NLS - generator.generateFileListReports((Map) wiz.getProperty("fileReportOptions")); //NON-NLS - generator.generateGeneralReports(); - generator.displayProgressPanels(); + TableReportModule tableReport = (TableReportModule) wiz.getProperty("tableModule"); + GeneralReportModule generalReport = (GeneralReportModule) wiz.getProperty("generalModule"); + FileReportModule fileReport = (FileReportModule) wiz.getProperty("fileModule"); + if (tableReport != null) { + generator.generateTableReport(tableReport, (Map) wiz.getProperty("artifactStates"), (Map) wiz.getProperty("tagStates")); //NON-NLS + } else if (generalReport != null) { + generator.generateGeneralReport(generalReport); + } else if (fileReport != null) { + generator.generateFileListReport(fileReport, (Map) wiz.getProperty("fileReportOptions")); //NON-NLS + } } } diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java new file mode 100755 index 0000000000..16e32b8461 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -0,0 +1,1680 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.report; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.Level; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.EscapeUtil; +import org.sleuthkit.autopsy.coreutils.ImageUtils; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardArtifactTag; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; + +class TableReportGenerator { + + private final List artifactTypes = new ArrayList<>(); + private final HashSet tagNamesFilter = new HashSet<>(); + + private final List images = new ArrayList<>(); + private final ReportProgressPanel progressPanel; + private final TableReportModule tableReport; + private final Map> columnHeaderMap; + private static final Logger logger = Logger.getLogger(TableReportGenerator.class.getName()); + + private final List errorList; + + TableReportGenerator(Map artifactTypeSelections, Map tagNameSelections, ReportProgressPanel progressPanel, TableReportModule tableReport) { + + this.progressPanel = progressPanel; + this.tableReport = tableReport; + this.columnHeaderMap = new HashMap<>(); + errorList = new ArrayList<>(); + // Get the artifact types selected by the user. + for (Map.Entry entry : artifactTypeSelections.entrySet()) { + if (entry.getValue()) { + artifactTypes.add(entry.getKey()); + } + } + + // Get the tag names selected by the user and make a tag names filter. + if (null != tagNameSelections) { + for (Map.Entry entry : tagNameSelections.entrySet()) { + if (entry.getValue() == true) { + tagNamesFilter.add(entry.getKey()); + } + } + } + } + + protected void execute() { + // Start the progress indicators for each active TableReportModule. + + progressPanel.start(); + progressPanel.setIndeterminate(false); + progressPanel.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags + // report on the blackboard results + if (progressPanel.getStatus() != ReportProgressPanel.ReportStatus.CANCELED) { + makeBlackboardArtifactTables(); + } + + // report on the tagged files and artifacts + if (progressPanel.getStatus() != ReportProgressPanel.ReportStatus.CANCELED) { + makeContentTagsTables(); + } + + if (progressPanel.getStatus() != ReportProgressPanel.ReportStatus.CANCELED) { + makeBlackboardArtifactTagsTables(); + } + + if (progressPanel.getStatus() != ReportProgressPanel.ReportStatus.CANCELED) { + // report on the tagged images + makeThumbnailTable(); + } + + // finish progress, wrap up + progressPanel.complete(ReportProgressPanel.ReportStatus.COMPLETE); + } + + /** + * Generate the tables for the selected blackboard artifacts + */ + private void makeBlackboardArtifactTables() { + // Make a comment string describing the tag names filter in effect. + StringBuilder comment = new StringBuilder(); + if (!tagNamesFilter.isEmpty()) { + comment.append(NbBundle.getMessage(this.getClass(), "ReportGenerator.artifactTable.taggedResults.text")); + comment.append(makeCommaSeparatedList(tagNamesFilter)); + } + + // Add a table to the report for every enabled blackboard artifact type. + for (BlackboardArtifact.Type type : artifactTypes) { + // Check for cancellaton. + + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + return; + } + + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + type.getDisplayName())); + + // Keyword hits and hashset hit artifacts get special handling. + if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { + writeKeywordHits(tableReport, comment.toString(), tagNamesFilter); + continue; + } else if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { + writeHashsetHits(tableReport, comment.toString(), tagNamesFilter); + continue; + } + + List artifactList = getFilteredArtifacts(type, tagNamesFilter); + + if (artifactList.isEmpty()) { + continue; + } + + /* + Gets all of the attribute types of this artifact type by adding + all of the types to a set + */ + Set attrTypeSet = new TreeSet<>((BlackboardAttribute.Type o1, BlackboardAttribute.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; + } + 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()); + } + + tableReport.startDataType(type.getDisplayName(), comment.toString()); + tableReport.startTable(columnHeaderNames); + for (ArtifactData artifactData : artifactList) { + // Get the row data for this artifact, and has the + // module add it. + List rowData = artifactData.getRow(); + if (rowData.isEmpty()) { + continue; + } + + tableReport.addRow(rowData); + } + // Finish up this data type + progressPanel.increment(); + tableReport.endTable(); + tableReport.endDataType(); + } + } + + /** + * Make table for tagged files + */ + @SuppressWarnings("deprecation") + private void makeContentTagsTables() { + + // Get the content tags. + List tags; + try { + tags = Case.getCurrentCase().getServices().getTagsManager().getAllContentTags(); + } catch (TskCoreException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetContentTags")); + logger.log(Level.SEVERE, "failed to get content tags", ex); //NON-NLS + return; + } + + // Tell the modules reporting on content tags is beginning. + // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. + // @@@ Alos Using the obsolete ARTIFACT_TYPE.TSK_TAG_FILE is also an expedient hack. + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName())); + ArrayList columnHeaders = new ArrayList<>(Arrays.asList( + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.tag"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.file"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.comment"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeModified"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeChanged"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeAccessed"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeCreated"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.size"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.hash"))); + + StringBuilder comment = new StringBuilder(); + if (!tagNamesFilter.isEmpty()) { + comment.append( + NbBundle.getMessage(this.getClass(), "ReportGenerator.makeContTagTab.taggedFiles.msg")); + comment.append(makeCommaSeparatedList(tagNamesFilter)); + } + if (tableReport instanceof ReportHTML) { + ReportHTML htmlReportModule = (ReportHTML) tableReport; + htmlReportModule.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); + htmlReportModule.startContentTagsTable(columnHeaders); + } else { + tableReport.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); + tableReport.startTable(columnHeaders); + } + + // Give the modules the rows for the content tags. + for (ContentTag tag : tags) { + // skip tags that we are not reporting on + if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) { + continue; + } + + String fileName; + try { + fileName = tag.getContent().getUniquePath(); + } catch (TskCoreException ex) { + fileName = tag.getContent().getName(); + } + + ArrayList rowData = new ArrayList<>(Arrays.asList(tag.getName().getDisplayName(), fileName, tag.getComment())); + Content content = tag.getContent(); + if (content instanceof AbstractFile) { + AbstractFile file = (AbstractFile) content; + + // Add metadata about the file to HTML output + rowData.add(file.getMtimeAsDate()); + rowData.add(file.getCtimeAsDate()); + rowData.add(file.getAtimeAsDate()); + rowData.add(file.getCrtimeAsDate()); + rowData.add(Long.toString(file.getSize())); + rowData.add(file.getMd5Hash()); + } + // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. + if (tableReport instanceof ReportHTML) { + ReportHTML htmlReportModule = (ReportHTML) tableReport; + htmlReportModule.addRowWithTaggedContentHyperlink(rowData, tag); + } else { + tableReport.addRow(rowData); + } + + // see if it is for an image so that we later report on it + checkIfTagHasImage(tag); + } + + // The the modules content tags reporting is ended. + progressPanel.increment(); + tableReport.endTable(); + tableReport.endDataType(); + } + + /** + * Generate the tables for the tagged artifacts + */ + @SuppressWarnings("deprecation") + private void makeBlackboardArtifactTagsTables() { + + List tags; + try { + tags = Case.getCurrentCase().getServices().getTagsManager().getAllBlackboardArtifactTags(); + } catch (TskCoreException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBArtifactTags")); + logger.log(Level.SEVERE, "failed to get blackboard artifact tags", ex); //NON-NLS + return; + } + + // Tell the modules reporting on blackboard artifact tags data type is beginning. + // @@@ Using the obsolete ARTIFACT_TYPE.TSK_TAG_ARTIFACT is an expedient hack. + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName())); + StringBuilder comment = new StringBuilder(); + if (!tagNamesFilter.isEmpty()) { + comment.append( + NbBundle.getMessage(this.getClass(), "ReportGenerator.makeBbArtTagTab.taggedRes.msg")); + comment.append(makeCommaSeparatedList(tagNamesFilter)); + } + tableReport.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName(), comment.toString()); + tableReport.startTable(new ArrayList<>(Arrays.asList( + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.resultType"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.tag"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.comment"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.srcFile")))); + + // Give the modules the rows for the content tags. + for (BlackboardArtifactTag tag : tags) { + if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) { + continue; + } + + List row; + row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName(), tag.getComment(), tag.getContent().getName())); + tableReport.addRow(row); + + // check if the tag is an image that we should later make a thumbnail for + checkIfTagHasImage(tag); + } + + // The the modules blackboard artifact tags reporting is ended. + progressPanel.increment(); + tableReport.endTable(); + tableReport.endDataType(); + } + + /** + * Test if the user requested that this tag be reported on + * + * @param tagName + * + * @return true if it should be reported on + */ + private boolean passesTagNamesFilter(String tagName) { + return tagNamesFilter.isEmpty() || tagNamesFilter.contains(tagName); + } + + /** + * Make a report for the files that were previously found to be images. + */ + private void makeThumbnailTable() { + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.createdThumb.text")); + + if (tableReport instanceof ReportHTML) { + ReportHTML htmlModule = (ReportHTML) tableReport; + htmlModule.startDataType( + NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.name"), + NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.desc")); + List emptyHeaders = new ArrayList<>(); + for (int i = 0; i < ReportHTML.THUMBNAIL_COLUMNS; i++) { + emptyHeaders.add(""); + } + htmlModule.startTable(emptyHeaders); + + htmlModule.addThumbnailRows(images); + + htmlModule.endTable(); + htmlModule.endDataType(); + } + + } + + /** + * Analyze artifact associated with tag and add to internal list if it is + * associated with an image. + * + * @param artifactTag + */ + private void checkIfTagHasImage(BlackboardArtifactTag artifactTag) { + AbstractFile file; + try { + file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(artifactTag.getArtifact().getObjectID()); + } catch (TskCoreException ex) { + errorList.add( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.errGetContentFromBBArtifact")); + logger.log(Level.WARNING, "Error while getting content from a blackboard artifact to report on.", ex); //NON-NLS + return; + } + + if (file != null) { + checkIfFileIsImage(file); + } + } + + /** + * Analyze file that tag is associated with and determine if it is an image + * and should have a thumbnail reported for it. Images are added to internal + * list. + * + * @param contentTag + */ + private void checkIfTagHasImage(ContentTag contentTag) { + Content c = contentTag.getContent(); + if (c instanceof AbstractFile == false) { + return; + } + checkIfFileIsImage((AbstractFile) c); + } + + /** + * If file is an image file, add it to the internal 'images' list. + * + * @param file + */ + private void checkIfFileIsImage(AbstractFile file) { + + if (file.isDir() + || file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS + || file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) { + return; + } + + if (ImageUtils.thumbnailSupported(file)) { + images.add(file); + } + } + + /** + * Converts a collection of strings into a single string of comma-separated + * items + * + * @param items A collection of strings + * + * @return A string of comma-separated items + */ + private String makeCommaSeparatedList(Collection items) { + String list = ""; + for (Iterator iterator = items.iterator(); iterator.hasNext();) { + list += iterator.next() + (iterator.hasNext() ? ", " : ""); + } + return list; + } + + /** + * Write the keyword hits to the provided TableReportModules. + * + * @param tableModule module to report on + */ + @SuppressWarnings("deprecation") + private void writeKeywordHits(TableReportModule tableModule, String comment, HashSet tagNamesFilter) { + + // Query for keyword lists-only so that we can tell modules what lists + // will exist for their index. + // @@@ There is a bug in here. We should use the tags in the below code + // so that we only report the lists that we will later provide with real + // hits. If no keyord hits are tagged, then we make the page for nothing. + String orderByClause; + if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { + orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS + } else { + orderByClause = "ORDER BY list ASC"; //NON-NLS + } + String keywordListQuery + = "SELECT att.value_text AS list " + + //NON-NLS + "FROM blackboard_attributes AS att, blackboard_artifacts AS art " + + //NON-NLS + "WHERE att.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " + + //NON-NLS + "AND art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + " " + + //NON-NLS + "AND att.artifact_id = art.artifact_id " + + //NON-NLS + "GROUP BY list " + orderByClause; //NON-NLS + + try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(keywordListQuery)) { + ResultSet listsRs = dbQuery.getResultSet(); + List lists = new ArrayList<>(); + while (listsRs.next()) { + String list = listsRs.getString("list"); //NON-NLS + if (list.isEmpty()) { + list = NbBundle.getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs"); + } + lists.add(list); + } + + // Make keyword data type and give them set index + tableModule.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), comment); + tableModule.addSetIndex(lists); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName())); + } catch (TskCoreException | SQLException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryKWLists")); + logger.log(Level.SEVERE, "Failed to query keyword lists: ", ex); //NON-NLS + return; + } + + if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { + orderByClause = "ORDER BY convert_to(att3.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(att1.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(f.parent_path, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(f.name, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(att2.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS + } else { + orderByClause = "ORDER BY list ASC, keyword ASC, parent_path ASC, name ASC, preview ASC"; //NON-NLS + } + // Query for keywords, grouped by list + String keywordsQuery + = "SELECT art.artifact_id, art.obj_id, att1.value_text AS keyword, att2.value_text AS preview, att3.value_text AS list, f.name AS name, f.parent_path AS parent_path " + + //NON-NLS + "FROM blackboard_artifacts AS art, blackboard_attributes AS att1, blackboard_attributes AS att2, blackboard_attributes AS att3, tsk_files AS f " + + //NON-NLS + "WHERE (att1.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (att2.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (att3.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (f.obj_id = art.obj_id) " + + //NON-NLS + "AND (att1.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID() + ") " + + //NON-NLS + "AND (att2.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW.getTypeID() + ") " + + //NON-NLS + "AND (att3.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " + + //NON-NLS + "AND (art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ") " + + //NON-NLS + orderByClause; //NON-NLS + + try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(keywordsQuery)) { + ResultSet resultSet = dbQuery.getResultSet(); + + String currentKeyword = ""; + String currentList = ""; + while (resultSet.next()) { + // Check to see if all the TableReportModules have been canceled + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + break; + } + + // Get any tags that associated with this artifact and apply the tag filter. + HashSet uniqueTagNames = getUniqueTagNames(resultSet.getLong("artifact_id")); //NON-NLS + if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { + continue; + } + String tagsList = makeCommaSeparatedList(uniqueTagNames); + + Long objId = resultSet.getLong("obj_id"); //NON-NLS + String keyword = resultSet.getString("keyword"); //NON-NLS + String preview = resultSet.getString("preview"); //NON-NLS + String list = resultSet.getString("list"); //NON-NLS + String uniquePath = ""; + + try { + AbstractFile f = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId); + if (f != null) { + uniquePath = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId).getUniquePath(); + } + } catch (TskCoreException ex) { + errorList.add( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileByID")); + logger.log(Level.WARNING, "Failed to get Abstract File by ID.", ex); //NON-NLS + } + + // If the lists aren't the same, we've started a new list + if ((!list.equals(currentList) && !list.isEmpty()) || (list.isEmpty() && !currentList.equals( + NbBundle.getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs")))) { + if (!currentList.isEmpty()) { + tableModule.endTable(); + tableModule.endSet(); + } + currentList = list.isEmpty() ? NbBundle + .getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs") : list; + currentKeyword = ""; // reset the current keyword because it's a new list + tableModule.startSet(currentList); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), currentList)); + } + if (!keyword.equals(currentKeyword)) { + if (!currentKeyword.equals("")) { + tableModule.endTable(); + } + currentKeyword = keyword; + tableModule.addSetElement(currentKeyword); + List columnHeaderNames = new ArrayList<>(); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); + tableModule.startTable(columnHeaderNames); + } + + String previewreplace = EscapeUtil.escapeHtml(preview); + tableModule.addRow(Arrays.asList(new String[]{previewreplace.replaceAll(" tagNamesFilter) { + String orderByClause; + if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { + orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS + } else { + orderByClause = "ORDER BY att.value_text ASC"; //NON-NLS + } + String hashsetsQuery + = "SELECT att.value_text AS list " + + //NON-NLS + "FROM blackboard_attributes AS att, blackboard_artifacts AS art " + + //NON-NLS + "WHERE att.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " + + //NON-NLS + "AND art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + " " + + //NON-NLS + "AND att.artifact_id = art.artifact_id " + + //NON-NLS + "GROUP BY list " + orderByClause; //NON-NLS + + try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(hashsetsQuery)) { + // Query for hashsets + ResultSet listsRs = dbQuery.getResultSet(); + List lists = new ArrayList<>(); + while (listsRs.next()) { + lists.add(listsRs.getString("list")); //NON-NLS + } + + tableModule.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), comment); + tableModule.addSetIndex(lists); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName())); + } catch (TskCoreException | SQLException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryHashsetLists")); + logger.log(Level.SEVERE, "Failed to query hashset lists: ", ex); //NON-NLS + return; + } + + if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { + orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(f.parent_path, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "convert_to(f.name, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + + "size ASC NULLS FIRST"; //NON-NLS + } else { + orderByClause = "ORDER BY att.value_text ASC, f.parent_path ASC, f.name ASC, size ASC"; //NON-NLS + } + String hashsetHitsQuery + = "SELECT art.artifact_id, art.obj_id, att.value_text AS setname, f.name AS name, f.size AS size, f.parent_path AS parent_path " + + //NON-NLS + "FROM blackboard_artifacts AS art, blackboard_attributes AS att, tsk_files AS f " + + //NON-NLS + "WHERE (att.artifact_id = art.artifact_id) " + + //NON-NLS + "AND (f.obj_id = art.obj_id) " + + //NON-NLS + "AND (att.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " + + //NON-NLS + "AND (art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ") " + + //NON-NLS + orderByClause; //NON-NLS + + try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(hashsetHitsQuery)) { + // Query for hashset hits + ResultSet resultSet = dbQuery.getResultSet(); + String currentSet = ""; + while (resultSet.next()) { + // Check to see if all the TableReportModules have been canceled + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + break; + } + + // Get any tags that associated with this artifact and apply the tag filter. + HashSet uniqueTagNames = getUniqueTagNames(resultSet.getLong("artifact_id")); //NON-NLS + if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { + continue; + } + String tagsList = makeCommaSeparatedList(uniqueTagNames); + + Long objId = resultSet.getLong("obj_id"); //NON-NLS + String set = resultSet.getString("setname"); //NON-NLS + String size = resultSet.getString("size"); //NON-NLS + String uniquePath = ""; + + try { + AbstractFile f = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId); + if (f != null) { + uniquePath = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId).getUniquePath(); + } + } catch (TskCoreException ex) { + errorList.add( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileFromID")); + logger.log(Level.WARNING, "Failed to get Abstract File from ID.", ex); //NON-NLS + return; + } + + // If the sets aren't the same, we've started a new set + if (!set.equals(currentSet)) { + if (!currentSet.isEmpty()) { + tableModule.endTable(); + tableModule.endSet(); + } + currentSet = set; + tableModule.startSet(currentSet); + List columnHeaderNames = new ArrayList<>(); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size")); + columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); + tableModule.startTable(columnHeaderNames); + progressPanel.updateStatusLabel( + NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), currentSet)); + } + + // Add a row for this hit to every module + tableModule.addRow(Arrays.asList(new String[]{uniquePath, size, tagsList})); + } + + // Finish the current data type + progressPanel.increment(); + tableModule.endDataType(); + } catch (TskCoreException | SQLException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryHashsetHits")); + logger.log(Level.SEVERE, "Failed to query hashsets hits: ", ex); //NON-NLS + } + } + + /** + * @return the errorList + */ + List getErrorList() { + return errorList; + } + + /** + * Container class that holds data about an Artifact to eliminate duplicate + * calls to the Sleuthkit database. + */ + private class ArtifactData implements Comparable { + + private BlackboardArtifact artifact; + private List attributes; + private HashSet tags; + private List rowData = null; + private Content content; + + ArtifactData(BlackboardArtifact artifact, List attrs, HashSet tags) { + this.artifact = artifact; + this.attributes = attrs; + this.tags = tags; + try { + this.content = Case.getCurrentCase().getSleuthkitCase().getContentById(artifact.getObjectID()); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Could not get content from database"); + } + } + + public BlackboardArtifact getArtifact() { + return artifact; + } + + public List getAttributes() { + return attributes; + } + + public HashSet getTags() { + return tags; + } + + public long getArtifactID() { + return artifact.getArtifactID(); + } + + public long getObjectID() { + return artifact.getObjectID(); + } + + /** + * @return the content + */ + public Content getContent() { + return content; + } + + /** + * Compares ArtifactData objects by the first attribute they have in + * 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 + * the same type. + */ + @Override + public int compareTo(ArtifactData otherArtifactData) { + List thisRow = getRow(); + List otherRow = otherArtifactData.getRow(); + for (int i = 0; i < thisRow.size(); i++) { + int compare = thisRow.get(i).compareTo(otherRow.get(i)); + if (compare != 0) { + return compare; + } + } + return ((Long) this.getArtifactID()).compareTo(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(); + // 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( + NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.coreExceptionWhileGenRptRow")); + logger.log(Level.WARNING, "Core exception while generating row data for artifact report.", ex); //NON-NLS + rowData = Collections.emptyList(); + } + } + return rowData; + } + + /** + * Get a list of Strings with all the row values for the Artifact in the + * correct order to be written to the report. + * + * @return List row values. Values could be null if attribute is + * not defined in artifact + * + * @throws TskCoreException + */ + private List getOrderedRowDataAsStrings() throws TskCoreException { + + List orderedRowData = new ArrayList<>(); + if (BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() == getArtifact().getArtifactTypeID()) { + if (content != null && content instanceof AbstractFile) { + AbstractFile file = (AbstractFile) content; + 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()); + } 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 (BlackboardArtifact.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(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME))) { + attributeDataArray[0] = attr.getDisplayString(); + } else if (attr.getAttributeType().equals(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY))) { + attributeDataArray[1] = attr.getDisplayString(); + } else if (attr.getAttributeType().equals(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))) { + String pathToShow = attr.getDisplayString(); + if (pathToShow.isEmpty()) { + pathToShow = getFileUniquePath(content); + } + attributeDataArray[2] = pathToShow; + } + } + orderedRowData.addAll(Arrays.asList(attributeDataArray)); + orderedRowData.add(makeCommaSeparatedList(getTags())); + + } else if (columnHeaderMap.containsKey(this.artifact.getArtifactTypeID())) { + + for (Column currColumn : columnHeaderMap.get(this.artifact.getArtifactTypeID())) { + String cellData = currColumn.getCellData(this); + orderedRowData.add(cellData); + } + } + + return orderedRowData; + } + + } + + /** + * 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 tagNamesFilter The tag names that should be included. + * + * @return a list of the filtered tags. + */ + private List getFilteredArtifacts(BlackboardArtifact.Type type, HashSet tagNamesFilter) { + List artifacts = new ArrayList<>(); + try { + for (BlackboardArtifact artifact : Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifacts(type.getTypeID())) { + List tags = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact); + HashSet uniqueTagNames = new HashSet<>(); + for (BlackboardArtifactTag tag : tags) { + uniqueTagNames.add(tag.getName().getDisplayName()); + } + if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { + continue; + } + try { + artifacts.add(new ArtifactData(artifact, Case.getCurrentCase().getSleuthkitCase().getBlackboardAttributes(artifact), uniqueTagNames)); + } catch (TskCoreException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBAttribs")); + logger.log(Level.SEVERE, "Failed to get Blackboard Attributes when generating report.", ex); //NON-NLS + } + } + } catch (TskCoreException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBArtifacts")); + logger.log(Level.SEVERE, "Failed to get Blackboard Artifacts when generating report.", ex); //NON-NLS + } + return artifacts; + } + + private Boolean failsTagFilter(HashSet tagNames, HashSet tagsNamesFilter) { + if (null == tagsNamesFilter || tagsNamesFilter.isEmpty()) { + return false; + } + + HashSet filteredTagNames = new HashSet<>(tagNames); + filteredTagNames.retainAll(tagsNamesFilter); + return filteredTagNames.isEmpty(); + } + + /** + * For a given artifact type ID, return the list of the columns that we are + * reporting on. + * + * @param artifactTypeId artifact type ID + * @param attributeTypeSet The set of attributeTypeSet available for this + * artifact type + * + * @return List row titles + */ + private List getArtifactTableColumns(int artifactTypeId, Set attributeTypeSet) { + ArrayList columns = new ArrayList<>(); + + // Long switch statement to retain ordering of attribute types that are + // attached to pre-defined artifact types. + if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.title"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateCreated"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.value"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.referrer"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REFERRER))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.title"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.urlDomainDecoded"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL_DECODED))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dest"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.sourceUrl"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.path"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.progName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.instDateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() == artifactTypeId) { + columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview"))); + + } else if (BlackboardArtifact.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 (BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devMake"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MAKE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devModel"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MODEL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceId"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.text"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.domain"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.progName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTaken"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devManufacturer"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MAKE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devModel"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MODEL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumber"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumHome"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_HOME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumOffice"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_OFFICE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumMobile"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_MOBILE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.email"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.msgType"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.direction"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.readStatus"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_READ_STATUS))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromPhoneNum"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromEmail"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toPhoneNum"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toEmail"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_TO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.subject"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.text"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromPhoneNum"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toPhoneNum"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.direction"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_CALENDAR_ENTRY.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.calendarEntryType"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CALENDAR_ENTRY_TYPE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.description"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.startDateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.endDateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.location"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_SPEED_DIAL_ENTRY.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.shortCut"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SHORTCUT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME_PERSON))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumber"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceAddress"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.category"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userId"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.password"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PASSWORD))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.appName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.appPath"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.description"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.replytoAddress"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_REPLYTO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.mailServer"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SERVER_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + } else if (BlackboardArtifact.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 (BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_INFO.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.processorArchitecture.text"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROCESSOR_ARCHITECTURE))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.osName.text"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.osInstallDate.text"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailTo"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_TO))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailFrom"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSubject"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskDateTimeSent"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskDateTimeRcvd"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_RCVD))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskPath"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailCc"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CC))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailBcc"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_BCC))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskMsgId"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MSG_ID))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSetName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskInterestingFilesCategory"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskPath"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskGpsRouteCategory"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitudeEnd"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitudeEnd"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitudeStart"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitudeStart"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.location"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSetName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.associatedArtifact"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.associatedArtifact"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.count"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COUNT))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_ACCOUNT.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userName"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userId"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID))); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_REMOTE_DRIVE.getTypeID() == artifactTypeId) { + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.localPath"), + new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCAL_PATH))); + + columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.remotePath"), + new BlackboardAttribute.Type(BlackboardAttribute.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"))); + + // Short circuits to guarantee that the attribute types aren't added + // twice. + return columns; + } + // 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 == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALENDAR_ENTRY.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_SPEED_DIAL_ENTRY.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT.getTypeID() + || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() + || artifactTypeId == BlackboardArtifact.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; + } + + /** + * Given a tsk_file's obj_id, return the unique path of that file. + * + * @param objId tsk_file obj_id + * + * @return String unique path + */ + private String getFileUniquePath(Content content) { + try { + if (content != null) { + return content.getUniquePath(); + } else { + return ""; + } + } catch (TskCoreException ex) { + errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileByID")); + logger.log(Level.WARNING, "Failed to get Abstract File by ID.", ex); //NON-NLS + } + return ""; + + } + + /** + * Get any tags associated with an artifact + * + * @param artifactId + * + * @return hash set of tag display names + * + * @throws SQLException + */ + @SuppressWarnings("deprecation") + private HashSet getUniqueTagNames(long artifactId) throws TskCoreException { + HashSet uniqueTagNames = new HashSet<>(); + + String query = "SELECT display_name, artifact_id FROM tag_names AS tn, blackboard_artifact_tags AS bat " + + //NON-NLS + "WHERE tn.tag_name_id = bat.tag_name_id AND bat.artifact_id = " + artifactId; //NON-NLS + + try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(query)) { + ResultSet tagNameRows = dbQuery.getResultSet(); + while (tagNameRows.next()) { + uniqueTagNames.add(tagNameRows.getString("display_name")); //NON-NLS + } + } catch (TskCoreException | SQLException ex) { + throw new TskCoreException("Error getting tag names for artifact: ", ex); + } + + return uniqueTagNames; + + } + + private interface Column { + + String getColumnHeader(); + + String getCellData(ArtifactData artData); + + Set removeTypeFromSet(Set types); + } + + private class AttributeColumn implements Column { + + private final String columnHeader; + private final 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)) { + if (attribute.getAttributeType().getValueType() != BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) { + return attribute.getDisplayString(); + } else { + return ContentUtils.getStringTime(attribute.getValueLong(), artData.getContent()); + } + } + } + return ""; + } + + @Override + public Set removeTypeFromSet(Set types) { + types.remove(this.attributeType); + return types; + } + } + + private class SourceFileColumn implements Column { + + private final String columnHeader; + + SourceFileColumn(String columnHeader) { + this.columnHeader = columnHeader; + } + + @Override + public String getColumnHeader() { + return this.columnHeader; + } + + @Override + public String getCellData(ArtifactData artData) { + return getFileUniquePath(artData.getContent()); + /*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 final 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 final 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; + } + } +} From 11cd0fc998be3eb4d47020eae6340ce2a0470e92 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 23 May 2016 12:51:23 -0400 Subject: [PATCH 08/39] begin work on list view scroll/navigation controlls --- .../timeline/images/resultset_first.png | Bin 0 -> 522 bytes .../timeline/images/resultset_last.png | Bin 0 -> 524 bytes .../timeline/images/resultset_next.png | Bin 0 -> 395 bytes .../timeline/images/resultset_previous.png | Bin 0 -> 389 bytes .../timeline/ui/listvew/ListTimeline.fxml | 50 +++++++++++++++++- .../timeline/ui/listvew/ListTimeline.java | 49 +++++++++++++++++ .../timeline/ui/listvew/ListViewPane.java | 9 +++- 7 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/timeline/images/resultset_first.png create mode 100644 Core/src/org/sleuthkit/autopsy/timeline/images/resultset_last.png create mode 100644 Core/src/org/sleuthkit/autopsy/timeline/images/resultset_next.png create mode 100644 Core/src/org/sleuthkit/autopsy/timeline/images/resultset_previous.png diff --git a/Core/src/org/sleuthkit/autopsy/timeline/images/resultset_first.png b/Core/src/org/sleuthkit/autopsy/timeline/images/resultset_first.png new file mode 100644 index 0000000000000000000000000000000000000000..b03eaf8b5416fa6878165d95116e73003f8445f5 GIT binary patch literal 522 zcmV+l0`>igP)ufs8f5Kzx*fI63}@)AAFXgQp7K#X5)&2^7g z_9O9^7^ARqyc%qAP{1M7?|}io8xW>dotf=a%%ZSXBBI&Rf<-t`#(~H!2g~*8&15{# zVXjXMwHZYVJ6lk!gb6?r$g;SuO>QI;yeQ51#0H@Z6sk_ajqECPZEqLq!PMf5MQ5gS1i(Owi(ut_CY*w|Psf-Iy6=08Y` zHnsuDs6h)+OwcBqopImX_v1c`5LkrSCWWWFUvW71z%eN$cB714YVYtd`}$X<%JbQ) zM;;CHJDu;#-swg0iul07{S&4s!M>4O+`c|6_tW_i^y+I%|aPsIlEx5K=^ki~8LwqDy-)t}thx1D9 zB6|#ECQ%2a60OQQ<{6-)5|okv)6E>1Xpv+@iIv@MJ8v15 zR{N~1_2z$e&R$WgNhIQelIl1rK}5XruIN#GDZA_4bJqcqID*^mXXFcgt1K5iK7HPL zwLW*@#tu()#Cyd@CHc^75Ul6pYT4PCpSeBE)hh4bY>IO8de(|Ml<%@O-40!dwX61{2C5s-llVw2V@@N0oo_PPieZ!0Y2~+R( zk!(QTf=B;X9DnzJ@u9c>OP4(U@7{849!UlyO@H`*;lVfmCvAW6f9CF&{}ZR*{jXDW zb_vl21ozzrYJBy-Vb$aRjjJF3@7nm}zjw#A|58cE9uZ}LbIY~=6ShA8U$XeY|MDdd zfQCH!?_7WRzhvaG%|sbsT7Kz&`}!yUix%Do#>T_{_Ei`DO9UTSBkH=Hg(w4*^UnUS zTk-IJ<+2C=ZObqG7Z2FGlB7VCN;>(!bn*TFHYMl(i+Sx`L~=ArL>~EXU3lidsO!!J pWF;gqzXSh89JkLNxXeT<1_12n>%V}Y6R`jQ002ovPDHLkV1iLCz99er literal 0 HcmV?d00001 diff --git a/Core/src/org/sleuthkit/autopsy/timeline/images/resultset_previous.png b/Core/src/org/sleuthkit/autopsy/timeline/images/resultset_previous.png new file mode 100644 index 0000000000000000000000000000000000000000..18f9cc10948f025fde708328fa704b520161e5f6 GIT binary patch literal 389 zcmV;00eb$4P)K{b{Xc8(tN&i@ zH%T)fYQpV#rAr?FpSkE_eXe+_wJd|K3f{{%aMTC(eL? z&YO?2=RWv9b;pbUjjJF3FIss2fAiYM|D{t;5@!?n%vQ}6um-u(1``H~0!(`ViJ zU$yMvf616*#2KJfaGFIu@9Y|n)@%Q3RzCcnHskjH!iD$#iw7MbEf6JRj;ypTzwkeA z{@wqXv+w*Db>B;RG>UocU1Xkp@_*9QTmMBIcK# + + + + + - + - diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java index 77fc831b29..10bbeca64f 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.timeline.ui.listvew; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -29,7 +30,10 @@ import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; import javafx.collections.ObservableList; +import javafx.event.ActionEvent; import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; import javafx.scene.control.ContextMenu; import javafx.scene.control.Label; import javafx.scene.control.MenuItem; @@ -68,6 +72,21 @@ class ListTimeline extends BorderPane { */ private static final Callback, ObservableValue> CELL_VALUE_FACTORY = param -> new SimpleObjectProperty<>(param.getValue()); + @FXML + private ComboBox scrollInrementComboBox; + + @FXML + private Button firstButton; + + @FXML + private Button previousButton; + + @FXML + private Button nextButton; + + @FXML + private Button lastButton; + @FXML private Label eventCountLabel; @FXML @@ -111,6 +130,25 @@ class ListTimeline extends BorderPane { assert subTypeColumn != null : "fx:id=\"subTypeColumn\" was not injected: check your FXML file 'ListViewPane.fxml'."; assert knownColumn != null : "fx:id=\"knownColumn\" was not injected: check your FXML file 'ListViewPane.fxml'."; + scrollInrementComboBox.getItems().setAll( + ChronoUnit.YEARS, + ChronoUnit.MONTHS, + ChronoUnit.DAYS, + ChronoUnit.HOURS, + ChronoUnit.MINUTES, + ChronoUnit.SECONDS, + ChronoUnit.MILLIS + ); + scrollInrementComboBox.getSelectionModel().select(ChronoUnit.YEARS); + + firstButton.setOnAction((ActionEvent event) -> table.scrollTo(0)); + previousButton.setOnAction((ActionEvent event) -> { + table.scrollTo(0); + + }); +// nextButton.setOnAction((ActionEvent event) -> table.scrollTo(0)); + lastButton.setOnAction((ActionEvent event) -> table.scrollTo(table.getItems().size())); + //override default row with one that provides context menu.S table.setRowFactory(tableView -> new EventRow()); @@ -149,6 +187,10 @@ class ListTimeline extends BorderPane { table.getItems().clear(); } + Long getSelectedEventID() { + return table.getSelectionModel().getSelectedItem(); + } + /** * Set the Collection of events (by ID) to show in the table. * @@ -169,6 +211,13 @@ class ListTimeline extends BorderPane { return table.getSelectionModel().getSelectedItems(); } + void selectEventID(Long selectedEventID) { + //restore selection. + table.scrollTo(selectedEventID); + table.getSelectionModel().select(selectedEventID); + table.requestFocus(); + } + /** * TableCell to show the icon for the type of an event. */ diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java index 23278f0d86..09b129ed78 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java @@ -73,7 +73,7 @@ public class ListViewPane extends AbstractTimeLineView { @Override protected void clearData() { - listChart.clear(); + } private static class ListViewSettingsPane extends Parent { @@ -96,13 +96,18 @@ public class ListViewPane extends AbstractTimeLineView { } FilteredEventsModel eventsModel = getEventsModel(); + Long selectedEventID = listChart.getSelectedEventID(); + //clear the chart and set the horixontal axis resetView(eventsModel.getTimeRange()); updateMessage("Querying db for events"); //get the event stripes to be displayed List eventIDs = eventsModel.getEventIDs(); - Platform.runLater(() -> listChart.setEventIDs(eventIDs)); + Platform.runLater(() -> { + listChart.setEventIDs(eventIDs); + listChart.selectEventID(selectedEventID); + }); updateMessage("updating ui"); return eventIDs.isEmpty() == false; From 0b010732327bfef7c2056a17d51e7460888777af Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Wed, 25 May 2016 15:05:03 -0400 Subject: [PATCH 09/39] Made search button disable based upon whether a filter is enabled. --- .../filesearch/AbstractFileSearchFilter.java | 6 ++++ .../autopsy/filesearch/DateSearchFilter.java | 5 ++++ .../autopsy/filesearch/DateSearchPanel.java | 14 ++++++++++ .../autopsy/filesearch/FileSearchFilter.java | 5 +++- .../autopsy/filesearch/FileSearchPanel.java | 28 +++++++++++++------ .../filesearch/KnownStatusSearchFilter.java | 1 - .../filesearch/KnownStatusSearchPanel.java | 19 +++++++++++-- .../autopsy/filesearch/MimeTypeFilter.java | 2 ++ .../autopsy/filesearch/MimeTypePanel.form | 2 +- .../autopsy/filesearch/MimeTypePanel.java | 23 +++++++++++++++ .../autopsy/filesearch/NameSearchPanel.java | 19 +++++++++++-- .../autopsy/filesearch/SizeSearchPanel.java | 17 ++++++++++- 12 files changed, 125 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/AbstractFileSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/AbstractFileSearchFilter.java index 0d59301eea..67f65be80b 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/AbstractFileSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/AbstractFileSearchFilter.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.filesearch; +import java.beans.PropertyChangeListener; import javax.swing.JComponent; /** @@ -39,4 +40,9 @@ abstract class AbstractFileSearchFilter implements FileSea public T getComponent() { return this.component; } + + @Override + public void addPropertyChangeListener(PropertyChangeListener listener) { + this.getComponent().addPropertyChangeListener(listener); + } } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java index be8a799556..be42035087 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java @@ -205,6 +205,11 @@ class DateSearchFilter extends AbstractFileSearchFilter { getComponent().addActionListener(l); } + @Override + public void addPropertyChangeListener(PropertyChangeListener listener) { + getComponent().addPropertyChangeListener(listener); + } + /** * Inner class to put the separator inside the combo box. */ diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java index ea3642a65d..a852fddfa3 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java @@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.text.DateFormat; import java.text.ParseException; import java.util.Date; @@ -37,6 +39,7 @@ class DateSearchPanel extends javax.swing.JPanel { DateFormat dateFormat; List timeZones; + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); DateSearchPanel(DateFormat dateFormat, List timeZones) { this.dateFormat = dateFormat; @@ -133,6 +136,16 @@ class DateSearchPanel extends javax.swing.JPanel { this.changedCheckBox.setEnabled(enable); this.createdCheckBox.setEnabled(enable); } + + @Override + public void addPropertyChangeListener(PropertyChangeListener pcl) { + pcs.addPropertyChangeListener(pcl); + } + + @Override + public void removePropertyChangeListener(PropertyChangeListener pcl) { + pcs.removePropertyChangeListener(pcl); + } /** * This method is called from within the constructor to initialize the form. @@ -349,6 +362,7 @@ class DateSearchPanel extends javax.swing.JPanel { private void dateCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dateCheckBoxActionPerformed this.setComponentsEnabled(); + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); }//GEN-LAST:event_dateCheckBoxActionPerformed /** diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java index 878c500c0b..d4b39716d7 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java @@ -19,12 +19,13 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionListener; +import java.beans.PropertyChangeListener; import javax.swing.JComponent; /** * Provides a filter and the panel to display it to the FileSearchTopComponent */ -interface FileSearchFilter { + interface FileSearchFilter { /** * Gets the panel to put in the File Search pane. @@ -55,6 +56,8 @@ interface FileSearchFilter { * Add an action listener to the fields of this panel */ void addActionListener(ActionListener l); + + void addPropertyChangeListener(PropertyChangeListener listener); /** * Thrown if a filter's inputs are invalid diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java index e796589d22..de01ecd901 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java @@ -17,38 +17,35 @@ * limitations under the License. */ -/* + /* * FileSearchPanel.java * * Created on Mar 5, 2012, 1:51:50 PM */ package org.sleuthkit.autopsy.filesearch; -import java.awt.BorderLayout; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.logging.Level; - -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.coreutils.Logger; -import javax.swing.BoxLayout; -import javax.swing.JButton; import javax.swing.JLabel; -import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; +import org.openide.util.NbBundle; import org.openide.windows.TopComponent; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.corecomponents.TableFilterNode; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException; import org.sleuthkit.datamodel.AbstractFile; @@ -64,6 +61,10 @@ class FileSearchPanel extends javax.swing.JPanel { private static int resultWindowCount = 0; //keep track of result windows so they get unique names private static final String EMPTY_WHERE_CLAUSE = NbBundle.getMessage(DateSearchFilter.class, "FileSearchPanel.emptyWhereClause.text"); + enum EVENT { + CHECKED + } + /** * Creates new form FileSearchPanel */ @@ -100,12 +101,22 @@ class FileSearchPanel extends javax.swing.JPanel { filterPanel.add(fa); } + for (FileSearchFilter filter : this.getFilters()) { + filter.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + searchButton.setEnabled(anyFiltersEnabled()); + } + }); + } + addListenerToAll(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { search(); } }); + searchButton.setEnabled(anyFiltersEnabled()); } /** @@ -290,6 +301,7 @@ class FileSearchPanel extends javax.swing.JPanel { .addContainerGap()) ); }// //GEN-END:initComponents + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel filterPanel; private javax.swing.JButton searchButton; diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java index bd9776f61d..8bd74d02fa 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionListener; - import org.openide.util.NbBundle; import org.sleuthkit.datamodel.TskData.FileKnown; diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java index 291ced32e7..89e12481b1 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java @@ -17,13 +17,15 @@ * limitations under the License. */ -/* + /* * KnownStatusSearchPanel.java * * Created on Oct 19, 2011, 11:45:44 AM */ package org.sleuthkit.autopsy.filesearch; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import javax.swing.JCheckBox; /** @@ -32,6 +34,8 @@ import javax.swing.JCheckBox; */ class KnownStatusSearchPanel extends javax.swing.JPanel { + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + /** * Creates new form KnownStatusSearchPanel */ @@ -55,7 +59,7 @@ class KnownStatusSearchPanel extends javax.swing.JPanel { JCheckBox getUnknownOptionCheckBox() { return unknownOptionCheckBox; } - + private void setComponentsEnabled() { boolean enabled = this.knownCheckBox.isSelected(); this.unknownOptionCheckBox.setEnabled(enabled); @@ -63,6 +67,16 @@ class KnownStatusSearchPanel extends javax.swing.JPanel { this.knownBadOptionCheckBox.setEnabled(enabled); } + @Override + public void addPropertyChangeListener(PropertyChangeListener pcl) { + pcs.addPropertyChangeListener(pcl); + } + + @Override + public void removePropertyChangeListener(PropertyChangeListener pcl) { + pcs.removePropertyChangeListener(pcl); + } + /** * 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 @@ -132,6 +146,7 @@ class KnownStatusSearchPanel extends javax.swing.JPanel { private void knownCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownCheckBoxActionPerformed setComponentsEnabled(); + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); }//GEN-LAST:event_knownCheckBoxActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypeFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypeFilter.java index b119566299..72cb4e7012 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypeFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypeFilter.java @@ -40,5 +40,7 @@ class MimeTypeFilter extends AbstractFileSearchFilter { @Override public void addActionListener(ActionListener l) { } + + } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypePanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypePanel.form index a8c7fa65f9..7eb2d436df 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypePanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypePanel.form @@ -31,7 +31,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypePanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypePanel.java index b4172354a4..e14e5e0dc4 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypePanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/MimeTypePanel.java @@ -5,12 +5,16 @@ */ package org.sleuthkit.autopsy.filesearch; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.logging.Level; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; import org.apache.tika.mime.MediaType; import org.apache.tika.mime.MimeTypes; import org.sleuthkit.autopsy.coreutils.Logger; @@ -25,6 +29,7 @@ public class MimeTypePanel extends javax.swing.JPanel { private static final SortedSet mediaTypes = MimeTypes.getDefaultMimeTypes().getMediaTypeRegistry().getTypes(); private static final Logger logger = Logger.getLogger(MimeTypePanel.class.getName()); private static final long serialVersionUID = 1L; + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); /** * Creates new form MimeTypePanel @@ -32,6 +37,12 @@ public class MimeTypePanel extends javax.swing.JPanel { public MimeTypePanel() { initComponents(); setComponentsEnabled(); + this.mimeTypeList.addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + }); } private String[] getMimeTypeArray() { @@ -75,6 +86,16 @@ public class MimeTypePanel extends javax.swing.JPanel { this.mimeTypeList.setEnabled(enabled); this.jLabel1.setEnabled(enabled); } + + @Override + public void addPropertyChangeListener(PropertyChangeListener pcl) { + pcs.addPropertyChangeListener(pcl); + } + + @Override + public void removePropertyChangeListener(PropertyChangeListener pcl) { + pcs.removePropertyChangeListener(pcl); + } /** * This method is called from within the constructor to initialize the form. @@ -141,6 +162,8 @@ public class MimeTypePanel extends javax.swing.JPanel { private void mimeTypeCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mimeTypeCheckBoxActionPerformed setComponentsEnabled(); + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + this.mimeTypeList.setSelectedIndices(new int[0]); }//GEN-LAST:event_mimeTypeCheckBoxActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java index 1ae2842947..dd7a3d008f 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java @@ -17,7 +17,7 @@ * limitations under the License. */ -/* + /* * NameSearchPanel.java * * Created on Oct 19, 2011, 11:58:53 AM @@ -26,6 +26,8 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import javax.swing.JCheckBox; import javax.swing.JMenuItem; import javax.swing.JTextField; @@ -36,6 +38,8 @@ import javax.swing.JTextField; */ class NameSearchPanel extends javax.swing.JPanel { + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + /** * Creates new form NameSearchPanel */ @@ -77,12 +81,22 @@ class NameSearchPanel extends javax.swing.JPanel { JTextField getSearchTextField() { return searchTextField; } - + void setComponentsEnabled() { boolean enabled = nameCheckBox.isSelected(); this.searchTextField.setEnabled(enabled); this.noteNameLabel.setEnabled(enabled); } + + @Override + public void addPropertyChangeListener(PropertyChangeListener pcl) { + pcs.addPropertyChangeListener(pcl); + } + + @Override + public void removePropertyChangeListener(PropertyChangeListener pcl) { + pcs.removePropertyChangeListener(pcl); + } /** * This method is called from within the constructor to initialize the form. @@ -168,6 +182,7 @@ class NameSearchPanel extends javax.swing.JPanel { private void nameCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nameCheckBoxActionPerformed setComponentsEnabled(); + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); }//GEN-LAST:event_nameCheckBoxActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java index 4a0bc91d5e..4bde4eb5e7 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java @@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.text.NumberFormat; import javax.swing.JCheckBox; import javax.swing.JComboBox; @@ -32,6 +34,8 @@ import javax.swing.JMenuItem; */ class SizeSearchPanel extends javax.swing.JPanel { + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + /** * Creates new form SizeSearchPanel */ @@ -81,13 +85,23 @@ class SizeSearchPanel extends javax.swing.JPanel { JComboBox getSizeUnitComboBox() { return sizeUnitComboBox; } - + void setComponentsEnabled() { boolean enabled = this.sizeCheckBox.isSelected(); this.sizeCompareComboBox.setEnabled(enabled); this.sizeUnitComboBox.setEnabled(enabled); this.sizeTextField.setEnabled(enabled); } + + @Override + public void addPropertyChangeListener(PropertyChangeListener pcl) { + pcs.addPropertyChangeListener(pcl); + } + + @Override + public void removePropertyChangeListener(PropertyChangeListener pcl) { + pcs.removePropertyChangeListener(pcl); + } /** * This method is called from within the constructor to initialize the form. @@ -168,6 +182,7 @@ class SizeSearchPanel extends javax.swing.JPanel { private void sizeCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sizeCheckBoxActionPerformed setComponentsEnabled(); + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); }//GEN-LAST:event_sizeCheckBoxActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables From 50caa5aa8b68901c6caeefde925202cb65e794bb Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Thu, 26 May 2016 08:50:19 -0400 Subject: [PATCH 10/39] Finished search button enabling. --- .../autopsy/filesearch/DateSearchFilter.java | 3 +- .../autopsy/filesearch/DateSearchPanel.form | 12 ++++++ .../autopsy/filesearch/DateSearchPanel.java | 43 +++++++++++++++++++ .../filesearch/KnownStatusSearchFilter.java | 3 +- .../filesearch/KnownStatusSearchPanel.form | 6 +++ .../filesearch/KnownStatusSearchPanel.java | 24 ++++++++++- .../autopsy/filesearch/NameSearchFilter.java | 4 +- .../autopsy/filesearch/NameSearchPanel.java | 18 ++++++++ 8 files changed, 108 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java index be42035087..507edfe973 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java @@ -67,7 +67,8 @@ class DateSearchFilter extends AbstractFileSearchFilter { @Override public boolean isEnabled() { - return this.getComponent().getDateCheckBox().isSelected(); + return this.getComponent().getDateCheckBox().isSelected() && + this.getComponent().isSearchable(); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form index 2d09e16507..e92d57fdd9 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form @@ -236,6 +236,9 @@ + + + @@ -244,6 +247,9 @@ + + + @@ -252,6 +258,9 @@ + + + @@ -260,6 +269,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java index a852fddfa3..718eaa8b8f 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java @@ -222,15 +222,35 @@ class DateSearchPanel extends javax.swing.JPanel { modifiedCheckBox.setSelected(true); modifiedCheckBox.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.modifiedCheckBox.text")); // NOI18N + modifiedCheckBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + modifiedCheckBoxActionPerformed(evt); + } + }); changedCheckBox.setSelected(true); changedCheckBox.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.changedCheckBox.text")); // NOI18N + changedCheckBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + changedCheckBoxActionPerformed(evt); + } + }); accessedCheckBox.setSelected(true); accessedCheckBox.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.accessedCheckBox.text")); // NOI18N + accessedCheckBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + accessedCheckBoxActionPerformed(evt); + } + }); createdCheckBox.setSelected(true); createdCheckBox.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.createdCheckBox.text")); // NOI18N + createdCheckBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + createdCheckBoxActionPerformed(evt); + } + }); dateFromButtonCalendar.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateFromButtonCalendar.text")); // NOI18N dateFromButtonCalendar.addPropertyChangeListener(new java.beans.PropertyChangeListener() { @@ -365,6 +385,22 @@ class DateSearchPanel extends javax.swing.JPanel { pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); }//GEN-LAST:event_dateCheckBoxActionPerformed + private void modifiedCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_modifiedCheckBoxActionPerformed + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + }//GEN-LAST:event_modifiedCheckBoxActionPerformed + + private void accessedCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_accessedCheckBoxActionPerformed + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + }//GEN-LAST:event_accessedCheckBoxActionPerformed + + private void createdCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createdCheckBoxActionPerformed + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + }//GEN-LAST:event_createdCheckBoxActionPerformed + + private void changedCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_changedCheckBoxActionPerformed + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + }//GEN-LAST:event_changedCheckBoxActionPerformed + /** * Validate and set the datetime field on the screen given a datetime * string. @@ -393,6 +429,13 @@ class DateSearchPanel extends javax.swing.JPanel { dateToTextField.setText(dateStringResult); dateToButtonCalendar.setTargetDate(date); } + + boolean isSearchable() { + return this.accessedCheckBox.isSelected() || + this.changedCheckBox.isSelected() || + this.createdCheckBox.isSelected() || + this.modifiedCheckBox.isSelected(); + } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JCheckBox accessedCheckBox; private javax.swing.JCheckBox changedCheckBox; diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java index 8bd74d02fa..b40eedf845 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java @@ -40,7 +40,8 @@ class KnownStatusSearchFilter extends AbstractFileSearchFilter + + + @@ -83,6 +86,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java index 89e12481b1..4791d8c4fb 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java @@ -77,6 +77,10 @@ class KnownStatusSearchPanel extends javax.swing.JPanel { pcs.removePropertyChangeListener(pcl); } + boolean isSearchable() { + return this.unknownOptionCheckBox.isSelected() || this.knownBadOptionCheckBox.isSelected() || this.knownOptionCheckBox.isSelected(); + } + /** * 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 @@ -100,6 +104,11 @@ class KnownStatusSearchPanel extends javax.swing.JPanel { unknownOptionCheckBox.setSelected(true); unknownOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.unknownOptionCheckBox.text")); // NOI18N + unknownOptionCheckBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + unknownOptionCheckBoxActionPerformed(evt); + } + }); knownOptionCheckBox.setSelected(true); knownOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownOptionCheckBox.text")); // NOI18N @@ -111,6 +120,11 @@ class KnownStatusSearchPanel extends javax.swing.JPanel { knownBadOptionCheckBox.setSelected(true); knownBadOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownBadOptionCheckBox.text")); // NOI18N + knownBadOptionCheckBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + knownBadOptionCheckBoxActionPerformed(evt); + } + }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -141,7 +155,7 @@ class KnownStatusSearchPanel extends javax.swing.JPanel { }// //GEN-END:initComponents private void knownOptionCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownOptionCheckBoxActionPerformed - // TODO add your handling code here: + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); }//GEN-LAST:event_knownOptionCheckBoxActionPerformed private void knownCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownCheckBoxActionPerformed @@ -149,6 +163,14 @@ class KnownStatusSearchPanel extends javax.swing.JPanel { pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); }//GEN-LAST:event_knownCheckBoxActionPerformed + private void unknownOptionCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_unknownOptionCheckBoxActionPerformed + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + }//GEN-LAST:event_unknownOptionCheckBoxActionPerformed + + private void knownBadOptionCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownBadOptionCheckBoxActionPerformed + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + }//GEN-LAST:event_knownBadOptionCheckBoxActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JCheckBox knownBadOptionCheckBox; private javax.swing.JCheckBox knownCheckBox; diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java index 2433a71ba3..40e10701cc 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionListener; - import org.openide.util.NbBundle; import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException; @@ -42,7 +41,8 @@ class NameSearchFilter extends AbstractFileSearchFilter { @Override public boolean isEnabled() { - return this.getComponent().getNameCheckBox().isSelected(); + return this.getComponent().getNameCheckBox().isSelected() && + !this.getComponent().getSearchTextField().getText().isEmpty(); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java index dd7a3d008f..4ffc2c86f7 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java @@ -31,6 +31,8 @@ import java.beans.PropertyChangeSupport; import javax.swing.JCheckBox; import javax.swing.JMenuItem; import javax.swing.JTextField; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; /** * @@ -71,6 +73,22 @@ class NameSearchPanel extends javax.swing.JPanel { copyMenuItem.addActionListener(actList); pasteMenuItem.addActionListener(actList); selectAllMenuItem.addActionListener(actList); + this.searchTextField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + + @Override + public void removeUpdate(DocumentEvent e) { + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + + @Override + public void changedUpdate(DocumentEvent e) { + pcs.firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + }); } From fd09fb81eb41948778c9bab2ae6b4f4b67616434 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Thu, 26 May 2016 13:10:39 -0400 Subject: [PATCH 11/39] Made search not happen when an exception would be thrown. --- .../autopsy/filesearch/DateSearchFilter.java | 13 ++++++++++-- .../autopsy/filesearch/FileSearchFilter.java | 2 ++ .../autopsy/filesearch/FileSearchPanel.java | 16 +++++++++------ .../filesearch/KnownStatusSearchFilter.java | 13 ++++++++++-- .../autopsy/filesearch/MimeTypeFilter.java | 20 ++++++++++++------- .../autopsy/filesearch/NameSearchFilter.java | 12 +++++++++-- .../autopsy/filesearch/SizeSearchFilter.java | 6 +++++- 7 files changed, 62 insertions(+), 20 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java index 507edfe973..d92d62e7e4 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java @@ -67,8 +67,7 @@ class DateSearchFilter extends AbstractFileSearchFilter { @Override public boolean isEnabled() { - return this.getComponent().getDateCheckBox().isSelected() && - this.getComponent().isSearchable(); + return this.getComponent().getDateCheckBox().isSelected(); } @Override @@ -211,6 +210,16 @@ class DateSearchFilter extends AbstractFileSearchFilter { getComponent().addPropertyChangeListener(listener); } + @Override + public boolean isValid() { + if (!isEnabled()) { + return true; + } + else { + return this.getComponent().isSearchable(); + } + } + /** * Inner class to put the separator inside the combo box. */ diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java index d4b39716d7..bf1cb6fdcf 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java @@ -40,6 +40,8 @@ import javax.swing.JComponent; * @return true if it should be included in the search */ boolean isEnabled(); + + boolean isValid(); /** * Gets predicate expression to include in the SQL filter expression diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java index de01ecd901..569bb4ba32 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java @@ -105,7 +105,7 @@ class FileSearchPanel extends javax.swing.JPanel { filter.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { - searchButton.setEnabled(anyFiltersEnabled()); + searchButton.setEnabled(isSearchable()); } }); } @@ -116,20 +116,24 @@ class FileSearchPanel extends javax.swing.JPanel { search(); } }); - searchButton.setEnabled(anyFiltersEnabled()); + searchButton.setEnabled(isSearchable()); } /** * @return true if any of the filters in the panel are enabled (checked) */ - private boolean anyFiltersEnabled() { + private boolean isSearchable() { + boolean enabled = false; for (FileSearchFilter filter : this.getFilters()) { if (filter.isEnabled()) { - return true; + enabled = true; + if (!filter.isValid()) { + return false; + } } } - return false; + return enabled; } /** @@ -140,7 +144,7 @@ class FileSearchPanel extends javax.swing.JPanel { // change the cursor to "waiting cursor" for this operation this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); try { - if (this.anyFiltersEnabled()) { + if (this.isSearchable()) { String title = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.title", ++resultWindowCount); String pathText = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.pathText"); diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java index b40eedf845..e11de57180 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java @@ -40,8 +40,8 @@ class KnownStatusSearchFilter extends AbstractFileSearchFilter { +class MimeTypeFilter extends AbstractFileSearchFilter { public MimeTypeFilter(MimeTypePanel component) { super(component); } + public MimeTypeFilter() { this(new MimeTypePanel()); } @Override public boolean isEnabled() { - return this.getComponent().isSelected() && - !this.getComponent().getMimeTypesSelected().isEmpty(); + return this.getComponent().isSelected(); } @Override public String getPredicate() throws FilterValidationException { String predicate = ""; - for(String mimeType : this.getComponent().getMimeTypesSelected()) { + for (String mimeType : this.getComponent().getMimeTypesSelected()) { predicate += "mime_type = '" + mimeType + "' OR "; } - if(predicate.length() > 3) { + if (predicate.length() > 3) { predicate = predicate.substring(0, predicate.length() - 3); } return predicate; @@ -41,6 +41,12 @@ class MimeTypeFilter extends AbstractFileSearchFilter { public void addActionListener(ActionListener l) { } - - + @Override + public boolean isValid() { + if (!isEnabled()) { + return true; + } else { + return !this.getComponent().getMimeTypesSelected().isEmpty(); + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java index 40e10701cc..787d66784a 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java @@ -41,8 +41,7 @@ class NameSearchFilter extends AbstractFileSearchFilter { @Override public boolean isEnabled() { - return this.getComponent().getNameCheckBox().isSelected() && - !this.getComponent().getSearchTextField().getText().isEmpty(); + return this.getComponent().getNameCheckBox().isSelected(); } @Override @@ -63,4 +62,13 @@ class NameSearchFilter extends AbstractFileSearchFilter { public void addActionListener(ActionListener l) { getComponent().addActionListener(l); } + + @Override + public boolean isValid() { + if (!isEnabled()) { + return true; + } else { + return !this.getComponent().getSearchTextField().getText().isEmpty(); + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java index 03fc59b8d4..ca43dac7e0 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionListener; import javax.swing.JComboBox; - import org.openide.util.NbBundle; import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException; @@ -73,4 +72,9 @@ class SizeSearchFilter extends AbstractFileSearchFilter { public void addActionListener(ActionListener l) { getComponent().addActionListener(l); } + + @Override + public boolean isValid() { + return true; + } } From 562fd7b8d0fa74b143f2f3c377e478d3e7147897 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Thu, 26 May 2016 14:22:36 -0400 Subject: [PATCH 12/39] Worked towards adding timeline to the toolbar. --- Core/src/org/sleuthkit/autopsy/core/layer.xml | 5 +++++ .../autopsy/timeline/OpenTimelineAction.java | 21 ++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index 8e71419b45..92e64dfa55 100644 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -387,6 +387,11 @@ + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java index b766394926..cd4392e32b 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java @@ -18,8 +18,11 @@ */ package org.sleuthkit.autopsy.timeline; +import java.awt.Component; import java.io.IOException; import java.util.logging.Level; +import javax.swing.ImageIcon; +import javax.swing.JButton; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; @@ -27,6 +30,7 @@ import org.openide.awt.ActionRegistration; import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; +import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.Installer; import org.sleuthkit.autopsy.coreutils.Logger; @@ -37,13 +41,15 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; @ActionRegistration(displayName = "#CTL_MakeTimeline", lazy = false) @ActionReferences(value = { @ActionReference(path = "Menu/Tools", position = 100)}) -public class OpenTimelineAction extends CallableSystemAction { +public class OpenTimelineAction extends CallableSystemAction implements Presenter.Toolbar { private static final Logger LOGGER = Logger.getLogger(OpenTimelineAction.class.getName()); private static final boolean fxInited = Installer.isJavaFxInited(); private static TimeLineController timeLineController = null; + + private JButton toolbarButton = new JButton(); synchronized static void invalidateController() { timeLineController = null; @@ -102,4 +108,17 @@ public class OpenTimelineAction extends CallableSystemAction { public boolean asynchronous() { return false; // run on edt } + + /** + * Returns the toolbar component of this action + * + * @return component the toolbar button + */ + @Override + public Component getToolbarPresenter() { + ImageIcon icon = new ImageIcon("images//20140521121247760_easyicon_net_32_colorized.png"); //NON-NLS + toolbarButton.setIcon(icon); + toolbarButton.setText(this.getName()); + return toolbarButton; + } } From 305c7a332be5db92014e93a9478f8f91df349560 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Thu, 26 May 2016 15:17:54 -0400 Subject: [PATCH 13/39] Got rid of toolbar updates. --- Core/src/org/sleuthkit/autopsy/core/layer.xml | 5 ----- .../autopsy/timeline/OpenTimelineAction.java | 21 +------------------ 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index 92e64dfa55..8e71419b45 100644 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -387,11 +387,6 @@ - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java index cd4392e32b..b766394926 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java @@ -18,11 +18,8 @@ */ package org.sleuthkit.autopsy.timeline; -import java.awt.Component; import java.io.IOException; import java.util.logging.Level; -import javax.swing.ImageIcon; -import javax.swing.JButton; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; @@ -30,7 +27,6 @@ import org.openide.awt.ActionRegistration; import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; -import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.Installer; import org.sleuthkit.autopsy.coreutils.Logger; @@ -41,15 +37,13 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; @ActionRegistration(displayName = "#CTL_MakeTimeline", lazy = false) @ActionReferences(value = { @ActionReference(path = "Menu/Tools", position = 100)}) -public class OpenTimelineAction extends CallableSystemAction implements Presenter.Toolbar { +public class OpenTimelineAction extends CallableSystemAction { private static final Logger LOGGER = Logger.getLogger(OpenTimelineAction.class.getName()); private static final boolean fxInited = Installer.isJavaFxInited(); private static TimeLineController timeLineController = null; - - private JButton toolbarButton = new JButton(); synchronized static void invalidateController() { timeLineController = null; @@ -108,17 +102,4 @@ public class OpenTimelineAction extends CallableSystemAction implements Presente public boolean asynchronous() { return false; // run on edt } - - /** - * Returns the toolbar component of this action - * - * @return component the toolbar button - */ - @Override - public Component getToolbarPresenter() { - ImageIcon icon = new ImageIcon("images//20140521121247760_easyicon_net_32_colorized.png"); //NON-NLS - toolbarButton.setIcon(icon); - toolbarButton.setText(this.getName()); - return toolbarButton; - } } From 126c12d2d172feaced698ef87a75e688bfe3b7ed Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Thu, 26 May 2016 16:06:20 -0400 Subject: [PATCH 14/39] Fixed semantics. --- .../autopsy/filesearch/DateSearchFilter.java | 12 +----------- .../autopsy/filesearch/DateSearchPanel.java | 2 +- .../autopsy/filesearch/FileSearchFilter.java | 16 +++++++++++++--- .../autopsy/filesearch/FileSearchPanel.java | 8 ++++---- .../filesearch/KnownStatusSearchFilter.java | 6 +----- .../filesearch/KnownStatusSearchPanel.java | 2 +- .../autopsy/filesearch/MimeTypeFilter.java | 6 +----- .../autopsy/filesearch/NameSearchFilter.java | 6 +----- 8 files changed, 23 insertions(+), 35 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java index d92d62e7e4..33e1ba6635 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java @@ -205,19 +205,9 @@ class DateSearchFilter extends AbstractFileSearchFilter { getComponent().addActionListener(l); } - @Override - public void addPropertyChangeListener(PropertyChangeListener listener) { - getComponent().addPropertyChangeListener(listener); - } - @Override public boolean isValid() { - if (!isEnabled()) { - return true; - } - else { - return this.getComponent().isSearchable(); - } + return this.getComponent().isValidSearch(); } /** diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java index 718eaa8b8f..9794e25700 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java @@ -430,7 +430,7 @@ class DateSearchPanel extends javax.swing.JPanel { dateToButtonCalendar.setTargetDate(date); } - boolean isSearchable() { + boolean isValidSearch() { return this.accessedCheckBox.isSelected() || this.changedCheckBox.isSelected() || this.createdCheckBox.isSelected() || diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java index bf1cb6fdcf..457db56570 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java @@ -25,7 +25,7 @@ import javax.swing.JComponent; /** * Provides a filter and the panel to display it to the FileSearchTopComponent */ - interface FileSearchFilter { +interface FileSearchFilter { /** * Gets the panel to put in the File Search pane. @@ -40,7 +40,12 @@ import javax.swing.JComponent; * @return true if it should be included in the search */ boolean isEnabled(); - + + /** + * Checks if the panel has valid input for search. + * + * @return Whether the panel has valid input for search. + */ boolean isValid(); /** @@ -58,7 +63,12 @@ import javax.swing.JComponent; * Add an action listener to the fields of this panel */ void addActionListener(ActionListener l); - + + /** + * Adds the property change listener to the panel + * + * @param listener the listener to add. + */ void addPropertyChangeListener(PropertyChangeListener listener); /** diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java index 569bb4ba32..656e22ef9e 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java @@ -105,7 +105,7 @@ class FileSearchPanel extends javax.swing.JPanel { filter.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { - searchButton.setEnabled(isSearchable()); + searchButton.setEnabled(isValidSearch()); } }); } @@ -116,13 +116,13 @@ class FileSearchPanel extends javax.swing.JPanel { search(); } }); - searchButton.setEnabled(isSearchable()); + searchButton.setEnabled(isValidSearch()); } /** * @return true if any of the filters in the panel are enabled (checked) */ - private boolean isSearchable() { + private boolean isValidSearch() { boolean enabled = false; for (FileSearchFilter filter : this.getFilters()) { if (filter.isEnabled()) { @@ -144,7 +144,7 @@ class FileSearchPanel extends javax.swing.JPanel { // change the cursor to "waiting cursor" for this operation this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); try { - if (this.isSearchable()) { + if (this.isValidSearch()) { String title = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.title", ++resultWindowCount); String pathText = NbBundle.getMessage(this.getClass(), "FileSearchPanel.search.results.pathText"); diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java index e11de57180..5f52afa035 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java @@ -86,10 +86,6 @@ class KnownStatusSearchFilter extends AbstractFileSearchFilter { @Override public boolean isValid() { - if (!isEnabled()) { - return true; - } else { - return !this.getComponent().getMimeTypesSelected().isEmpty(); - } + return !this.getComponent().getMimeTypesSelected().isEmpty(); } } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java index 787d66784a..ee70ebd5e1 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java @@ -65,10 +65,6 @@ class NameSearchFilter extends AbstractFileSearchFilter { @Override public boolean isValid() { - if (!isEnabled()) { - return true; - } else { - return !this.getComponent().getSearchTextField().getText().isEmpty(); - } + return !this.getComponent().getSearchTextField().getText().isEmpty(); } } From 5c72b20f11552107316b79cd4b6fab8720db3442 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Fri, 27 May 2016 10:43:42 -0400 Subject: [PATCH 15/39] Added timeline to the toolbar. --- .../sleuthkit/autopsy/casemodule/Case.java | 5 +- Core/src/org/sleuthkit/autopsy/core/layer.xml | 4 +- .../autopsy/timeline/OpenTimelineAction.java | 48 +++++++++++++++++- .../timeline/images/btn_icon_timeline.png | Bin 0 -> 1390 bytes .../images/btn_icon_image_gallery.png | Bin 0 -> 2169 bytes .../OpenAction.java | 0 6 files changed, 51 insertions(+), 6 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/timeline/images/btn_icon_timeline.png create mode 100755 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/btn_icon_image_gallery.png rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{actions => publicactions}/OpenAction.java (100%) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 7677b5be68..3c0e223064 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -46,7 +46,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; -import org.apache.commons.io.FileUtils; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; @@ -76,6 +75,7 @@ import org.sleuthkit.autopsy.events.AutopsyEventException; import org.sleuthkit.autopsy.events.AutopsyEventPublisher; import org.sleuthkit.autopsy.ingest.IngestJob; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.timeline.OpenTimelineAction; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; @@ -1523,7 +1523,7 @@ public class Case implements SleuthkitCase.ErrorObserver { CallableSystemAction.get(CaseCloseAction.class).setEnabled(true); CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true); CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true); // Delete Case menu - + CallableSystemAction.get(OpenTimelineAction.class).setEnabled(true); if (toChangeTo.hasData()) { // open all top components SwingUtilities.invokeLater(() -> { @@ -1560,6 +1560,7 @@ public class Case implements SleuthkitCase.ErrorObserver { CallableSystemAction.get(CaseCloseAction.class).setEnabled(false); // Case Close menu CallableSystemAction.get(CasePropertiesAction.class).setEnabled(false); // Case Properties menu CallableSystemAction.get(CaseDeleteAction.class).setEnabled(false); // Delete Case menu + CallableSystemAction.get(OpenTimelineAction.class).setEnabled(false); }); } diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index b2852f6069..b6a7828a57 100644 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -387,11 +387,11 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java index b766394926..7c16b9da8e 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/OpenTimelineAction.java @@ -18,8 +18,13 @@ */ package org.sleuthkit.autopsy.timeline; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.io.IOException; import java.util.logging.Level; +import javax.swing.ImageIcon; +import javax.swing.JButton; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; @@ -27,6 +32,7 @@ import org.openide.awt.ActionRegistration; import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; +import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.Installer; import org.sleuthkit.autopsy.coreutils.Logger; @@ -36,8 +42,9 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.timeline.Timeline") @ActionRegistration(displayName = "#CTL_MakeTimeline", lazy = false) @ActionReferences(value = { - @ActionReference(path = "Menu/Tools", position = 100)}) -public class OpenTimelineAction extends CallableSystemAction { + @ActionReference(path = "Menu/Tools", position = 100), + @ActionReference(path = "Toolbars/Case", position = 102)}) +public class OpenTimelineAction extends CallableSystemAction implements Presenter.Toolbar { private static final Logger LOGGER = Logger.getLogger(OpenTimelineAction.class.getName()); @@ -45,10 +52,22 @@ public class OpenTimelineAction extends CallableSystemAction { private static TimeLineController timeLineController = null; + private JButton toolbarButton = new JButton(); + synchronized static void invalidateController() { timeLineController = null; } + public OpenTimelineAction() { + toolbarButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + performAction(); + } + }); + this.setEnabled(false); + } + @Override public boolean isEnabled() { /** @@ -102,4 +121,29 @@ public class OpenTimelineAction extends CallableSystemAction { public boolean asynchronous() { return false; // run on edt } + + /** + * Set this action to be enabled/disabled + * + * @param value whether to enable this action or not + */ + @Override + public void setEnabled(boolean value) { + super.setEnabled(value); + toolbarButton.setEnabled(value); + } + + /** + * Returns the toolbar component of this action + * + * @return component the toolbar button + */ + @Override + public Component getToolbarPresenter() { + ImageIcon icon = new ImageIcon("Core\\src\\org\\sleuthkit\\autopsy\\timeline\\images\\btn_icon_timeline.png"); //NON-NLS + toolbarButton.setIcon(icon); + toolbarButton.setText(this.getName()); + + return toolbarButton; + } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/images/btn_icon_timeline.png b/Core/src/org/sleuthkit/autopsy/timeline/images/btn_icon_timeline.png new file mode 100755 index 0000000000000000000000000000000000000000..f44034ff012b20ef0e2db418541e0f699ac803ab GIT binary patch literal 1390 zcmZ{kdo&by6vuz8!5D*3UWvv$SZ11;ERC5wM`qGkkIC^!FFVMHSJG7i0Kn-q zs=JiB-&0XuT7@T1iKUPWwPV-;(3k_;3xG&_!$6ul1Aurm0K8NHcBB$-1%Mbl0Pp+( zuqpvSD@xGeMv)HWSYbZ5dfIR_mlx;0&S_Nz@;-B73Lv&P+7#~ zjlWUSrG9j(9g{X#SmejP5v)0wG`{^s!BzN|B3Z(&Nlk2Vq#@g9d~Vb`Z~gzt zBd9(N_m9(NjZpNbXA{CoHpDp+1+K_PBeP(hELvyatUVzyyb0_f<d8jv?zUZLEc8cTD$xp^!3e78X} z`3S@)uUvOtj=3wJwicp-0O{FH;ry!`7$vmK%|qrj9F&N#L+W!IUInjbUKY-+!y&{gV8dzAcTz)=*+zkVS0aaQQh?j()tL=y4Y_mJ(zjpddA}Tu_b3)-K`H z0d}>pZdk>C%$4!*&sQe|Z|>~#ft8pZ8zE0F+ZYmw$-8d)j=sKJ6NsXv&qv6~FDKZ0 zJ7%ppzg&;c_{ydGK9AYxj9cu_aosHUJ>ECf=sBR~BUicT-o>A2;YS6gp735Jk9W0p zvs!-Do$!c63UH|{Mq4)h$wl2UU1NIV9s&CubMyzBA_cSS(!)L3%zfFXs46k$c)_Qe zCsJTEVM?x!jW^Ozjg7jk$S_)}ko*-{Pu%8A)ZeG2lh_^HTzKcJo&}C*3VtB5yVnMD zq>)JaZGw2$Ix&l-HP)rCos~BkOD^48)T$=gCiwhbtzp7O^)nAfAd;LlCUvyF88|_= zRAm#VioC-z4q;x7ud-U6JsDM%h~(572%a@mWHXcchynM%e)?vRAKwC3(YB62zWsR- zpsW$7Xtxl*WlozMdI9Vyq&e3)PwW+JNq-ND>*&P|3g8A?1zrf20ub>83oQO8EYXsQ uCt2Z%R!7aTcylW}zWYps@qY{vkwKi0xc@hZW&S9T8UWqVg<5a#&;J)70Z&B$ literal 0 HcmV?d00001 diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/btn_icon_image_gallery.png b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/images/btn_icon_image_gallery.png new file mode 100755 index 0000000000000000000000000000000000000000..eea6d5083537a19c24f1191a1021791992666e83 GIT binary patch literal 2169 zcmZ{lXEYlO7sq3dM^NKMP_)#j6|158Sh06#k=lfkmxjD+}1^~eOXMde|vCw--A2XOW01$Bn0EkTh0FLQW>@ollt_lFGdIA7CF984{ zR9=(4E`7l2ZD|UnlO9J#%@63{K$*Fq>DxyCB!i(`E`~0$g_&C$vrV&zazNw<@H@kF z<&HVjz|pLeoYk8mHY%9d7P)rI$?5(c^375S)~wd|dzSB)EQF{S8=qORu|BVA_ocKF zRd$t@WRA~Lo+lEJ+7`=NqL4Wh7w1G__T_4yOBA!LH3fCwxG`~K!fnFMZ6sX6rOU^V z%Y8Avj+8R>EOL{yBzCALb#^fQbD`Ju1L|RhtnIN%>)|XmJHGioUd&oLf=hWIp&@QuyI6z0oWQAmZEAU;^J030hX;cz zIUvV<&8*FvH`7}UAUY(E!_*+=uptAjxwH$)Me zlc8Z_ITH=0jSI^g|4C4NuX*$|SNaKySZq_o-fC+=(f2&P@xWBxZrcT4=NA$|z{Al< zH{6|>qXK>t5mSjiXSbl5D9v7CQsp znx>{?uwRjwasOJblEQvH*UjvaM4%;`xL3Vd`IWL^bm17zd$3e2)5TR0rhFv%%C6?n z*c!XZP2l#9nK5W0i|?jBhb7nf4}9A?;L$;@6+Bqa`}{gkDF*w#Z*UIy_!OMsYoW`B zqdc~0?B5$`3X23cH)m}=O{6;1-zyFfX|tOznHpw~vt!`XudJv*t$dSl$1Y@c1mqYK z$YKUPa>%(BnaP;nH_lEv*XCWGC@MYV0KZ962lfO4gA8jBj6E0uc{^y9?0Wb;NJNF} zcr{b_90i!bdxoqgH~cM(>o}9kB&BqRTivbJpRUf>d&)N-&RLa|SjcztaOc?z>@wyd z&8^ep{F|46Kjfo!B2AH4E-BBR4uG6+ZGh@VMYI6_!l z`iQ;>D3-;{_A$1dO>h#mUs`#pqE0q?N+DN6Ah>L`WOY1C5Pk*`JL^+)NP+WE)@5Q`Qi)aG3|!C@mqgUb@{hxQ;8T_$4pm0-rY(4 zVrMEn#*UA50$aaBkIrh*e#8+_`VwMB*sFVa6I9$&`DsMk;N5Y_nOfF*ZB&tr}vCKS$(&Qm0 zz}>l11`)<_NjrlXuW+%7=hb1{_lagWzb+b8$dz;~MQB}|th!=zd`C@#|T(U*#7_Z$Vm&gfc2ui%i+gzG=o+Ak#~3p$2S zP~ZHs1~9++Kq+h~>kZeVes%-lk=Jpu@G$(~Hjj$ait*tkCjUUbi^IjIA3D z(AW6%VuuRy`3aRHkL6?r);C(hg$y@NBB`XCQNuR-mf zdzZ;Ev(Df$Va`$&_&^GOsYJ)Fu6-qq6uy@7$f4Bc5u+qKBSYEu|1Mr%VtmCp96jan z=fuaH&u7cp-q(rLdJ8RtS6Y+^7{+!;l^C(78A6tLsUdoq)I$91Vt?*=%e{@UY61N$ z1b5fN7DojcZ2o~|$v1*gBKK*eR_BwGX0G&N0YdNH0 znJz7!YSQhimd(W)|KZ2RzG;!YMACr~JDAUK91r7eBL;8q8(*LZi!itI;9*O3is~*| zz+GJl$kOaNUmk!X%}m~5VAt=X75nqsNFtHujNG^nLb#aZFI}*E0SlCZE@Iu4OEhS3 zAKV~CxUo$rO6Z({=_h-amdbb&{SC{689RshdW9i$d_oa)0Mt~$T1u*#N@~{}Rkd|A swRAMVN~#( Date: Tue, 31 May 2016 13:06:51 -0400 Subject: [PATCH 16/39] Made run ingest modules dialog accessable via directory listing. --- .../autopsy/datamodel/ImageNode.java | 61 +++++++++++++++++-- .../datamodel/VirtualDirectoryNode.java | 57 ++++++++++++++++- 2 files changed, 113 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index 4a822aec09..634d0fc114 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -18,15 +18,25 @@ */ package org.sleuthkit.autopsy.datamodel; +import java.awt.event.ActionEvent; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import javax.swing.AbstractAction; import javax.swing.Action; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor; +import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.FileSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.autopsy.ingest.RunIngestModulesDialog; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.VirtualDirectory; /** * This class is used to represent the "Node" for the image. The children of @@ -66,15 +76,58 @@ public class ImageNode extends AbstractContentNode { * @return */ @Override + @Messages({"ImageNode.action.runIngestMods.text=Run Ingest Modules", + "ImageNode.action.openFileSrcByAttr.text=Open File Search by Attributes",}) public Action[] getActions(boolean context) { + List actionsList = new ArrayList(); + actionsList.addAll(ExplorerNodeActionVisitor.getActions(content)); + actionsList.add(new FileSearchAction( + NbBundle.getMessage(this.getClass(), "ImageNode.getActions.openFileSearchByAttr.text"))); + + //extract dir action + Directory dir = this.getLookup().lookup(Directory.class); + if (dir != null) { + actionsList.add(ExtractAction.getInstance()); + actionsList.add(new AbstractAction( + Bundle.ImageNode_action_runIngestMods_text()) { + @Override + public void actionPerformed(ActionEvent e) { + final RunIngestModulesDialog ingestDialog = new RunIngestModulesDialog(dir); + ingestDialog.display(); + } + }); + } + final Image img = this.getLookup().lookup(Image.class); + + VirtualDirectory virtualDirectory = this.getLookup().lookup(VirtualDirectory.class); + // determine if the virtualDireory is at root-level (Logical File Set). + boolean isRootVD = false; + if (virtualDirectory != null) { + try { + if (virtualDirectory.getParent() == null) { + isRootVD = true; + } + } catch (TskCoreException ex) { + //logger.log(Level.WARNING, "Error determining the parent of the virtual directory", ex); // NON-NLS + } + } + + // 'run ingest' action and 'file search' action are added only if the + // selected node is img node or a root level virtual directory. + if (img != null || isRootVD) { + actionsList.add(new AbstractAction( + Bundle.ImageNode_action_runIngestMods_text()) { + @Override + public void actionPerformed(ActionEvent e) { + final RunIngestModulesDialog ingestDialog = new RunIngestModulesDialog(Collections.singletonList(content)); + ingestDialog.display(); + } + }); + } actionsList.add(new NewWindowViewAction( NbBundle.getMessage(this.getClass(), "ImageNode.getActions.viewInNewWin.text"), this)); - actionsList.add(new FileSearchAction( - NbBundle.getMessage(this.getClass(), "ImageNode.getActions.openFileSearchByAttr.text"))); - actionsList.addAll(ExplorerNodeActionVisitor.getActions(content)); - return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index f908251d28..c5ad17d65c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -18,19 +18,28 @@ */ package org.sleuthkit.autopsy.datamodel; +import java.awt.event.ActionEvent; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import javax.swing.AbstractAction; import javax.swing.Action; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; +import org.sleuthkit.autopsy.directorytree.FileSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.datamodel.VirtualDirectory; +import org.sleuthkit.autopsy.ingest.RunIngestModulesDialog; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.Directory; +import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.datamodel.VirtualDirectory; /** * Node for layout dir @@ -73,8 +82,54 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode actions = new ArrayList<>(); + if (this.content.isDataSource()) { + //extract dir action + Directory dir = this.getLookup().lookup(Directory.class); + if (dir != null) { + actions.add(ExtractAction.getInstance()); + actions.add(new AbstractAction( + Bundle.VirtualDirectoryNode_action_runIngestMods_text()) { + @Override + public void actionPerformed(ActionEvent e) { + final RunIngestModulesDialog ingestDialog = new RunIngestModulesDialog(dir); + ingestDialog.display(); + } + }); + } + final Image img = this.getLookup().lookup(Image.class); + + VirtualDirectory virtualDirectory = this.getLookup().lookup(VirtualDirectory.class); + // determine if the virtualDireory is at root-level (Logical File Set). + boolean isRootVD = false; + if (virtualDirectory != null) { + try { + if (virtualDirectory.getParent() == null) { + isRootVD = true; + } + } catch (TskCoreException ex) { + //logger.log(Level.WARNING, "Error determining the parent of the virtual directory", ex); // NON-NLS + } + } + + // 'run ingest' action and 'file search' action are added only if the + // selected node is img node or a root level virtual directory. + if (img != null || isRootVD) { + actions.add(new FileSearchAction( + Bundle.VirtualDirectoryNode_action_openFileSrcByAttr_text())); + actions.add(new AbstractAction( + Bundle.VirtualDirectoryNode_action_runIngestMods_text()) { + @Override + public void actionPerformed(ActionEvent e) { + final RunIngestModulesDialog ingestDialog = new RunIngestModulesDialog(Collections.singletonList(content)); + ingestDialog.display(); + } + }); + } + } actions.add(new NewWindowViewAction( NbBundle.getMessage(this.getClass(), "VirtualDirectoryNode.getActions.viewInNewWin.text"), this)); actions.add(null); // creates a menu separator From dc10a91fd5f16b97624039c4a356077190822714 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 31 May 2016 15:43:43 -0400 Subject: [PATCH 17/39] swap zoom in out buttons for scroll by buttons --- .../timeline/ui/AbstractTimeLineView.java | 10 ++- .../autopsy/timeline/ui/ViewFrame.fxml | 4 +- .../autopsy/timeline/ui/ViewFrame.java | 78 ++++++++++++----- .../ui/countsview/CountsViewPane.java | 7 +- .../ui/detailview/DetailViewPane.java | 6 ++ .../timeline/ui/listvew/ListTimeline.fxml | 86 ++++++++++--------- .../timeline/ui/listvew/ListTimeline.java | 10 +++ .../timeline/ui/listvew/ListViewPane.java | 10 ++- 8 files changed, 138 insertions(+), 73 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimeLineView.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimeLineView.java index 86fa7ec132..8aa5a8b887 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimeLineView.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractTimeLineView.java @@ -40,6 +40,7 @@ import org.sleuthkit.autopsy.coreutils.LoggedTask; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.timeline.TimeLineController; +import org.sleuthkit.autopsy.timeline.ViewMode; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent; @@ -136,8 +137,8 @@ public abstract class AbstractTimeLineView extends BorderPane { /** * Refresh this view based on current state of zoom / filters. Primarily - * this invokes the background ViewRefreshTask returned by - * getUpdateTask(), which derived classes must implement. + * this invokes the background ViewRefreshTask returned by getUpdateTask(), + * which derived classes must implement. * * TODO: replace this logic with a javafx Service ? -jm */ @@ -185,9 +186,10 @@ public abstract class AbstractTimeLineView extends BorderPane { */ protected abstract Task getNewUpdateTask(); + protected abstract ViewMode getViewMode(); + /** - * Get a List of Nodes containing settings widgets to insert into this - * view's header. + * Get a List of Nodes containing settings widgets to insert into this view. * * @return The List of settings Nodes. */ diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/ViewFrame.fxml b/Core/src/org/sleuthkit/autopsy/timeline/ui/ViewFrame.fxml index 777986e600..5de950392e 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/ViewFrame.fxml +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/ViewFrame.fxml @@ -125,7 +125,7 @@ - + - + - - - + + + + diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java index 04669ad4fd..b8591b11d0 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.java @@ -23,6 +23,7 @@ import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Objects; @@ -42,6 +43,7 @@ import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.geometry.Pos; +import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.ComboBox; import javafx.scene.control.ContextMenu; @@ -58,6 +60,7 @@ import javafx.scene.control.Tooltip; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.util.Callback; import javax.swing.Action; @@ -98,6 +101,9 @@ class ListTimeline extends BorderPane { */ private static final Callback, ObservableValue> CELL_VALUE_FACTORY = param -> new SimpleObjectProperty<>(param.getValue()); + @FXML + private HBox navControls; + @FXML private ComboBox scrollInrementComboBox; @@ -286,6 +292,10 @@ class ListTimeline extends BorderPane { table.requestFocus(); } + List getNavControls() { + return Collections.singletonList(navControls); + } + /** * TableCell to show the (sub) type of an event. */ diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java index 06cba98a68..d386578964 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListViewPane.java @@ -23,9 +23,9 @@ import java.util.List; import javafx.application.Platform; import javafx.beans.Observable; import javafx.concurrent.Task; -import javafx.scene.Parent; import org.joda.time.Interval; import org.sleuthkit.autopsy.timeline.TimeLineController; +import org.sleuthkit.autopsy.timeline.ViewMode; import org.sleuthkit.autopsy.timeline.datamodel.CombinedEvent; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.ui.AbstractTimeLineView; @@ -48,7 +48,7 @@ public class ListViewPane extends AbstractTimeLineView { //initialize chart; setCenter(listTimeline); - setSettingsNodes(new ListViewPane.ListViewSettingsPane().getChildrenUnmodifiable()); + setSettingsNodes(listTimeline.getNavControls()); //keep controller's list of selected event IDs in sync with this list's listTimeline.getSelectedEventIDs().addListener((Observable selectedIDs) -> { @@ -66,9 +66,13 @@ public class ListViewPane extends AbstractTimeLineView { listTimeline.clear(); } - private static class ListViewSettingsPane extends Parent { + @Override + final protected ViewMode getViewMode() { + return ViewMode.LIST; } + + private class ListUpdateTask extends ViewRefreshTask { ListUpdateTask() { From b8714bf87115188f57d9ac7818ba786061c9ee4f Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 31 May 2016 17:02:43 -0400 Subject: [PATCH 18/39] simplified swapping nodes/controls for different views; broekn implementation of jump to next (year/day/mont/etc) --- .../autopsy/timeline/ui/ViewFrame.java | 65 ++++++------------- .../timeline/ui/listvew/ListTimeline.fxml | 14 ++-- .../timeline/ui/listvew/ListTimeline.java | 37 +++++++++-- 3 files changed, 60 insertions(+), 56 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/ViewFrame.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/ViewFrame.java index b427b26be2..be28b2adb0 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/ViewFrame.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/ViewFrame.java @@ -587,8 +587,7 @@ final public class ViewFrame extends BorderPane { * AbstractTimelineView for one of the correct type. */ private void syncViewMode() { - AbstractTimeLineView view; - ViewMode viewMode = controller.viewModeProperty().get(); + ViewMode newViewMode = controller.getViewMode(); Platform.runLater(() -> { //clear out old view. @@ -607,60 +606,38 @@ final public class ViewFrame extends BorderPane { } hostedView.dispose(); } - }); - //make new view. - switch (viewMode) { - case LIST: - view = new ListViewPane(controller); - Platform.runLater(() -> { + //Set a new AbstractTimeLineView as the one hosted by this ViewFrame. + switch (newViewMode) { + case LIST: + hostedView = new ListViewPane(controller); listToggle.setSelected(true); + timeRangeToolBar.getItems().removeAll(zoomInOutHBox, zoomMenuButton); + timeRangeToolBar.getItems().addAll(2, hostedView.getSettingsNodes()); //TODO: should remove listeners from events tree - }); - break; - case COUNTS: - view = new CountsViewPane(controller); - Platform.runLater(() -> { + break; + case COUNTS: + hostedView = new CountsViewPane(controller); countsToggle.setSelected(true); + toolBar.getItems().addAll(2, hostedView.getSettingsNodes()); //TODO: should remove listeners from events tree - }); - break; - case DETAIL: - DetailViewPane detailViewPane = new DetailViewPane(controller); - Platform.runLater(() -> { + break; + case DETAIL: + DetailViewPane detailViewPane = new DetailViewPane(controller); + hostedView = detailViewPane; detailsToggle.setSelected(true); + toolBar.getItems().addAll(2, hostedView.getSettingsNodes()); + detailViewPane.setHighLightedEvents(eventsTree.getSelectedEvents()); eventsTree.setDetailViewPane(detailViewPane); - }); - view = detailViewPane; - break; - default: - throw new IllegalArgumentException("Unknown ViewMode: " + viewMode.toString()); - } - - //Set the new AbstractTimeLineView as the one hosted by this ViewFrame. - Platform.runLater(() -> { - - hostedView = view; + break; + default: + throw new IllegalArgumentException("Unknown ViewMode: " + newViewMode.toString()); + } //setup new view. ActionUtils.configureButton(new Refresh(), refreshButton);//configure new refresh action for new view hostedView.refresh(); - - switch (hostedView.getViewMode()) { - case COUNTS: - case DETAIL: - toolBar.getItems().addAll(2, hostedView.getSettingsNodes()); - break; - case LIST: - timeRangeToolBar.getItems().removeAll(zoomInOutHBox, zoomMenuButton); - timeRangeToolBar.getItems().addAll(2, hostedView.getSettingsNodes()); - break; - default: - throw new UnsupportedOperationException("Unknown ViewMode: " + hostedView.getViewMode()); - } - notificationPane.setContent(hostedView); - //listen to has events property and show "dialog" if it is false. hostedView.hasVisibleEventsProperty().addListener(hasEvents -> { notificationPane.setContent(hostedView.hasVisibleEvents() diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.fxml b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.fxml index 2a4798740b..d8d0c7673e 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.fxml +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/listvew/ListTimeline.fxml @@ -19,11 +19,11 @@