diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index 8209da0221..5e07fadf28 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -75,7 +75,7 @@ file.reference.javax.ws.rs-api-2.0.1.jar=release/modules/ext/javax.ws.rs-api-2.0 file.reference.cxf-core-3.0.16.jar=release/modules/ext/cxf-core-3.0.16.jar file.reference.cxf-rt-frontend-jaxrs-3.0.16.jar=release/modules/ext/cxf-rt-frontend-jaxrs-3.0.16.jar file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-transports-http-3.0.16.jar -file.reference.sleuthkit-postgresql-4.6.6.jar=release/modules/ext/sleuthkit-postgresql-4.6.6.jar +file.reference.sleuthkit-postgresql-4.6.7.jar=release/modules/ext/sleuthkit-postgresql-4.6.7.jar file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar file.reference.curator-framework-2.8.0.jar=release/modules/ext/curator-framework-2.8.0.jar file.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0.jar diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 3dbc3069e3..967399cc20 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -482,8 +482,8 @@ release\modules\ext\jmatio-1.5.jar - ext/sleuthkit-postgresql-4.6.6.jar - release/modules/ext/sleuthkit-postgresql-4.6.6.jar + ext/sleuthkit-postgresql-4.6.7.jar + release/modules/ext/sleuthkit-postgresql-4.6.7.jar ext/tika-parsers-1.20.jar diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OccurrencePanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OccurrencePanel.java index d8b18d5f82..36877a124d 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OccurrencePanel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OccurrencePanel.java @@ -175,7 +175,7 @@ final class OccurrencePanel extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(knownStatusLabel, Bundle.OccurrencePanel_commonPropertyKnownStatusLabel_text()); addItemToBag(gridY, 0, 0, 0, knownStatusLabel); javax.swing.JLabel knownStatusValue = new javax.swing.JLabel(); - knownStatusValue.setText(knownStatus.toString()); + knownStatusValue.setText(knownStatus.getName()); if (knownStatus == TskData.FileKnown.BAD) { knownStatusValue.setForeground(Color.RED); } diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form index 2a656008c2..1aba67e76c 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form @@ -66,7 +66,7 @@ - + @@ -95,7 +95,7 @@ - + @@ -464,7 +464,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java index 5ba6b9b89a..76c2f189ad 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java @@ -53,6 +53,7 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.ingest.IngestManager; +import static org.sleuthkit.autopsy.ingest.IngestManager.IngestJobEvent.COMPLETED; import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.DATA_ADDED; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.Account; @@ -63,6 +64,7 @@ import org.sleuthkit.datamodel.CommunicationsFilter.AccountTypeFilter; import org.sleuthkit.datamodel.CommunicationsFilter.DateRangeFilter; import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter; import org.sleuthkit.datamodel.CommunicationsFilter.MostRecentFilter; +import org.sleuthkit.datamodel.CommunicationsManager; import org.sleuthkit.datamodel.DataSource; import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG; import static org.sleuthkit.datamodel.Relationship.Type.CONTACT; @@ -96,9 +98,10 @@ final public class FiltersPanel extends JPanel { * Listens to ingest events to enable refresh button */ private final PropertyChangeListener ingestListener; + private final PropertyChangeListener ingestJobListener; /** - * Flag that indicates the UI is not up-sto-date with respect to the case DB + * Flag that indicates the UI is not up-to-date with respect to the case DB * and it should be refreshed (by reapplying the filters). */ private boolean needsRefresh; @@ -123,6 +126,11 @@ final public class FiltersPanel extends JPanel { @NbBundle.Messages({"refreshText=Refresh Results", "applyText=Apply"}) public FiltersPanel() { initComponents(); + + CheckBoxIconPanel panel = createAccoutTypeCheckBoxPanel(Account.Type.DEVICE, true); + accountTypeMap.put(Account.Type.DEVICE, panel.getCheckBox()); + accountTypeListPane.add(panel); + deviceRequiredLabel.setVisible(false); accountTypeRequiredLabel.setVisible(false); startDatePicker.setDate(LocalDate.now().minusWeeks(3)); @@ -155,18 +163,30 @@ final public class FiltersPanel extends JPanel { // Indicate that a refresh may be needed, unless the data added is Keyword or Hashset hits ModuleDataEvent eventData = (ModuleDataEvent) pce.getOldValue(); if (null != eventData - && eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() - && eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { - updateFilters(false); + && (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() + || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID() + || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() + || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID())) + { + updateFilters(true); + needsRefresh = true; + validateFilters(); + } + } + }; + + this.ingestJobListener = pce -> { + String eventType = pce.getPropertyName(); + if (eventType.equals(COMPLETED.toString()) && + updateFilters(true)) { + needsRefresh = true; validateFilters(); - } } }; applyFiltersButton.addActionListener(e -> applyFilters()); refreshButton.addActionListener(e -> applyFilters()); - } /** @@ -219,19 +239,26 @@ final public class FiltersPanel extends JPanel { /** * Updates the filter widgets to reflect he data sources/types in the case. */ - private void updateFilters(boolean initialState) { - updateAccountTypeFilter(); - updateDeviceFilter(initialState); + private boolean updateFilters(boolean initialState) { + boolean newAccountType = updateAccountTypeFilter(initialState); + boolean newDeviceFilter = updateDeviceFilter(initialState); + + // both or either are true, return true; + return newAccountType || newDeviceFilter; } @Override public void addNotify() { super.addNotify(); IngestManager.getInstance().addIngestModuleEventListener(ingestListener); + IngestManager.getInstance().addIngestJobEventListener(ingestJobListener); Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> { //clear the device filter widget when the case changes. devicesMap.clear(); devicesListPane.removeAll(); + + accountTypeMap.clear(); + accountTypeListPane.removeAll(); }); } @@ -239,64 +266,107 @@ final public class FiltersPanel extends JPanel { public void removeNotify() { super.removeNotify(); IngestManager.getInstance().removeIngestModuleEventListener(ingestListener); + IngestManager.getInstance().removeIngestJobEventListener(ingestJobListener); } /** * Populate the Account Types filter widgets + * + * @param selected the initial value for the account type checkbox + * + * @return True, if a new accountType was found */ - private void updateAccountTypeFilter() { - - //TODO: something like this commented code could be used to show only - //the account types that are found: - //final CommunicationsManager communicationsManager = Case.getCurrentOpenCase().getSleuthkitCase().getCommunicationsManager(); - //List accountTypesInUse = communicationsManager.getAccountTypesInUse(); - //accountTypesInUSe.forEach(...) - Account.Type.PREDEFINED_ACCOUNT_TYPES.forEach(type -> { - if (type.equals(Account.Type.CREDIT_CARD)) { - //don't show a check box for credit cards - } else { - accountTypeMap.computeIfAbsent(type, t -> { - - CheckBoxIconPanel panel = new CheckBoxIconPanel( - type.getDisplayName(), - new ImageIcon(FiltersPanel.class.getResource(Utils.getIconFilePath(type)))); - panel.setSelected(true); - panel.addItemListener(validationListener); + private boolean updateAccountTypeFilter(boolean selected) { + boolean newOneFound = false; + try { + final CommunicationsManager communicationsManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); + List accountTypesInUse = communicationsManager.getAccountTypesInUse(); + + for (Account.Type type : accountTypesInUse) { + + if (!accountTypeMap.containsKey(type) && !type.equals(Account.Type.CREDIT_CARD)) { + CheckBoxIconPanel panel = createAccoutTypeCheckBoxPanel(type, selected); + accountTypeMap.put(type, panel.getCheckBox()); accountTypeListPane.add(panel); - if (t.equals(Account.Type.DEVICE)) { - //Deveice type filter is enabled based on whether we are in table or graph view. - panel.setEnabled(deviceAccountTypeEnabled); - } - return panel.getCheckBox(); - }); + + newOneFound = true; + } } - }); + + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Unable to update to update Account Types Filter", ex); + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "A case is required to update the account types filter.", ex); + } + + if (newOneFound) { + accountTypeListPane.revalidate(); + } + + return newOneFound; + } + + /** + * Helper function to create a new instance of the CheckBoxIconPanel base on + * the Account.Type and initalState (check box state). + * + * @param type Account.Type to display on the panel + * @param initalState initial check box state + * + * @return instance of the CheckBoxIconPanel + */ + private CheckBoxIconPanel createAccoutTypeCheckBoxPanel(Account.Type type, boolean initalState) { + CheckBoxIconPanel panel = new CheckBoxIconPanel( + type.getDisplayName(), + new ImageIcon(FiltersPanel.class.getResource(Utils.getIconFilePath(type)))); + + panel.setSelected(initalState); + panel.addItemListener(validationListener); + if (type.equals(Account.Type.DEVICE)) { + //Deveice type filter is enabled based on whether we are in table or graph view. + panel.setEnabled(deviceAccountTypeEnabled); + } + + return panel; } /** * Populate the devices filter widgets * - * @param initialState + * @param selected Sets the initial state of device check box + * + * @return true if a new device was found */ - private void updateDeviceFilter(boolean initialState) { + private boolean updateDeviceFilter(boolean selected) { + boolean newOneFound = false; try { final SleuthkitCase sleuthkitCase = Case.getCurrentCaseThrows().getSleuthkitCase(); for (DataSource dataSource : sleuthkitCase.getDataSources()) { String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName(); - //store the device id in the map, but display a datasource name in the UI. - devicesMap.computeIfAbsent(dataSource.getDeviceId(), ds -> { - final JCheckBox jCheckBox = new JCheckBox(dsName, initialState); - jCheckBox.addItemListener(validationListener); - devicesListPane.add(jCheckBox); - return jCheckBox; - }); + if(devicesMap.containsKey(dataSource.getDeviceId())) { + continue; + } + + final JCheckBox jCheckBox = new JCheckBox(dsName, selected); + jCheckBox.addItemListener(validationListener); + devicesListPane.add(jCheckBox); + devicesMap.put(dataSource.getDeviceId(), jCheckBox); + + newOneFound = true; + } } catch (NoCurrentCaseException ex) { logger.log(Level.INFO, "Filter update cancelled. Case is closed."); } catch (TskCoreException tskCoreException) { logger.log(Level.SEVERE, "There was a error loading the datasources for the case.", tskCoreException); } + + if(newOneFound) { + devicesListPane.revalidate(); + } + + return newOneFound; } /** @@ -319,7 +389,7 @@ final public class FiltersPanel extends JPanel { } /** - * Sets the state of the device filter checkboxes + * Sets the state of the device filter check boxes * * @param deviceFilter Selected devices */ @@ -366,6 +436,12 @@ final public class FiltersPanel extends JPanel { endDatePicker.setEnabled(state.isEnabled()); } + /** + * Sets the state of the most recent UI controls based on the current values + * in MostRecentFilter. + * + * @param filter The MostRecentFilter state to be set + */ private void setMostRecentFilter(MostRecentFilter filter) { int limit = filter.getLimit(); if(limit > 0) { @@ -424,6 +500,7 @@ final public class FiltersPanel extends JPanel { gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; + gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 5); topPane.add(applyFiltersButton, gridBagConstraints); needsRefreshLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.needsRefreshLabel.text")); // NOI18N @@ -697,7 +774,7 @@ final public class FiltersPanel extends JPanel { accountTypesScrollPane.setPreferredSize(new java.awt.Dimension(2, 200)); - accountTypeListPane.setLayout(new javax.swing.BoxLayout(accountTypeListPane, javax.swing.BoxLayout.Y_AXIS)); + accountTypeListPane.setLayout(new javax.swing.BoxLayout(accountTypeListPane, javax.swing.BoxLayout.PAGE_AXIS)); accountTypesScrollPane.setViewportView(accountTypeListPane); gridBagConstraints = new java.awt.GridBagConstraints(); @@ -740,6 +817,7 @@ final public class FiltersPanel extends JPanel { gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; + gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 0); add(scrollPane, gridBagConstraints); }// //GEN-END:initComponents @@ -808,6 +886,11 @@ final public class FiltersPanel extends JPanel { endCheckBox.isSelected() ? endDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0); } + /** + * Get a MostRecentFilter that based on the current state of the ui controls. + * + * @return A new instance of MostRecentFilter + */ private MostRecentFilter getMostRecentFilter() { String value = (String)limitComboBox.getSelectedItem(); if(value.trim().equalsIgnoreCase("all")){ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/nail.png b/Core/src/org/sleuthkit/autopsy/communications/images/nail.png new file mode 100755 index 0000000000..f10f365a10 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/nail.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/screw.png b/Core/src/org/sleuthkit/autopsy/communications/images/screw.png new file mode 100755 index 0000000000..ec8d434e25 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/screw.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/threaded.png b/Core/src/org/sleuthkit/autopsy/communications/images/threaded.png new file mode 100755 index 0000000000..449f6bad6c Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/threaded.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/images/unthreaded.png b/Core/src/org/sleuthkit/autopsy/communications/images/unthreaded.png new file mode 100755 index 0000000000..e66695ea88 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/communications/images/unthreaded.png differ diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties b/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties index 4970a5958e..970f5474a4 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties @@ -11,5 +11,13 @@ SummaryViewer.emailDataLabel.text=emails SummaryViewer.attachmentsDataLabel.text=attachments SummaryViewer.messagesLabel.text=Messages: SummaryViewer.callLogsLabel.text=Call Logs: +ThreadRootMessagePanel.showAllCheckBox.text=Show All Messages +ThreadPane.backButton.text=<--- SummaryViewer.caseReferencesPanel.border.title=Other Occurrences SummaryViewer.fileReferencesPanel.border.title=File References in Current Case +MessageViewer.threadsLabel.text=Select a Thread to View +MessageViewer.threadNameLabel.text= +MessageViewer.showingMessagesLabel.text=Showing Messages for Thread: +MessageViewer.backButton.AccessibleContext.accessibleDescription= +MessageViewer.backButton.text=Threads +MessageViewer.showAllButton.text=All Messages diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties-MERGED index 162cf1982f..9b01fc653b 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties-MERGED @@ -19,12 +19,16 @@ MessageNode_Node_Property_Subject=Subject MessageNode_Node_Property_To=To MessageNode_Node_Property_Type=Type MessageViewer_columnHeader_Attms=Attachments -MessageViewer_columnHeader_Date=Date +MessageViewer_columnHeader_Date=Data +MessageViewer_columnHeader_EarlyDate=Earliest Message MessageViewer_columnHeader_From=From MessageViewer_columnHeader_Subject=Subject MessageViewer_columnHeader_To=To MessageViewer_no_messages= MessageViewer_tabTitle=Messages +MessageViewer_viewMessage_all=All +MessageViewer_viewMessage_selected=Selected +MessageViewer_viewMessage_unthreaded=Unthreaded SummaryViewer.countsPanel.border.title=Counts SummaryViewer.emailLabel.text=Emails: SummaryViewer.contactsLabel.text=Contacts: @@ -37,11 +41,19 @@ SummaryViewer.emailDataLabel.text=emails SummaryViewer.attachmentsDataLabel.text=attachments SummaryViewer.messagesLabel.text=Messages: SummaryViewer.callLogsLabel.text=Call Logs: -SummaryViewer.caseReferencesPanel.border.title=Other Occurrences -SummaryViewer.fileReferencesPanel.border.title=File References in Current Case SummaryViewer_CaseRefNameColumn_Title=Case Name SummaryViewer_CentralRepository_Message= SummaryViewer_Creation_Date_Title=Creation Date SummaryViewer_FileRefNameColumn_Title=Path SummaryViewer_TabTitle=Summary SummeryViewer_FileRef_Message=