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=