From 1bcb510a1db3409526949eb52a77f1ba0c87500a Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 7 Jun 2019 10:09:10 -0400 Subject: [PATCH 01/16] Commit to save while I go work on something else --- .../relationships/Bundle.properties | 10 + .../relationships/Bundle.properties-MERGED | 17 +- .../relationships/ContactDetailsPane.form | 39 +- .../relationships/ContactDetailsPane.java | 44 +- .../ContactsChildNodeFactory.java | 2 +- .../relationships/MessageNode.java | 26 +- .../relationships/MessageViewer.form | 189 +++++++ .../relationships/MessageViewer.java | 481 ++++++++++++++++++ .../MessagesChildNodeFactory.java | 78 ++- .../relationships/MessagesPanel.form | 51 ++ ...MessagesViewer.java => MessagesPanel.java} | 131 ++--- .../relationships/MessagesViewer.form | 42 -- .../relationships/OutlineViewPanel.form | 5 - .../relationships/OutlineViewPanel.java | 2 - .../relationships/RelationshipBrowser.java | 11 +- .../relationships/ThreadChildNodeFactory.java | 200 ++++++++ .../directorytree/DataResultFilterNode.java | 6 + .../keywordsearch/Bundle.properties-MERGED | 2 +- .../recentactivity/Bundle.properties-MERGED | 2 +- 19 files changed, 1103 insertions(+), 235 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.form create mode 100755 Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java create mode 100755 Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.form rename Core/src/org/sleuthkit/autopsy/communications/relationships/{MessagesViewer.java => MessagesPanel.java} (59%) delete mode 100755 Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.form create mode 100755 Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties b/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties index 4970a5958e..4adb9e4b8c 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties @@ -11,5 +11,15 @@ 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=Threads +MessageViewer.threadNameLabel.text= +MessageViewer.showingMessagesLabel.text=Showing Messages for Thread: +MessageViewer.messagesLabel.text=Messages +MessageViewer.backButton.AccessibleContext.accessibleDescription= +MessageViewer.backButton.text= +MessageViewer.showMessagesButton.text= +MessageViewer.viewMessageLabel.text=View 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 b31598dbc6..7eed716c86 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/Bundle.properties-MERGED @@ -25,6 +25,9 @@ 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,10 +40,20 @@ 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 +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=Threads +MessageViewer.threadNameLabel.text= +MessageViewer.showingMessagesLabel.text=Showing Messages for Thread: +MessageViewer.messagesLabel.text=Messages +MessageViewer.backButton.AccessibleContext.accessibleDescription= +MessageViewer.backButton.text= +MessageViewer.showMessagesButton.text= +MessageViewer.viewMessageLabel.text=View Messages: diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactDetailsPane.form b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactDetailsPane.form index 2ae2165358..671fac333e 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactDetailsPane.form +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactDetailsPane.form @@ -17,34 +17,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -55,11 +28,21 @@ + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactDetailsPane.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactDetailsPane.java index 82d4668e43..ae456e0abb 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactDetailsPane.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactDetailsPane.java @@ -73,38 +73,36 @@ public final class ContactDetailsPane extends javax.swing.JPanel implements Expl @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { + java.awt.GridBagConstraints gridBagConstraints; messageContentViewer1 = new org.sleuthkit.autopsy.contentviewers.MessageContentViewer(); nameLabel = new javax.swing.JLabel(); propertySheet = new org.openide.explorer.propertysheet.PropertySheet(); + setLayout(new java.awt.GridBagLayout()); + nameLabel.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(ContactDetailsPane.class, "ContactDetailsPane.nameLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(16, 15, 15, 15); + add(nameLabel, gridBagConstraints); propertySheet.setDescriptionAreaVisible(false); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(propertySheet, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addComponent(nameLabel) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(nameLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(propertySheet, javax.swing.GroupLayout.DEFAULT_SIZE, 283, Short.MAX_VALUE) - .addContainerGap()) - ); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.weighty = 1.0; + gridBagConstraints.insets = new java.awt.Insets(9, 15, 16, 15); + add(propertySheet, gridBagConstraints); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsChildNodeFactory.java index 681a572b96..07f98c613b 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsChildNodeFactory.java @@ -36,7 +36,7 @@ import org.sleuthkit.datamodel.TskCoreException; * ChildFactory for ContactNodes. */ final class ContactsChildNodeFactory extends ChildFactory{ - private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName()); + private static final Logger logger = Logger.getLogger(ContactsChildNodeFactory.class.getName()); private SelectionInfo selectionInfo; diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java index e6ac3f507f..4a3f88ad8d 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.communications.relationships; import java.util.List; import java.util.TimeZone; import java.util.logging.Level; +import javax.swing.Action; import org.apache.commons.lang3.StringUtils; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; @@ -48,16 +49,26 @@ import org.sleuthkit.autopsy.communications.Utils; /** * Wraps a BlackboardArtifact as an AbstractNode for use in an OutlookView */ -final class MessageNode extends BlackboardArtifactNode { +class MessageNode extends BlackboardArtifactNode { + public static final String UNTHREADED_ID = ""; + private static final Logger logger = Logger.getLogger(MessageNode.class.getName()); + + private final String threadID; + + private final Action preferredAction; - MessageNode(BlackboardArtifact artifact) { + MessageNode(BlackboardArtifact artifact, String threadID, Action preferredAction) { super(artifact); + + this.preferredAction = preferredAction; final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s"); // NON-NLS String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message"); // NON-NLS setDisplayName(removeEndIgnoreCase.isEmpty() ? stripEnd : removeEndIgnoreCase); + + this.threadID = threadID; } @Messages({ @@ -112,6 +123,8 @@ final class MessageNode extends BlackboardArtifactNode { } catch (TskCoreException ex) { logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS } + + sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",threadID == null ? "" : threadID)); //NON-NLS break; case TSK_MESSAGE: @@ -183,4 +196,13 @@ final class MessageNode extends BlackboardArtifactNode { public String getSourceName() { return getDisplayName(); } + + String getThreadID() { + return threadID; + } + + @Override + public Action getPreferredAction() { + return preferredAction; + } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.form b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.form new file mode 100755 index 0000000000..a6d0ddfa45 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.form @@ -0,0 +1,189 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java new file mode 100755 index 0000000000..3da19c0d83 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java @@ -0,0 +1,481 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 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.communications.relationships; + +import java.awt.CardLayout; +import java.awt.Component; +import java.awt.KeyboardFocusManager; +import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.logging.Level; +import javax.swing.AbstractAction; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import static javax.swing.SwingUtilities.isDescendingFrom; +import org.netbeans.swing.outline.DefaultOutlineModel; +import org.netbeans.swing.outline.Outline; +import org.openide.explorer.ExplorerManager; +import static org.openide.explorer.ExplorerUtils.createLookup; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.nodes.Node.Property; +import org.openide.nodes.Node.PropertySet; +import org.openide.util.Lookup; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.communications.ModifiableProxyLookup; +import org.sleuthkit.autopsy.corecomponents.TableFilterNode; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; + + +/** + * + * + */ +public class MessageViewer extends JPanel implements RelationshipsViewer{ + + private static final Logger logger = Logger.getLogger(MessageViewer.class.getName()); + + private final ModifiableProxyLookup proxyLookup; + private final PropertyChangeListener focusPropertyListener; + private final ThreadChildNodeFactory rootMessageFactory; + private final MessagesChildNodeFactory threadMessageNodeFactory; + + private SelectionInfo currentSelectionInfo = null; + + OutlineViewPanel currentPanel; + + @Messages({ + "MessageViewer_tabTitle=Messages", + "MessageViewer_columnHeader_From=From", + "MessageViewer_columnHeader_To=To", + "MessageViewer_columnHeader_Date=Date", + "MessageViewer_columnHeader_Subject=Subject", + "MessageViewer_columnHeader_Attms=Attachments", + "MessageViewer_no_messages=", + "MessageViewer_viewMessage_all=All", + "MessageViewer_viewMessage_selected=Selected", + "MessageViewer_viewMessage_unthreaded=Unthreaded", + }) + + + + /** + * Creates new form MessageViewer2 + */ + public MessageViewer() { + + initComponents(); + currentPanel = rootTablePane; + proxyLookup = new ModifiableProxyLookup(createLookup(rootTablePane.getExplorerManager(), getActionMap())); + rootMessageFactory = new ThreadChildNodeFactory(new ShowThreadMessagesAction()); + threadMessageNodeFactory = new MessagesChildNodeFactory(); + + // See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed + // explaination of focusPropertyListener + focusPropertyListener = (final PropertyChangeEvent focusEvent) -> { + if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) { + final Component newFocusOwner = (Component) focusEvent.getNewValue(); + + if (newFocusOwner == null) { + return; + } + if (isDescendingFrom(newFocusOwner, rootTablePane)) { + proxyLookup.setNewLookups(createLookup(rootTablePane.getExplorerManager(), getActionMap())); + } else if (isDescendingFrom(newFocusOwner, MessageViewer.this)) { + proxyLookup.setNewLookups(createLookup(currentPanel.getExplorerManager(), getActionMap())); + } + } + }; + + + rootTablePane.getExplorerManager().setRootContext( + new TableFilterNode( + new DataResultFilterNode( + new AbstractNode( + Children.create(rootMessageFactory, true)), + rootTablePane.getExplorerManager()), + true)); + + Outline outline = rootTablePane.getOutlineView().getOutline(); + rootTablePane.getOutlineView().setPropertyColumns( + "From", Bundle.MessageViewer_columnHeader_From(), + "To", Bundle.MessageViewer_columnHeader_To(), + "Date", Bundle.MessageViewer_columnHeader_Date(), + "Subject", Bundle.MessageViewer_columnHeader_Subject(), + "Attms", Bundle.MessageViewer_columnHeader_Attms() + ); + outline.setRootVisible(false); + ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel("Type"); + + + rootTablePane.getExplorerManager().addPropertyChangeListener((PropertyChangeEvent evt) -> { + if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) { + final Node[] nodes = rootTablePane.getExplorerManager().getSelectedNodes(); + + switch((VIEW_MESSAGE_TYPE)viewMessageComboBox.getSelectedItem()) { + case ALL: + showMessagesButton.setEnabled((nodes != null && nodes.length > 0)); + break; + case SELECTED: + showMessagesButton.setEnabled((nodes != null && nodes.length == 1)); + break; + } + } + }); + + threadMessagesPanel.setChildFactory(threadMessageNodeFactory); + + this.viewMessageComboBox.addItem(VIEW_MESSAGE_TYPE.SELECTED); + this.viewMessageComboBox.addItem(VIEW_MESSAGE_TYPE.ALL); + } + + @Override + public String getDisplayName() { + return Bundle.MessageViewer_tabTitle(); + } + + @Override + public JPanel getPanel() { + return this; + } + + @Override + public void setSelectionInfo(SelectionInfo info) { + currentSelectionInfo = info; + + currentPanel = rootTablePane; + + CardLayout layout = (CardLayout) this.getLayout(); + layout.show(this, "threads"); + + rootMessageFactory.refresh(info); + } + + @Override + public Lookup getLookup() { + return proxyLookup; + } + + @Override + public void addNotify() { + super.addNotify(); + //add listener that maintains correct selection in the Global Actions Context + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .addPropertyChangeListener("focusOwner", focusPropertyListener); + } + + @Override + public void removeNotify() { + super.removeNotify(); + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .removePropertyChangeListener("focusOwner", focusPropertyListener); + } + + private void showMessages() { + VIEW_MESSAGE_TYPE viewType = (VIEW_MESSAGE_TYPE)viewMessageComboBox.getSelectedItem(); + switch((VIEW_MESSAGE_TYPE)viewMessageComboBox.getSelectedItem()){ + case ALL: + threadMessageNodeFactory.refresh(currentSelectionInfo, null); + threadNameLabel.setText("All Messages"); + + ((CardLayout)getLayout()).show(this, "messages"); + break; + case SELECTED: + showSelectedThread(); + break; + } + } + + @SuppressWarnings("rawtypes") + private void showSelectedThread() { + final Node[] nodes = rootTablePane.getExplorerManager().getSelectedNodes(); + + if(nodes == null) { + return; + } + + if(nodes.length == 0 || nodes.length > 1) { + return; + } + + ArrayList threadIDList = new ArrayList<>(); + String subject = ""; + + PropertySet[] propertySets = nodes[0].getPropertySets(); + for(PropertySet pset: propertySets) { + Property[] properties = pset.getProperties(); + for(Property prop: properties) { + if(prop.getName().equalsIgnoreCase("threadid")){ + try { + String threadID = prop.getValue().toString(); + if(!threadIDList.contains(threadID)){ + threadIDList.add(threadID); + } + } catch (IllegalAccessException | InvocationTargetException ex) { + logger.log(Level.WARNING, String.format("Unable to get threadid for node: %s", nodes[0].getDisplayName()), ex); + } + } else if(prop.getName().equalsIgnoreCase("subject")) { + try { + subject = prop.getValue().toString(); + } catch (IllegalAccessException | InvocationTargetException ex) { + logger.log(Level.WARNING, String.format("Unable to get subject for node: %s", nodes[0].getDisplayName()), ex); + subject = ""; + } + } + } + + } + + if(!threadIDList.isEmpty()) { + threadMessageNodeFactory.refresh(currentSelectionInfo, threadIDList); + + if(!subject.isEmpty()){ + threadNameLabel.setText(subject); + } + // Come back and put involk later for safety. + CardLayout layout = (CardLayout)getLayout(); + layout.show(this, "messages"); + } + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor.' + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + java.awt.GridBagConstraints gridBagConstraints; + + rootMessagesPane = new javax.swing.JPanel(); + rootTablePane = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel(); + threadsLabel = new javax.swing.JLabel(); + viewMessageComboBox = new javax.swing.JComboBox<>(); + viewMessageLabel = new javax.swing.JLabel(); + showMessagesButton = new javax.swing.JButton(); + messagePanel = new javax.swing.JPanel(); + threadMessagesPanel = new MessagesPanel(); + backButton = new javax.swing.JButton(); + messagesLabel = new javax.swing.JLabel(); + showingMessagesLabel = new javax.swing.JLabel(); + threadNameLabel = new javax.swing.JLabel(); + + setLayout(new java.awt.CardLayout()); + + rootMessagesPane.setOpaque(false); + rootMessagesPane.setLayout(new java.awt.GridBagLayout()); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 4; + gridBagConstraints.gridwidth = 4; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weighty = 1.0; + gridBagConstraints.insets = new java.awt.Insets(5, 15, 15, 15); + rootMessagesPane.add(rootTablePane, gridBagConstraints); + + threadsLabel.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(threadsLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.threadsLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridheight = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(15, 15, 0, 0); + rootMessagesPane.add(threadsLabel, gridBagConstraints); + + viewMessageComboBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + viewMessageComboBoxActionPerformed(evt); + } + }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 2; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridheight = 4; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 0); + rootMessagesPane.add(viewMessageComboBox, gridBagConstraints); + + org.openide.awt.Mnemonics.setLocalizedText(viewMessageLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.viewMessageLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridheight = 2; + gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; + gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 5); + rootMessagesPane.add(viewMessageLabel, gridBagConstraints); + + showMessagesButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/timeline/images/btn_step_forward.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(showMessagesButton, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.showMessagesButton.text")); // NOI18N + showMessagesButton.setBorder(null); + showMessagesButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + showMessagesButtonActionPerformed(evt); + } + }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 3; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(15, 5, 0, 15); + rootMessagesPane.add(showMessagesButton, gridBagConstraints); + + add(rootMessagesPane, "threads"); + + messagePanel.setLayout(new java.awt.GridBagLayout()); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 3; + gridBagConstraints.gridwidth = 5; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.weighty = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 15, 0, 15); + messagePanel.add(threadMessagesPanel, gridBagConstraints); + + backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/timeline/images/btn_step_back.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.backButton.text")); // NOI18N + backButton.setBorder(null); + backButton.setBorderPainted(false); + backButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + backButtonActionPerformed(evt); + } + }); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(16, 15, 0, 0); + messagePanel.add(backButton, gridBagConstraints); + backButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.backButton.AccessibleContext.accessibleDescription")); // NOI18N + + messagesLabel.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(messagesLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.messagesLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(5, 15, 0, 0); + messagePanel.add(messagesLabel, gridBagConstraints); + + org.openide.awt.Mnemonics.setLocalizedText(showingMessagesLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.showingMessagesLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 2; + gridBagConstraints.gridwidth = 3; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.insets = new java.awt.Insets(5, 15, 5, 0); + messagePanel.add(showingMessagesLabel, gridBagConstraints); + + org.openide.awt.Mnemonics.setLocalizedText(threadNameLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.threadNameLabel.text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 3; + gridBagConstraints.gridy = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 15); + messagePanel.add(threadNameLabel, gridBagConstraints); + + add(messagePanel, "messages"); + }// //GEN-END:initComponents + + private void backButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backButtonActionPerformed + CardLayout layout = (CardLayout) this.getLayout(); + layout.show(this, "threads"); + }//GEN-LAST:event_backButtonActionPerformed + + private void showMessagesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showMessagesButtonActionPerformed + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + showMessages(); + } + }); + }//GEN-LAST:event_showMessagesButtonActionPerformed + + private void viewMessageComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewMessageComboBoxActionPerformed + boolean accountSelected = (currentSelectionInfo != null && currentSelectionInfo.getAccounts() != null && !currentSelectionInfo.getAccounts().isEmpty()); + switch((VIEW_MESSAGE_TYPE)viewMessageComboBox.getSelectedItem()) { + case ALL: + showMessagesButton.setEnabled(accountSelected); + break; + case SELECTED: + Node[] selected = rootTablePane.getExplorerManager().getSelectedNodes(); + showMessagesButton.setEnabled(selected != null && selected.length == 1); + break; + } + }//GEN-LAST:event_viewMessageComboBoxActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton backButton; + private javax.swing.JPanel messagePanel; + private javax.swing.JLabel messagesLabel; + private javax.swing.JPanel rootMessagesPane; + private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel rootTablePane; + private javax.swing.JButton showMessagesButton; + private javax.swing.JLabel showingMessagesLabel; + private org.sleuthkit.autopsy.communications.relationships.MessagesPanel threadMessagesPanel; + private javax.swing.JLabel threadNameLabel; + private javax.swing.JLabel threadsLabel; + private javax.swing.JComboBox viewMessageComboBox; + private javax.swing.JLabel viewMessageLabel; + // End of variables declaration//GEN-END:variables + + class ShowThreadMessagesAction extends AbstractAction { + @Override + public void actionPerformed(ActionEvent e) { + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + showSelectedThread(); + } + }); + } + } + + private enum VIEW_MESSAGE_TYPE{ + ALL(Bundle.MessageViewer_viewMessage_all()), + SELECTED(Bundle.MessageViewer_viewMessage_selected()); + + private final String displayLabel; + VIEW_MESSAGE_TYPE(String label) { + displayLabel = label; + } + + @Override + public String toString() { + return displayLabel; + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java index bb986c3920..9dd6fd45e8 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java @@ -27,29 +27,30 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.CommunicationsManager; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; /** - * ChildFactory that creates createKeys and nodes from a given selectionInfo for - * only emails, call logs and messages. + * * */ -final class MessagesChildNodeFactory extends ChildFactory { +public class MessagesChildNodeFactory extends ChildFactory{ private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName()); private SelectionInfo selectionInfo; - - /** - * Construct a new MessageChildNodeFactory from the currently selectionInfo - * - * @param selectionInfo SelectionInfo object for the currently selected - * accounts - */ - MessagesChildNodeFactory(SelectionInfo selectionInfo) { + + private List threadIDs; + + MessagesChildNodeFactory(SelectionInfo selectionInfo, List threadIDs) { this.selectionInfo = selectionInfo; + this.threadIDs = threadIDs; + } + + MessagesChildNodeFactory() { + this(null, null); } /** @@ -61,18 +62,23 @@ final class MessagesChildNodeFactory extends ChildFactory { this.selectionInfo = selectionInfo; refresh(true); } + + public void refresh(List threadIDs) { + this.threadIDs = threadIDs; + refresh(true); + } + + public void refresh(SelectionInfo selectionInfo, List threadIDs) { + this.threadIDs = threadIDs; + this.selectionInfo = selectionInfo; + refresh(true); - /** - * Creates a list of Keys (BlackboardArtifact) for only messages for the - * currently selected accounts - * - * @param list List of BlackboardArtifact to populate - * - * @return True on success - */ + } + @Override protected boolean createKeys(List list) { CommunicationsManager communicationManager; + try { communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); } catch (NoCurrentCaseException | TskCoreException ex) { @@ -87,19 +93,34 @@ final class MessagesChildNodeFactory extends ChildFactory { final Set relationshipSources; try { + relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter()); - - relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> { - + for(Content content: relationshipSources) { + if( !(content instanceof BlackboardArtifact)){ + continue; + } + BlackboardArtifact bba = (BlackboardArtifact) content; BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID()); - if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG - || fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG - || fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) { + if (fromID != BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG + && fromID != BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG + && fromID != BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) { + continue; + } + + String artifactThreadID = MessageNode.UNTHREADED_ID; + BlackboardAttribute attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID)); + + if(attribute != null) { + artifactThreadID = attribute.getValueString(); + } + + if(threadIDs == null || threadIDs.contains(artifactThreadID)) { list.add(bba); } - }); + + } } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS @@ -107,9 +128,10 @@ final class MessagesChildNodeFactory extends ChildFactory { return true; } - + @Override protected Node createNodeForKey(BlackboardArtifact key) { - return new MessageNode(key); + return new MessageNode(key, null, null); } + } diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.form b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.form new file mode 100755 index 0000000000..50c8190984 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.form @@ -0,0 +1,51 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java similarity index 59% rename from Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java rename to Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java index 8bda078161..20ce895e8e 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java @@ -6,7 +6,7 @@ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. - * You may obt ain a copy of the License at + * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -22,56 +22,37 @@ import java.awt.Component; import java.awt.KeyboardFocusManager; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import javax.swing.JPanel; -import javax.swing.SwingUtilities; import static javax.swing.SwingUtilities.isDescendingFrom; import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; import static org.openide.explorer.ExplorerUtils.createLookup; import org.openide.nodes.AbstractNode; +import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; -import org.openide.nodes.NodeAdapter; -import org.openide.nodes.NodeMemberEvent; import org.openide.util.Lookup; -import org.openide.util.NbBundle.Messages; -import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.communications.ModifiableProxyLookup; import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; /** - * Visualation for the messages of the currently selected accounts. + * + * */ -@ServiceProvider(service = RelationshipsViewer.class) -public final class MessagesViewer extends JPanel implements RelationshipsViewer { +public class MessagesPanel extends javax.swing.JPanel implements Lookup.Provider { private final Outline outline; private final ModifiableProxyLookup proxyLookup; private final PropertyChangeListener focusPropertyListener; - private final MessagesChildNodeFactory nodeFactory; - - @Messages({ - "MessageViewer_tabTitle=Messages", - "MessageViewer_columnHeader_From=From", - "MessageViewer_columnHeader_To=To", - "MessageViewer_columnHeader_Date=Date", - "MessageViewer_columnHeader_Subject=Subject", - "MessageViewer_columnHeader_Attms=Attachments", - "MessageViewer_no_messages=" - }) - + /** - * Visualation for the messages of the currently selected accounts. + * Creates new form ThreadMessagesPanel */ - public MessagesViewer() { + public MessagesPanel() { initComponents(); - outlineViewPanel.hideOutlineView(Bundle.MessageViewer_no_messages()); - proxyLookup = new ModifiableProxyLookup(createLookup(outlineViewPanel.getExplorerManager(), getActionMap())); - nodeFactory = new MessagesChildNodeFactory(null); // See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed // explaination of focusPropertyListener @@ -82,10 +63,10 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer if (newFocusOwner == null) { return; } - if (isDescendingFrom(newFocusOwner, contentViewer)) { + if (isDescendingFrom(newFocusOwner, messageContentViewer)) { //if the focus owner is within the MessageContentViewer (the attachments table) - proxyLookup.setNewLookups(createLookup(((MessageDataContent) contentViewer).getExplorerManager(), getActionMap())); - } else if (isDescendingFrom(newFocusOwner, MessagesViewer.this)) { + proxyLookup.setNewLookups(createLookup(((MessageDataContent) messageContentViewer).getExplorerManager(), getActionMap())); + } else if (isDescendingFrom(newFocusOwner, MessagesPanel.this)) { //... or if it is within the Results table. proxyLookup.setNewLookups(createLookup(outlineViewPanel.getExplorerManager(), getActionMap())); @@ -109,52 +90,21 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer final Node[] nodes = outlineViewPanel.getExplorerManager().getSelectedNodes(); if (nodes != null && nodes.length == 1) { - contentViewer.setNode(nodes[0]); + messageContentViewer.setNode(nodes[0]); } else { - contentViewer.setNode(null); + messageContentViewer.setNode(null); } } }); - outlineViewPanel.getExplorerManager().setRootContext( - new TableFilterNode( - new DataResultFilterNode( - new AbstractNode( - Children.create(nodeFactory, true)), - outlineViewPanel.getExplorerManager()), - true)); - - // When a new set of nodes are added to the OutlineView the childrenAdded - // seems to be fired before the childrenRemoved. - outlineViewPanel.getExplorerManager().getRootContext().addNodeListener(new NodeAdapter() { - @Override - public void childrenAdded(NodeMemberEvent nme) { - updateOutlineViewPanel(); - } - - @Override - public void childrenRemoved(NodeMemberEvent nme) { - updateOutlineViewPanel(); - } - }); } - - @Override - public String getDisplayName() { - return Bundle.MessageViewer_tabTitle(); + + public MessagesPanel(ChildFactory nodeFactory) { + this(); + setChildFactory(nodeFactory); } - - @Override - public JPanel getPanel() { - return this; - } - - @Override - public void setSelectionInfo(SelectionInfo info) { - nodeFactory.refresh(info); - } - + @Override public Lookup getLookup() { return proxyLookup; @@ -174,16 +124,16 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer KeyboardFocusManager.getCurrentKeyboardFocusManager() .removePropertyChangeListener("focusOwner", focusPropertyListener); } - - private void updateOutlineViewPanel() { - int nodeCount = outlineViewPanel.getExplorerManager().getRootContext().getChildren().getNodesCount(); - if(nodeCount == 0) { - outlineViewPanel.hideOutlineView(Bundle.MessageViewer_no_messages()); - } else { - outlineViewPanel.showOutlineView(); - } - } + final void setChildFactory(ChildFactory nodeFactory) { + outlineViewPanel.getExplorerManager().setRootContext( + new TableFilterNode( + new DataResultFilterNode( + new AbstractNode( + Children.create(nodeFactory, true)), + outlineViewPanel.getExplorerManager()),true)); + } + /** * 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 @@ -193,28 +143,23 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer // //GEN-BEGIN:initComponents private void initComponents() { - contentViewer = new MessageDataContent(); + jSplitPane1 = new javax.swing.JSplitPane(); outlineViewPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel(); + messageContentViewer = new MessageDataContent(); - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(contentViewer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(outlineViewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(outlineViewPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(contentViewer, javax.swing.GroupLayout.DEFAULT_SIZE, 390, Short.MAX_VALUE)) - ); + setLayout(new java.awt.BorderLayout()); + + jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); + jSplitPane1.setLeftComponent(outlineViewPanel); + jSplitPane1.setRightComponent(messageContentViewer); + + add(jSplitPane1, java.awt.BorderLayout.CENTER); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private org.sleuthkit.autopsy.contentviewers.MessageContentViewer contentViewer; + private javax.swing.JSplitPane jSplitPane1; + private org.sleuthkit.autopsy.contentviewers.MessageContentViewer messageContentViewer; private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel outlineViewPanel; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.form b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.form deleted file mode 100755 index 34126bbf8c..0000000000 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.form +++ /dev/null @@ -1,42 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.form b/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.form index 5efb16c2b1..58240dec57 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.form +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.form @@ -20,11 +20,6 @@
- - - - - diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.java index 4e04db4f53..81f05b8534 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.java @@ -113,8 +113,6 @@ public class OutlineViewPanel extends javax.swing.JPanel implements ExplorerMana messageLabel = new javax.swing.JLabel(); setLayout(new java.awt.CardLayout(5, 5)); - - outlineView.setPreferredSize(new java.awt.Dimension(300, 400)); add(outlineView, "outlineCard"); messagePanel.setLayout(new java.awt.BorderLayout()); diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java index 03729540df..b13eef621b 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java @@ -31,7 +31,7 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider private SelectionInfo currentSelection; - private final MessagesViewer messagesViewer; + private final MessageViewer messagesViewer; private final ContactsViewer contactsViewer; private final SummaryViewer summaryViewer; private final MediaViewer mediaViewer; @@ -42,21 +42,18 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider * Creates new form RelationshipBrowser */ public RelationshipBrowser() { - messagesViewer = new MessagesViewer(); + initComponents(); + messagesViewer = new MessageViewer(); contactsViewer = new ContactsViewer(); summaryViewer = new SummaryViewer(); mediaViewer = new MediaViewer(); proxyLookup = new ModifiableProxyLookup(messagesViewer.getLookup()); - - initComponents(); - + tabPane.add(summaryViewer.getDisplayName(), summaryViewer); tabPane.add(messagesViewer.getDisplayName(), messagesViewer); tabPane.add(contactsViewer.getDisplayName(), contactsViewer); tabPane.add(mediaViewer.getDisplayName(), mediaViewer); - - } /** diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java new file mode 100755 index 0000000000..4cbdd87f53 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java @@ -0,0 +1,200 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 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.communications.relationships; + +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import javax.swing.Action; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.NodeProperty; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.CommunicationsManager; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * ChildFactory that creates createKeys and nodes from a given selectionInfo for + * only emails, call logs and messages. + * + */ +final class ThreadChildNodeFactory extends ChildFactory { + + private static final Logger logger = Logger.getLogger(ThreadChildNodeFactory.class.getName()); + + private SelectionInfo selectionInfo; + + private final Action preferredAction; + + /** + * Construct a new ThreadChildNodeFactory from the currently selectionInfo + * + * @param preferredAction SelectionInfo object for the currently selected + * accounts + */ + + ThreadChildNodeFactory(Action preferredAction) { + this.preferredAction = preferredAction; + } + + /** + * Updates the current instance of selectionInfo and calls the refresh method. + * + * @param selectionInfo New instance of the currently selected accounts + */ + public void refresh(SelectionInfo selectionInfo) { + this.selectionInfo = selectionInfo; + refresh(true); + } + + /** + * Creates a list of Keys (BlackboardArtifact) for only messages for the + * currently selected accounts. + * + * @param list List of BlackboardArtifact to populate + * + * @return True on success + */ + @Override + protected boolean createKeys(List list) { + CommunicationsManager communicationManager; + try { + communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager(); + } catch (NoCurrentCaseException | TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS + return false; + } + + if(selectionInfo == null) { + return true; + } + + final Set relationshipSources; + + try { + relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter()); + + createRootMessageKeys(list, relationshipSources) ; + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS + } + + return true; + } + + /** + * Adds only BlackboardArtifact objects to the list where are the earliest + * message in a message thread (based on threadID). If there are "unthreaded" + * messages (messages that do not have a threadID) one representitive artifact + * will be added to the list and dealt with a node creation time. + * + * @param list + * @param relationshipSources + * @return + * @throws TskCoreException + */ + private boolean createRootMessageKeys(List list, Set relationshipSources) throws TskCoreException{ + HashMap rootMessageMap = new HashMap<>(); + for(Content content: relationshipSources) { + if(content instanceof BlackboardArtifact) { + BlackboardArtifact bba = (BlackboardArtifact) content; + BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID()); + + if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG + || fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG + || fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) { + + String threadID = MessageNode.UNTHREADED_ID; + BlackboardAttribute attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID)); + + if(attribute != null) { + threadID = attribute.getValueString(); + } + + BlackboardArtifact tableArtifact = rootMessageMap.get(threadID); + if(tableArtifact == null) { + rootMessageMap.put(threadID, bba); + } else { + BlackboardAttribute tableAttribute = tableArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT)); + attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT)); + + if(tableAttribute.getValueLong() > attribute.getValueLong()) { + rootMessageMap.put(threadID, bba); + } + } + } + } + } + + for(BlackboardArtifact bba: rootMessageMap.values()) { + list.add(bba); + } + + return true; + } + + @Override + protected Node createNodeForKey(BlackboardArtifact bba) { + BlackboardAttribute attribute = null; + try { + attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID)); + } catch (TskCoreException tskCoreException) { + } + + if (attribute != null) { + return new MessageNode(bba, attribute.getValueString(), preferredAction); + } else { + // Only one of these should occur. + return new UnthreadedNode(preferredAction); + } + } + + final class UnthreadedNode extends AbstractNode { + private final Action preferredAction; + + UnthreadedNode(Action preferredAction) { + super(Children.LEAF); + setDisplayName("Unthreaded"); + this.preferredAction = preferredAction; + } + + @Override + protected Sheet createSheet() { + Sheet sheet = super.createSheet(); + Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); + if (sheetSet == null) { + sheetSet = Sheet.createPropertiesSet(); + sheet.put(sheetSet); + } + + sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",MessageNode.UNTHREADED_ID)); + + return sheet; + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 0b3a6f698f..0961642519 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -489,6 +489,12 @@ public class DataResultFilterNode extends FilterNode { @Override public AbstractAction visit(BlackboardArtifactNode ban) { + + Action preferredAction = ban.getPreferredAction(); + if(preferredAction != null && preferredAction instanceof AbstractAction) { + return (AbstractAction) preferredAction; + } + BlackboardArtifact artifact = ban.getArtifact(); try { if ((artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED index c3a2ee4faf..2ba6856d7e 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties-MERGED @@ -36,7 +36,7 @@ KeywordSearchResultFactory.createNodeForKey.noResultsFound.text=No results found KeywordSearchResultFactory.query.exception.msg=Could not perform the query OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Keyword Search ingest module.\n\nThe module indexes files found in the disk image at ingest time.\nIt then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\nThe module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword search bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found. +OpenIDE-Module-Long-Description=Keyword Search ingest module.\n\nThe module indexes files found in the disk image at ingest time.\nIt then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\n\The module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword search bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found. OpenIDE-Module-Name=KeywordSearch OptionsCategory_Name_KeywordSearchOptions=Keyword Search OptionsCategory_Keywords_KeywordSearchOptions=Keyword Search diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED index 17d744eee1..7da2ebca7b 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED @@ -64,7 +64,7 @@ ExtractZone_progress_Msg=Extracting :Zone.Identifer files ExtractZone_Restricted=Restricted Sites Zone ExtractZone_Trusted=Trusted Sites Zone OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\nThe module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web activity (sites visited, stored cookies, book marked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\nThe module currently supports Windows only disk images.\nThe plugin is also fully functional when deployed on Windows version of Autopsy. +OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\n\The module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web activity (sites visited, stored cookies, book marked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\nThe module currently supports Windows only disk images.\nThe plugin is also fully functional when deployed on Windows version of Autopsy. OpenIDE-Module-Name=RecentActivity OpenIDE-Module-Short-Description=Recent Activity finder ingest module Chrome.moduleName=Chrome From de13b8c6e41a10d40b550f6d4cb51da14f4deefe Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 12 Jun 2019 10:11:44 -0400 Subject: [PATCH 02/16] Added comments and cleaned up factory code. --- .../MessagesChildNodeFactory.java | 15 ++++------ .../relationships/ThreadChildNodeFactory.java | 28 ++++++++++++------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java index 9dd6fd45e8..d185b1a374 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java @@ -57,17 +57,9 @@ public class MessagesChildNodeFactory extends ChildFactory{ * Updates the current instance of selectionInfo and calls the refresh method. * * @param selectionInfo New instance of the currently selected accounts + * @param threadIDs A list of threadIDs to filter the keys by, null will + * return all keys for the selected accounts. */ - public void refresh(SelectionInfo selectionInfo) { - this.selectionInfo = selectionInfo; - refresh(true); - } - - public void refresh(List threadIDs) { - this.threadIDs = threadIDs; - refresh(true); - } - public void refresh(SelectionInfo selectionInfo, List threadIDs) { this.threadIDs = threadIDs; this.selectionInfo = selectionInfo; @@ -109,6 +101,9 @@ public class MessagesChildNodeFactory extends ChildFactory{ continue; } + // We want all artifacts that do not have "threadIDs" to appear as one thread in the UI + // To achive this assign any artifact that does not have a threadID + // the "UNTHREADED_ID" String artifactThreadID = MessageNode.UNTHREADED_ID; BlackboardAttribute attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID)); diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java index 4cbdd87f53..679a4e62dc 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java @@ -113,9 +113,9 @@ final class ThreadChildNodeFactory extends ChildFactory { * messages (messages that do not have a threadID) one representitive artifact * will be added to the list and dealt with a node creation time. * - * @param list - * @param relationshipSources - * @return + * @param list List to populate with BlackboardArtifact keys + * @param relationshipSources Set of Content objects + * @return True on success * @throws TskCoreException */ private boolean createRootMessageKeys(List list, Set relationshipSources) throws TskCoreException{ @@ -129,6 +129,9 @@ final class ThreadChildNodeFactory extends ChildFactory { || fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG || fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) { + // We want all artifacts that do not have "threadIDs" to appear as one thread in the UI + // To achive this assign any artifact that does not have a threadID + // the "UNTHREADED_ID" String threadID = MessageNode.UNTHREADED_ID; BlackboardAttribute attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID)); @@ -143,7 +146,7 @@ final class ThreadChildNodeFactory extends ChildFactory { BlackboardAttribute tableAttribute = tableArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT)); attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT)); - if(tableAttribute.getValueLong() > attribute.getValueLong()) { + if(tableAttribute != null && attribute != null && tableAttribute.getValueLong() > attribute.getValueLong()) { rootMessageMap.put(threadID, bba); } } @@ -163,24 +166,28 @@ final class ThreadChildNodeFactory extends ChildFactory { BlackboardAttribute attribute = null; try { attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID)); - } catch (TskCoreException tskCoreException) { + } catch (TskCoreException ex) { + logger.log(Level.WARNING, String.format("Unable to get threadID for artifact: %s", bba.getName()), ex); } if (attribute != null) { return new MessageNode(bba, attribute.getValueString(), preferredAction); } else { // Only one of these should occur. - return new UnthreadedNode(preferredAction); + return new UnthreadedNode(); } } + /** + * An this node represents the "unthreaded" thread. + */ final class UnthreadedNode extends AbstractNode { - private final Action preferredAction; - - UnthreadedNode(Action preferredAction) { + /** + * Construct an instance of UnthreadNode. + */ + UnthreadedNode() { super(Children.LEAF); setDisplayName("Unthreaded"); - this.preferredAction = preferredAction; } @Override @@ -192,6 +199,7 @@ final class ThreadChildNodeFactory extends ChildFactory { sheet.put(sheetSet); } + // Give this node a threadID of "UNTHEADED_ID" sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",MessageNode.UNTHREADED_ID)); return sheet; From 49772123f8678725778af5b3f528a1fd7341fc0c Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 12 Jun 2019 16:22:41 -0400 Subject: [PATCH 03/16] Fixed the MessagePanel spliter bar --- .../relationships/MessagesPanel.form | 2 +- .../relationships/MessagesPanel.java | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.form b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.form index 50c8190984..5521c04bda 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.form @@ -16,7 +16,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java index 20ce895e8e..f2a161c148 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java @@ -98,6 +98,9 @@ public class MessagesPanel extends javax.swing.JPanel implements Lookup.Provider } }); + splitPane.setResizeWeight(0.5); + splitPane.setDividerLocation(0.5); + } public MessagesPanel(ChildFactory nodeFactory) { @@ -143,23 +146,23 @@ public class MessagesPanel extends javax.swing.JPanel implements Lookup.Provider // //GEN-BEGIN:initComponents private void initComponents() { - jSplitPane1 = new javax.swing.JSplitPane(); + splitPane = new javax.swing.JSplitPane(); outlineViewPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel(); messageContentViewer = new MessageDataContent(); setLayout(new java.awt.BorderLayout()); - jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); - jSplitPane1.setLeftComponent(outlineViewPanel); - jSplitPane1.setRightComponent(messageContentViewer); + splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); + splitPane.setLeftComponent(outlineViewPanel); + splitPane.setRightComponent(messageContentViewer); - add(jSplitPane1, java.awt.BorderLayout.CENTER); + add(splitPane, java.awt.BorderLayout.CENTER); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JSplitPane jSplitPane1; private org.sleuthkit.autopsy.contentviewers.MessageContentViewer messageContentViewer; private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel outlineViewPanel; + private javax.swing.JSplitPane splitPane; // End of variables declaration//GEN-END:variables } From 4da9bc79d4639202c60fb7c74d3578ad17f4c195 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 12 Jun 2019 16:36:59 -0400 Subject: [PATCH 04/16] Added support for andriod text message --- .../autopsy/communications/relationships/MessageNode.java | 4 ++-- InternalPythonModules/android/textmessage.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java index a7743dc3af..8a5af271d1 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java @@ -86,6 +86,8 @@ class MessageNode extends BlackboardArtifactNode { } sheetSet.put(new NodeProperty<>("Type", Bundle.MessageNode_Node_Property_Type(), "", getDisplayName())); //NON-NLS + + sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",threadID == null ? UNTHREADED_ID : threadID)); //NON-NLS final BlackboardArtifact artifact = getArtifact(); @@ -107,8 +109,6 @@ class MessageNode extends BlackboardArtifactNode { } catch (TskCoreException ex) { logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS } - - sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",threadID == null ? "" : threadID)); //NON-NLS break; case TSK_MESSAGE: diff --git a/InternalPythonModules/android/textmessage.py b/InternalPythonModules/android/textmessage.py index 5d7f9db638..ef8fa498c8 100644 --- a/InternalPythonModules/android/textmessage.py +++ b/InternalPythonModules/android/textmessage.py @@ -99,13 +99,14 @@ class TextMessageAnalyzer(general.AndroidComponentAnalyzer): resultSet = None try: resultSet = statement.executeQuery( - "SELECT address, date, read, type, subject, body FROM sms;") + "SELECT address, date, read, type, subject, body, thread_id FROM sms;") while resultSet.next(): address = resultSet.getString("address") # may be phone number, or other addresses date = Long.valueOf(resultSet.getString("date")) / 1000 read = resultSet.getInt("read") # may be unread = 0, read = 1 subject = resultSet.getString("subject") # message subject body = resultSet.getString("body") # message body + thread_id = "{0}_{1}".format(abstractFile.getId(), resultSet.getInt("thread_id")) attributes = ArrayList() artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); #create Message artifact and then add attributes from result set. if resultSet.getString("type") == "1": @@ -119,6 +120,7 @@ class TextMessageAnalyzer(general.AndroidComponentAnalyzer): attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT, general.MODULE_NAME, subject)) attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, body)) attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "SMS Message")) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID, general.MODULE_NAME, thread_id)) artifact.addAttributes(attributes) From d60052f281cd36ec0ec9d3dfe5a7f10d85a0c2c8 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 13 Jun 2019 14:31:12 -0400 Subject: [PATCH 05/16] modifying message view based on talks with Brian --- .../autopsy/communications/images/nail.png | Bin 0 -> 202 bytes .../autopsy/communications/images/screw.png | Bin 0 -> 217 bytes .../communications/images/threaded.png | Bin 0 -> 263 bytes .../communications/images/unthreaded.png | Bin 0 -> 199 bytes .../relationships/Bundle.properties | 8 +- .../relationships/Bundle.properties-MERGED | 11 +- .../relationships/MessageNode.java | 6 +- .../relationships/MessageViewer.form | 80 ++---- .../relationships/MessageViewer.java | 269 ++++++------------ .../relationships/MessagesPanel.java | 2 +- .../relationships/OutlineViewPanel.java | 24 ++ .../relationships/ThreadChildNodeFactory.java | 2 +- .../relationships/ThreadNode.java | 46 +++ 13 files changed, 194 insertions(+), 254 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/communications/images/nail.png create mode 100755 Core/src/org/sleuthkit/autopsy/communications/images/screw.png create mode 100755 Core/src/org/sleuthkit/autopsy/communications/images/threaded.png create mode 100755 Core/src/org/sleuthkit/autopsy/communications/images/unthreaded.png create mode 100755 Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java 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 0000000000000000000000000000000000000000..f10f365a10aabd7eae9c30ced2905b0958c86e82 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#F&nqAn9x_2jM+dT+02lL66gHf+|;}hAeVu`xhOTUBsE2$JhLQ2!QIn0AVn{g z9VqVL>EaloaX$Ia|Nr*PAmCh8WyPFlQ2fk?qnR_9qd!Z8cgL3noJNP{w(uyNJG^Rs mXQPY3s>Fhf19F#{U#T#x&=hkFowMpS$P!OiKbLh*2~7a=I5)Nc literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..ec8d434e258ad02545a0e7eefa3f166975b57cdf GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#F&nqAsP&xLi%oz+vY8S|xv6<2KrRD=b5UwyNotBhd1gt5g1e`0K#E=} zJ5b!;)5S4F<@Wt~$( F698u;KpOx6 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..449f6bad6cb1b286f2916044d10129b06ad9150b GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#F&noqzrI;c?`Ki;O^-gkfN8$ z4ivBTba4!^IK6lBK~4rm9+vPEr;XmYaBmlxKTYA^x41)!PCk5o950j?^UZb;il4^d zpxLUadPJg@fni4RuXqNAz2*1iJ(^UC&c#%FpXAIcRH}ab+veB?#;mo8jZxWVo$3>$ zKdf#p==#LB>(s%x?K=hDGM#PDID2ajOYR&~dH(J*{h6nh$^Z>wVDNPHb6Mw<&;$U^ C)KudD literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e66695ea888f26e1f25c6d04e801d29e5b467bff GIT binary patch literal 199 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#F&nqAp#CG>O};=O+02lL66gHf+|;}hAeVu`xhOTUBsE2$JhLQ2!QIn0AVn{g z9Vl+=>Eak-ar*5ALtX|$9+rchUqTZkx_&<9Xe;4kuYb+F!RqWPt@>|{X<;rms=qT8 mynk!oQ0%9@;aCFCF$Np+cI~Y MessageViewer.showingMessagesLabel.text=Showing Messages for Thread: -MessageViewer.messagesLabel.text=Messages MessageViewer.backButton.AccessibleContext.accessibleDescription= -MessageViewer.backButton.text= -MessageViewer.showMessagesButton.text= -MessageViewer.viewMessageLabel.text=View Messages: +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 1efa1db775..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,7 +19,8 @@ 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 @@ -50,11 +51,9 @@ 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=Threads +MessageViewer.threadsLabel.text=Select a Thread to View MessageViewer.threadNameLabel.text= MessageViewer.showingMessagesLabel.text=Showing Messages for Thread: -MessageViewer.messagesLabel.text=Messages MessageViewer.backButton.AccessibleContext.accessibleDescription= -MessageViewer.backButton.text= -MessageViewer.showMessagesButton.text= -MessageViewer.viewMessageLabel.text=View Messages: +MessageViewer.backButton.text=Threads +MessageViewer.showAllButton.text=All Messages diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java index a7743dc3af..6a39c246d0 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageNode.java @@ -25,7 +25,6 @@ import org.apache.commons.lang3.StringUtils; import org.openide.nodes.Sheet; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -41,6 +40,7 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBU import org.sleuthkit.datamodel.TimeUtilities; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.communications.Utils; +import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; /** * Wraps a BlackboardArtifact as an AbstractNode for use in an OutlookView @@ -86,8 +86,8 @@ class MessageNode extends BlackboardArtifactNode { } sheetSet.put(new NodeProperty<>("Type", Bundle.MessageNode_Node_Property_Type(), "", getDisplayName())); //NON-NLS - - final BlackboardArtifact artifact = getArtifact(); + + BlackboardArtifact artifact = this.getArtifact(); BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID()); if (null != fromID) { diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.form b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.form index a6d0ddfa45..cbff1d5e95 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.form +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.form @@ -28,71 +28,44 @@ - - - - - - - - - - - + - - - - - - - - - - - - - - + - + + + + - + - + - - - - - - - + + + - - - - + @@ -113,22 +86,18 @@ - + - + - - - - @@ -140,22 +109,7 @@ - - - - - - - - - - - - - - - - + @@ -167,7 +121,7 @@ - + @@ -179,7 +133,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java index 3da19c0d83..32f0496c81 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java @@ -24,11 +24,13 @@ import java.awt.KeyboardFocusManager; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.JPanel; +import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import static javax.swing.SwingUtilities.isDescendingFrom; import org.netbeans.swing.outline.DefaultOutlineModel; @@ -40,6 +42,7 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Node.Property; import org.openide.nodes.Node.PropertySet; +import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.communications.ModifiableProxyLookup; @@ -47,12 +50,11 @@ import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; - /** * * */ -public class MessageViewer extends JPanel implements RelationshipsViewer{ +public class MessageViewer extends JPanel implements RelationshipsViewer { private static final Logger logger = Logger.getLogger(MessageViewer.class.getName()); @@ -64,27 +66,25 @@ public class MessageViewer extends JPanel implements RelationshipsViewer{ private SelectionInfo currentSelectionInfo = null; OutlineViewPanel currentPanel; - + @Messages({ "MessageViewer_tabTitle=Messages", "MessageViewer_columnHeader_From=From", + "MessageViewer_columnHeader_Date=Data", "MessageViewer_columnHeader_To=To", - "MessageViewer_columnHeader_Date=Date", + "MessageViewer_columnHeader_EarlyDate=Earliest Message", "MessageViewer_columnHeader_Subject=Subject", "MessageViewer_columnHeader_Attms=Attachments", "MessageViewer_no_messages=", "MessageViewer_viewMessage_all=All", "MessageViewer_viewMessage_selected=Selected", - "MessageViewer_viewMessage_unthreaded=Unthreaded", - }) - - + "MessageViewer_viewMessage_unthreaded=Unthreaded",}) /** * Creates new form MessageViewer2 */ public MessageViewer() { - + initComponents(); currentPanel = rootTablePane; proxyLookup = new ModifiableProxyLookup(createLookup(rootTablePane.getExplorerManager(), getActionMap())); @@ -108,7 +108,6 @@ public class MessageViewer extends JPanel implements RelationshipsViewer{ } }; - rootTablePane.getExplorerManager().setRootContext( new TableFilterNode( new DataResultFilterNode( @@ -119,40 +118,27 @@ public class MessageViewer extends JPanel implements RelationshipsViewer{ Outline outline = rootTablePane.getOutlineView().getOutline(); rootTablePane.getOutlineView().setPropertyColumns( - "From", Bundle.MessageViewer_columnHeader_From(), - "To", Bundle.MessageViewer_columnHeader_To(), - "Date", Bundle.MessageViewer_columnHeader_Date(), - "Subject", Bundle.MessageViewer_columnHeader_Subject(), - "Attms", Bundle.MessageViewer_columnHeader_Attms() + "Date", Bundle.MessageViewer_columnHeader_EarlyDate(), + "Subject", Bundle.MessageViewer_columnHeader_Subject() ); outline.setRootVisible(false); ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel("Type"); - + outline.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); rootTablePane.getExplorerManager().addPropertyChangeListener((PropertyChangeEvent evt) -> { if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) { - final Node[] nodes = rootTablePane.getExplorerManager().getSelectedNodes(); - - switch((VIEW_MESSAGE_TYPE)viewMessageComboBox.getSelectedItem()) { - case ALL: - showMessagesButton.setEnabled((nodes != null && nodes.length > 0)); - break; - case SELECTED: - showMessagesButton.setEnabled((nodes != null && nodes.length == 1)); - break; - } + showSelectedThread(); } }); - + threadMessagesPanel.setChildFactory(threadMessageNodeFactory); - - this.viewMessageComboBox.addItem(VIEW_MESSAGE_TYPE.SELECTED); - this.viewMessageComboBox.addItem(VIEW_MESSAGE_TYPE.ALL); + + rootTablePane.setTableColumnsWidth(10, 20, 70); } @Override public String getDisplayName() { - return Bundle.MessageViewer_tabTitle(); + return Bundle.MessageViewer_tabTitle(); } @Override @@ -191,31 +177,16 @@ public class MessageViewer extends JPanel implements RelationshipsViewer{ KeyboardFocusManager.getCurrentKeyboardFocusManager() .removePropertyChangeListener("focusOwner", focusPropertyListener); } - - private void showMessages() { - VIEW_MESSAGE_TYPE viewType = (VIEW_MESSAGE_TYPE)viewMessageComboBox.getSelectedItem(); - switch((VIEW_MESSAGE_TYPE)viewMessageComboBox.getSelectedItem()){ - case ALL: - threadMessageNodeFactory.refresh(currentSelectionInfo, null); - threadNameLabel.setText("All Messages"); - - ((CardLayout)getLayout()).show(this, "messages"); - break; - case SELECTED: - showSelectedThread(); - break; - } - } @SuppressWarnings("rawtypes") private void showSelectedThread() { final Node[] nodes = rootTablePane.getExplorerManager().getSelectedNodes(); - if(nodes == null) { + if (nodes == null) { return; } - if(nodes.length == 0 || nodes.length > 1) { + if (nodes.length == 0 || nodes.length > 1) { return; } @@ -223,19 +194,19 @@ public class MessageViewer extends JPanel implements RelationshipsViewer{ String subject = ""; PropertySet[] propertySets = nodes[0].getPropertySets(); - for(PropertySet pset: propertySets) { + for (PropertySet pset : propertySets) { Property[] properties = pset.getProperties(); - for(Property prop: properties) { - if(prop.getName().equalsIgnoreCase("threadid")){ + for (Property prop : properties) { + if (prop.getName().equalsIgnoreCase("threadid")) { try { String threadID = prop.getValue().toString(); - if(!threadIDList.contains(threadID)){ + if (!threadIDList.contains(threadID)) { threadIDList.add(threadID); } } catch (IllegalAccessException | InvocationTargetException ex) { logger.log(Level.WARNING, String.format("Unable to get threadid for node: %s", nodes[0].getDisplayName()), ex); } - } else if(prop.getName().equalsIgnoreCase("subject")) { + } else if (prop.getName().equalsIgnoreCase("subject")) { try { subject = prop.getValue().toString(); } catch (IllegalAccessException | InvocationTargetException ex) { @@ -247,17 +218,34 @@ public class MessageViewer extends JPanel implements RelationshipsViewer{ } - if(!threadIDList.isEmpty()) { + if (!threadIDList.isEmpty()) { threadMessageNodeFactory.refresh(currentSelectionInfo, threadIDList); - - if(!subject.isEmpty()){ + + if (!subject.isEmpty()) { threadNameLabel.setText(subject); } - // Come back and put involk later for safety. - CardLayout layout = (CardLayout)getLayout(); - layout.show(this, "messages"); + + showMessagesPane(); } } + + private void showThreadsPane() { + switchCard("threads"); + } + + private void showMessagesPane() { + switchCard("messages"); + } + + private void switchCard(String cardName) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + CardLayout layout = (CardLayout)getLayout(); + layout.show(MessageViewer.this, cardName); + } + }); + } /** * This method is called from within the constructor to initialize the form. @@ -270,15 +258,12 @@ public class MessageViewer extends JPanel implements RelationshipsViewer{ java.awt.GridBagConstraints gridBagConstraints; rootMessagesPane = new javax.swing.JPanel(); - rootTablePane = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel(); threadsLabel = new javax.swing.JLabel(); - viewMessageComboBox = new javax.swing.JComboBox<>(); - viewMessageLabel = new javax.swing.JLabel(); - showMessagesButton = new javax.swing.JButton(); + showAllButton = new javax.swing.JButton(); + rootTablePane = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel(); messagePanel = new javax.swing.JPanel(); threadMessagesPanel = new MessagesPanel(); backButton = new javax.swing.JButton(); - messagesLabel = new javax.swing.JLabel(); showingMessagesLabel = new javax.swing.JLabel(); threadNameLabel = new javax.swing.JLabel(); @@ -286,64 +271,41 @@ public class MessageViewer extends JPanel implements RelationshipsViewer{ rootMessagesPane.setOpaque(false); rootMessagesPane.setLayout(new java.awt.GridBagLayout()); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 4; - gridBagConstraints.gridwidth = 4; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.weighty = 1.0; - gridBagConstraints.insets = new java.awt.Insets(5, 15, 15, 15); - rootMessagesPane.add(rootTablePane, gridBagConstraints); - threadsLabel.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(threadsLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.threadsLabel.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; - gridBagConstraints.gridheight = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; - gridBagConstraints.insets = new java.awt.Insets(15, 15, 0, 0); + gridBagConstraints.insets = new java.awt.Insets(15, 15, 9, 0); rootMessagesPane.add(threadsLabel, gridBagConstraints); - viewMessageComboBox.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(showAllButton, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.showAllButton.text")); // NOI18N + showAllButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - viewMessageComboBoxActionPerformed(evt); + showAllButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 2; - gridBagConstraints.gridy = 0; - gridBagConstraints.gridheight = 4; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 0); - rootMessagesPane.add(viewMessageComboBox, gridBagConstraints); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 2; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + gridBagConstraints.insets = new java.awt.Insets(0, 15, 15, 0); + rootMessagesPane.add(showAllButton, gridBagConstraints); - org.openide.awt.Mnemonics.setLocalizedText(viewMessageLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.viewMessageLabel.text")); // NOI18N + rootTablePane.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 0; - gridBagConstraints.gridheight = 2; - gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; - gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 5); - rootMessagesPane.add(viewMessageLabel, gridBagConstraints); - - showMessagesButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/timeline/images/btn_step_forward.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(showMessagesButton, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.showMessagesButton.text")); // NOI18N - showMessagesButton.setBorder(null); - showMessagesButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - showMessagesButtonActionPerformed(evt); - } - }); - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 3; - gridBagConstraints.gridy = 0; + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.gridwidth = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(15, 5, 0, 15); - rootMessagesPane.add(showMessagesButton, gridBagConstraints); + gridBagConstraints.weightx = 1.0; + gridBagConstraints.weighty = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 15, 9, 15); + rootMessagesPane.add(rootTablePane, gridBagConstraints); add(rootMessagesPane, "threads"); @@ -351,7 +313,7 @@ public class MessageViewer extends JPanel implements RelationshipsViewer{ gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; - gridBagConstraints.gridwidth = 5; + gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; @@ -359,102 +321,74 @@ public class MessageViewer extends JPanel implements RelationshipsViewer{ gridBagConstraints.insets = new java.awt.Insets(0, 15, 0, 15); messagePanel.add(threadMessagesPanel, gridBagConstraints); - backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/timeline/images/btn_step_back.png"))); // NOI18N + backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/timeline/images/arrow-180.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.backButton.text")); // NOI18N - backButton.setBorder(null); - backButton.setBorderPainted(false); backButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { backButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; + gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(16, 15, 0, 0); + gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(9, 0, 9, 15); messagePanel.add(backButton, gridBagConstraints); backButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.backButton.AccessibleContext.accessibleDescription")); // NOI18N - messagesLabel.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(messagesLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.messagesLabel.text")); // NOI18N - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 1; - gridBagConstraints.gridwidth = 2; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(5, 15, 0, 0); - messagePanel.add(messagesLabel, gridBagConstraints); - org.openide.awt.Mnemonics.setLocalizedText(showingMessagesLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.showingMessagesLabel.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 2; - gridBagConstraints.gridwidth = 3; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.insets = new java.awt.Insets(5, 15, 5, 0); + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + gridBagConstraints.insets = new java.awt.Insets(9, 15, 5, 0); messagePanel.add(showingMessagesLabel, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(threadNameLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.threadNameLabel.text")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 3; - gridBagConstraints.gridy = 2; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; - gridBagConstraints.weightx = 1.0; - gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 15); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 0; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + gridBagConstraints.insets = new java.awt.Insets(9, 5, 5, 15); messagePanel.add(threadNameLabel, gridBagConstraints); add(messagePanel, "messages"); }// //GEN-END:initComponents private void backButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backButtonActionPerformed - CardLayout layout = (CardLayout) this.getLayout(); - layout.show(this, "threads"); + try { + rootTablePane.getExplorerManager().setSelectedNodes(new Node[0]); + } catch (PropertyVetoException ex) { + Exceptions.printStackTrace(ex); + } + showThreadsPane(); }//GEN-LAST:event_backButtonActionPerformed - private void showMessagesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showMessagesButtonActionPerformed - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - showMessages(); - } - }); - }//GEN-LAST:event_showMessagesButtonActionPerformed - - private void viewMessageComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewMessageComboBoxActionPerformed - boolean accountSelected = (currentSelectionInfo != null && currentSelectionInfo.getAccounts() != null && !currentSelectionInfo.getAccounts().isEmpty()); - switch((VIEW_MESSAGE_TYPE)viewMessageComboBox.getSelectedItem()) { - case ALL: - showMessagesButton.setEnabled(accountSelected); - break; - case SELECTED: - Node[] selected = rootTablePane.getExplorerManager().getSelectedNodes(); - showMessagesButton.setEnabled(selected != null && selected.length == 1); - break; - } - }//GEN-LAST:event_viewMessageComboBoxActionPerformed + private void showAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showAllButtonActionPerformed + threadMessageNodeFactory.refresh(currentSelectionInfo, null); + threadNameLabel.setText("All Messages"); + showMessagesPane(); + }//GEN-LAST:event_showAllButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton backButton; private javax.swing.JPanel messagePanel; - private javax.swing.JLabel messagesLabel; private javax.swing.JPanel rootMessagesPane; private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel rootTablePane; - private javax.swing.JButton showMessagesButton; + private javax.swing.JButton showAllButton; private javax.swing.JLabel showingMessagesLabel; private org.sleuthkit.autopsy.communications.relationships.MessagesPanel threadMessagesPanel; private javax.swing.JLabel threadNameLabel; private javax.swing.JLabel threadsLabel; - private javax.swing.JComboBox viewMessageComboBox; - private javax.swing.JLabel viewMessageLabel; // End of variables declaration//GEN-END:variables class ShowThreadMessagesAction extends AbstractAction { + @Override public void actionPerformed(ActionEvent e) { - + SwingUtilities.invokeLater(new Runnable() { @Override public void run() { @@ -463,19 +397,4 @@ public class MessageViewer extends JPanel implements RelationshipsViewer{ }); } } - - private enum VIEW_MESSAGE_TYPE{ - ALL(Bundle.MessageViewer_viewMessage_all()), - SELECTED(Bundle.MessageViewer_viewMessage_selected()); - - private final String displayLabel; - VIEW_MESSAGE_TYPE(String label) { - displayLabel = label; - } - - @Override - public String toString() { - return displayLabel; - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java index f2a161c148..366d6ee43b 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java @@ -100,7 +100,7 @@ public class MessagesPanel extends javax.swing.JPanel implements Lookup.Provider splitPane.setResizeWeight(0.5); splitPane.setDividerLocation(0.5); - + outlineViewPanel.setTableColumnsWidth(5,10,10,15,50,10); } public MessagesPanel(ChildFactory nodeFactory) { diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.java index 81f05b8534..31d9a983f2 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/OutlineViewPanel.java @@ -19,7 +19,9 @@ package org.sleuthkit.autopsy.communications.relationships; import java.awt.CardLayout; +import javax.swing.JTable; import javax.swing.SwingUtilities; +import javax.swing.table.TableColumn; import org.openide.explorer.ExplorerManager; import static org.openide.explorer.ExplorerUtils.createLookup; import org.openide.explorer.view.OutlineView; @@ -98,6 +100,28 @@ public class OutlineViewPanel extends javax.swing.JPanel implements ExplorerMana super.setEnabled(enabled); outlineView.setEnabled(enabled); } + + /** + * Sets the width of the columns of the OutlineView based on the passed in + * list of percentages. There should be on double value for each column + * in the OutlineView. + * + * @param percentages A series of double percentages values representing + * what percent of the total width of the table each + * column should have. + */ + public void setTableColumnsWidth(double... percentages) { + JTable table = outlineView.getOutline(); + double total = 0; + for (int i = 0; i < table.getColumnModel().getColumnCount(); i++) { + total += percentages[i]; + } + + for (int i = 0; i < table.getColumnModel().getColumnCount(); i++) { + TableColumn column = table.getColumnModel().getColumn(i); + column.setPreferredWidth((int) (table.getPreferredSize().width * (percentages[i] / total))); + } + } /** * This method is called from within the constructor to initialize the form. diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java index 679a4e62dc..eaa975a1d9 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java @@ -171,7 +171,7 @@ final class ThreadChildNodeFactory extends ChildFactory { } if (attribute != null) { - return new MessageNode(bba, attribute.getValueString(), preferredAction); + return new ThreadNode(bba, attribute.getValueString()); } else { // Only one of these should occur. return new UnthreadedNode(); diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java new file mode 100755 index 0000000000..25cd3acf3b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java @@ -0,0 +1,46 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.communications.relationships; + +import javax.swing.Action; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.Children; +import org.openide.nodes.Sheet; +import org.sleuthkit.datamodel.BlackboardArtifact; + +/** + * + * @author kelly + */ +final class ThreadNode extends AbstractNode{ + + final private MessageNode messageNode; + + ThreadNode(BlackboardArtifact artifact, String threadID) { + super(Children.LEAF); + messageNode = new MessageNode(artifact, threadID, null); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/communications/images/threaded.png" ); + } + + @Override + protected Sheet createSheet() { + return messageNode.createSheet(); + } + + String getThreadID() { + return messageNode.getThreadID(); + } + + @Override + public Action getPreferredAction() { + return messageNode.getPreferredAction(); + } + + @Override + public String getDisplayName() { + return messageNode.getDisplayName(); + } +} From bf73912a5a7031db6e028ac08d1340ca5993bdc0 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 14 Jun 2019 10:25:29 -0400 Subject: [PATCH 06/16] Added unthreaded icon --- .../communications/relationships/ThreadChildNodeFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java index eaa975a1d9..1fad288bba 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java @@ -188,6 +188,7 @@ final class ThreadChildNodeFactory extends ChildFactory { UnthreadedNode() { super(Children.LEAF); setDisplayName("Unthreaded"); + this.setIconBaseWithExtension("org/sleuthkit/autopsy/communications/images/unthreaded.png" ); } @Override From 42291954b4dcbe0cfeb782a3f333f5d2dc49efb4 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 17 Jun 2019 15:28:23 -0400 Subject: [PATCH 07/16] Handled some of the codecy issues and fixed a bug --- .../autopsy/communications/relationships/MessageViewer.java | 2 ++ .../communications/relationships/ThreadChildNodeFactory.java | 4 +++- .../autopsy/communications/relationships/ThreadNode.java | 4 ++-- .../sleuthkit/autopsy/directorytree/DataResultFilterNode.java | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java index 32f0496c81..6e69841350 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java @@ -223,6 +223,8 @@ public class MessageViewer extends JPanel implements RelationshipsViewer { if (!subject.isEmpty()) { threadNameLabel.setText(subject); + } else { + threadNameLabel.setText(Bundle.MessageViewer_viewMessage_unthreaded()); } showMessagesPane(); diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java index 1fad288bba..3293ea59fd 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java @@ -143,9 +143,11 @@ final class ThreadChildNodeFactory extends ChildFactory { if(tableArtifact == null) { rootMessageMap.put(threadID, bba); } else { + // Get the date of the message BlackboardAttribute tableAttribute = tableArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT)); attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT)); + // put the earliest message into the table if(tableAttribute != null && attribute != null && tableAttribute.getValueLong() > attribute.getValueLong()) { rootMessageMap.put(threadID, bba); } @@ -171,7 +173,7 @@ final class ThreadChildNodeFactory extends ChildFactory { } if (attribute != null) { - return new ThreadNode(bba, attribute.getValueString()); + return new ThreadNode(bba, attribute.getValueString(), preferredAction); } else { // Only one of these should occur. return new UnthreadedNode(); diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java index 25cd3acf3b..a3730df69c 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java @@ -19,9 +19,9 @@ final class ThreadNode extends AbstractNode{ final private MessageNode messageNode; - ThreadNode(BlackboardArtifact artifact, String threadID) { + ThreadNode(BlackboardArtifact artifact, String threadID, Action preferredAction) { super(Children.LEAF); - messageNode = new MessageNode(artifact, threadID, null); + messageNode = new MessageNode(artifact, threadID, preferredAction); this.setIconBaseWithExtension("org/sleuthkit/autopsy/communications/images/threaded.png" ); } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index e6f8fd7cf0..3c206049d6 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -492,7 +492,7 @@ public class DataResultFilterNode extends FilterNode { public AbstractAction visit(BlackboardArtifactNode ban) { Action preferredAction = ban.getPreferredAction(); - if(preferredAction != null && preferredAction instanceof AbstractAction) { + if(preferredAction instanceof AbstractAction) { return (AbstractAction) preferredAction; } From cdd5c21787db057759fe4c29b131827b92763a80 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 18 Jun 2019 09:02:19 -0400 Subject: [PATCH 08/16] Fixed more codacy issues and scaled threads button image. --- .../relationships/MessageViewer.form | 3 - .../relationships/MessageViewer.java | 43 +++++++++++++- .../relationships/ThreadChildNodeFactory.java | 57 ++++++++++--------- 3 files changed, 73 insertions(+), 30 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.form b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.form index cbff1d5e95..37aa8bdfd5 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.form +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.form @@ -92,9 +92,6 @@ - - - diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java index 6e69841350..b7a42088d0 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java @@ -20,8 +20,12 @@ package org.sleuthkit.autopsy.communications.relationships; import java.awt.CardLayout; import java.awt.Component; +import java.awt.Graphics2D; +import java.awt.Image; import java.awt.KeyboardFocusManager; +import java.awt.RenderingHints; import java.awt.event.ActionEvent; +import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; @@ -29,6 +33,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.logging.Level; import javax.swing.AbstractAction; +import javax.swing.ImageIcon; import javax.swing.JPanel; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; @@ -134,6 +139,9 @@ public class MessageViewer extends JPanel implements RelationshipsViewer { threadMessagesPanel.setChildFactory(threadMessageNodeFactory); rootTablePane.setTableColumnsWidth(10, 20, 70); + + Image image = getScaledImage((new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/timeline/images/arrow-180.png"))).getImage(), 16, 16); + backButton.setIcon(new ImageIcon(image) ); } @Override @@ -231,14 +239,25 @@ public class MessageViewer extends JPanel implements RelationshipsViewer { } } + /** + * Make the threads pane visible. + */ private void showThreadsPane() { switchCard("threads"); } + /** + * Make the message pane visible. + */ private void showMessagesPane() { switchCard("messages"); } + /** + * Changes the visible panel (card). + * + * @param cardName Name of card to show + */ private void switchCard(String cardName) { SwingUtilities.invokeLater(new Runnable() { @Override @@ -248,6 +267,26 @@ public class MessageViewer extends JPanel implements RelationshipsViewer { } }); } + + /** + * Scales the given image to the given width and height. + * + * @param srcImg Image to scale + * @param w Image width + * @param h Image height + * + * @return Scaled version of srcImg + */ + private Image getScaledImage(Image srcImg, int w, int h){ + BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = resizedImg.createGraphics(); + + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2.drawImage(srcImg, 0, 0, w, h, null); + g2.dispose(); + + return resizedImg; + } /** * This method is called from within the constructor to initialize the form. @@ -323,7 +362,6 @@ public class MessageViewer extends JPanel implements RelationshipsViewer { gridBagConstraints.insets = new java.awt.Insets(0, 15, 0, 15); messagePanel.add(threadMessagesPanel, gridBagConstraints); - backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/timeline/images/arrow-180.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.backButton.text")); // NOI18N backButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -386,6 +424,9 @@ public class MessageViewer extends JPanel implements RelationshipsViewer { private javax.swing.JLabel threadsLabel; // End of variables declaration//GEN-END:variables + /** + * The preferred action of the table nodes. + */ class ShowThreadMessagesAction extends AbstractAction { @Override diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java index 3293ea59fd..8c4f8b40de 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadChildNodeFactory.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.communications.relationships; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.logging.Level; import javax.swing.Action; @@ -119,38 +120,42 @@ final class ThreadChildNodeFactory extends ChildFactory { * @throws TskCoreException */ private boolean createRootMessageKeys(List list, Set relationshipSources) throws TskCoreException{ - HashMap rootMessageMap = new HashMap<>(); + Map rootMessageMap = new HashMap<>(); for(Content content: relationshipSources) { - if(content instanceof BlackboardArtifact) { - BlackboardArtifact bba = (BlackboardArtifact) content; - BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID()); + if(!(content instanceof BlackboardArtifact)) { + continue; + } + + BlackboardArtifact bba = (BlackboardArtifact) content; + BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID()); - if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG - || fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG - || fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) { + if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG + || fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG + || fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) { - // We want all artifacts that do not have "threadIDs" to appear as one thread in the UI - // To achive this assign any artifact that does not have a threadID - // the "UNTHREADED_ID" - String threadID = MessageNode.UNTHREADED_ID; - BlackboardAttribute attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID)); + // We want all artifacts that do not have "threadIDs" to appear as one thread in the UI + // To achive this assign any artifact that does not have a threadID + // the "UNTHREADED_ID" + String threadID = MessageNode.UNTHREADED_ID; + BlackboardAttribute attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID)); - if(attribute != null) { - threadID = attribute.getValueString(); - } + if(attribute != null) { + threadID = attribute.getValueString(); + } - BlackboardArtifact tableArtifact = rootMessageMap.get(threadID); - if(tableArtifact == null) { - rootMessageMap.put(threadID, bba); - } else { - // Get the date of the message - BlackboardAttribute tableAttribute = tableArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT)); - attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT)); + BlackboardArtifact tableArtifact = rootMessageMap.get(threadID); + if(tableArtifact == null) { + rootMessageMap.put(threadID, bba); + } else { + // Get the date of the message + BlackboardAttribute tableAttribute = tableArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT)); + attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT)); - // put the earliest message into the table - if(tableAttribute != null && attribute != null && tableAttribute.getValueLong() > attribute.getValueLong()) { - rootMessageMap.put(threadID, bba); - } + // put the earliest message into the table + if(tableAttribute != null + && attribute != null + && tableAttribute.getValueLong() > attribute.getValueLong()) { + rootMessageMap.put(threadID, bba); } } } From 7699c53b318ecad1b422d118527e332d47d2ebce Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 18 Jun 2019 11:26:14 -0400 Subject: [PATCH 09/16] Added annotation to suppress codacy complaints --- .../autopsy/communications/relationships/MessageViewer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java index b7a42088d0..86b343cfac 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java @@ -56,9 +56,10 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; /** - * + * The main panel for the messages tab of the RelationshipViewer * */ +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives public class MessageViewer extends JPanel implements RelationshipsViewer { private static final Logger logger = Logger.getLogger(MessageViewer.class.getName()); @@ -86,7 +87,7 @@ public class MessageViewer extends JPanel implements RelationshipsViewer { "MessageViewer_viewMessage_unthreaded=Unthreaded",}) /** - * Creates new form MessageViewer2 + * Creates new form MessageViewer */ public MessageViewer() { From 3589b78f65ce850504f56cc09ca03f2e4051eb66 Mon Sep 17 00:00:00 2001 From: esaunders Date: Wed, 19 Jun 2019 11:44:32 -0400 Subject: [PATCH 10/16] Set root node before setting up paging support. --- .../autopsy/corecomponents/DataResultViewerTable.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index df2cbf5a49..e1feecf807 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -302,6 +302,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); try { if (rootNode != null) { + this.rootNode = rootNode; + /** * Check to see if we have previously created a paging support * class for this node. @@ -364,8 +366,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer { * case database round trips. */ if (rootNode != null && rootNode.getChildren().getNodesCount() > 0) { - this.rootNode = rootNode; - this.getExplorerManager().setRootContext(this.rootNode); setupTable(); } else { From ccd01682b9609c9d459c9f3a444c0ca77a1d44ff Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 19 Jun 2019 13:15:03 -0400 Subject: [PATCH 11/16] Addressed review comments and fixed ClassCastException --- .../relationships/MessageViewer.java | 11 +++------ .../MessagesChildNodeFactory.java | 3 ++- .../relationships/MessagesPanel.java | 5 ++-- .../relationships/ThreadNode.java | 24 +++++++++++++++---- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java index 86b343cfac..09f5d8e87f 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java @@ -51,9 +51,7 @@ import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.communications.ModifiableProxyLookup; -import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; /** * The main panel for the messages tab of the RelationshipViewer @@ -115,12 +113,9 @@ public class MessageViewer extends JPanel implements RelationshipsViewer { }; rootTablePane.getExplorerManager().setRootContext( - new TableFilterNode( - new DataResultFilterNode( - new AbstractNode( - Children.create(rootMessageFactory, true)), - rootTablePane.getExplorerManager()), - true)); + new AbstractNode(Children.create(rootMessageFactory, true))); + + rootTablePane.getOutlineView().setPopupAllowed(false); Outline outline = rootTablePane.getOutlineView().getOutline(); rootTablePane.getOutlineView().setPropertyColumns( diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java index d185b1a374..726fba4341 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesChildNodeFactory.java @@ -33,7 +33,8 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; /** - * + * A ChildFactory subclass for creating MessageNodes from a set of + * BlackboardArtifact objects. * */ public class MessagesChildNodeFactory extends ChildFactory{ diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java index 366d6ee43b..44f412ca30 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesPanel.java @@ -38,7 +38,8 @@ import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; /** * - * + * General Purpose class for panels that need OutlineView of message nodes at + * the top with a MessageContentViewer at the bottom. */ public class MessagesPanel extends javax.swing.JPanel implements Lookup.Provider { @@ -47,7 +48,7 @@ public class MessagesPanel extends javax.swing.JPanel implements Lookup.Provider private final PropertyChangeListener focusPropertyListener; /** - * Creates new form ThreadMessagesPanel + * Creates new form MessagesPanel */ public MessagesPanel() { initComponents(); diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java index a3730df69c..f398b94757 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2019 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.communications.relationships; @@ -12,8 +25,9 @@ import org.openide.nodes.Sheet; import org.sleuthkit.datamodel.BlackboardArtifact; /** - * - * @author kelly + * An AbstractNode subclass which wraps a MessagNode object. Doing this allows + * for the reuse of the createSheet and other function from MessageNode, but + * also some customizing of how a ThreadNode is shown. */ final class ThreadNode extends AbstractNode{ From d05a440065f37e07f029391d5e26f3518d628256 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Wed, 19 Jun 2019 13:17:29 -0400 Subject: [PATCH 12/16] Updated docs. --- CoreLibs/src/org/sleuthkit/autopsy/corelibs/OpenCvLoader.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CoreLibs/src/org/sleuthkit/autopsy/corelibs/OpenCvLoader.java b/CoreLibs/src/org/sleuthkit/autopsy/corelibs/OpenCvLoader.java index 7cfad05bc8..0027203cd7 100644 --- a/CoreLibs/src/org/sleuthkit/autopsy/corelibs/OpenCvLoader.java +++ b/CoreLibs/src/org/sleuthkit/autopsy/corelibs/OpenCvLoader.java @@ -41,6 +41,9 @@ public final class OpenCvLoader { * Return whether or not the OpenCV library has been loaded. * * @return - true if the opencv library is loaded or false if it is not + * @throws UnsatisfiedLinkError - A COPY of the exception that prevented OpenCV from loading. + * Note that the stack trace in the exception can be confusing because it refers to a + * past invocation. */ public static boolean isOpenCvLoaded() throws UnsatisfiedLinkError { if (!OPEN_CV_LOADED) { From 7cae653287cc11e37ced96640358abe5cd9dda65 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 19 Jun 2019 15:10:46 -0400 Subject: [PATCH 13/16] Add more info to DataSourceIngestJob logging --- .../autopsy/ingest/DataSourceIngestJob.java | 67 ++++++++++++++----- .../autopsy/ingest/IngestManager.java | 2 +- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java index 6563dd3540..bdf8d75505 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014-2018 Basis Technology Corp. + * Copyright 2014-2019 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -286,7 +286,7 @@ public final class DataSourceIngestJob { this.addIngestModules(fileIngestModuleTemplates, IngestModuleType.FILE_LEVEL, skCase); this.addIngestModules(secondStageDataSourceModuleTemplates, IngestModuleType.DATA_SOURCE_LEVEL, skCase); } catch (TskCoreException | NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Failed to add ingest modules to database.", ex); + logErrorMessage(Level.WARNING, "Failed to add ingest modules listing to case database", ex); } } @@ -421,13 +421,13 @@ public final class DataSourceIngestJob { try { this.ingestJob = Case.getCurrentCaseThrows().getSleuthkitCase().addIngestJob(dataSource, NetworkUtils.getLocalHostName(), ingestModules, new Date(this.createTime), new Date(0), IngestJobStatusType.STARTED, ""); } catch (TskCoreException | NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Failed to add ingest job to database.", ex); + logErrorMessage(Level.WARNING, "Failed to add ingest job info to case database", ex); //NON-NLS } if (this.hasFirstStageDataSourceIngestPipeline() || this.hasFileIngestPipeline()) { - logger.log(Level.INFO, "Starting first stage analysis for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS + logInfoMessage("Starting first stage analysis"); //NON-NLS this.startFirstStage(); } else if (this.hasSecondStageDataSourceIngestPipeline()) { - logger.log(Level.INFO, "Starting second stage analysis for {0} (jobId={1}), no first stage configured", new Object[]{dataSource.getName(), this.id}); //NON-NLS + logInfoMessage("Starting second stage analysis"); //NON-NLS this.startSecondStage(); } } @@ -521,13 +521,13 @@ public final class DataSourceIngestJob { * Schedule the first stage tasks. */ if (this.hasFirstStageDataSourceIngestPipeline() && this.hasFileIngestPipeline()) { - logger.log(Level.INFO, "Scheduling first stage data source and file level analysis tasks for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS + logInfoMessage("Scheduling first stage data source and file level analysis tasks"); //NON-NLS DataSourceIngestJob.taskScheduler.scheduleIngestTasks(this); } else if (this.hasFirstStageDataSourceIngestPipeline()) { - logger.log(Level.INFO, "Scheduling first stage data source level analysis tasks for {0} (jobId={1}), no file level analysis configured", new Object[]{dataSource.getName(), this.id}); //NON-NLS + logInfoMessage("Scheduling first stage data source level analysis tasks"); //NON-NLS DataSourceIngestJob.taskScheduler.scheduleDataSourceIngestTask(this); } else { - logger.log(Level.INFO, "Scheduling file level analysis tasks for {0} (jobId={1}), no first stage data source level analysis configured", new Object[]{dataSource.getName(), this.id}); //NON-NLS + logInfoMessage("Scheduling file level analysis tasks, no first stage data source level analysis configured"); //NON-NLS DataSourceIngestJob.taskScheduler.scheduleFileIngestTasks(this, this.files); /** @@ -546,7 +546,7 @@ public final class DataSourceIngestJob { * Starts the second stage of this ingest job. */ private void startSecondStage() { - logger.log(Level.INFO, "Starting second stage analysis for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS + logInfoMessage("Starting second stage analysis"); //NON-NLS this.stage = DataSourceIngestJob.Stages.SECOND; if (this.doUI) { this.startDataSourceIngestProgressBar(); @@ -554,7 +554,7 @@ public final class DataSourceIngestJob { synchronized (this.dataSourceIngestPipelineLock) { this.currentDataSourceIngestPipeline = this.secondStageDataSourceIngestPipeline; } - logger.log(Level.INFO, "Scheduling second stage data source level analysis tasks for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS + logInfoMessage("Scheduling second stage data source level analysis tasks"); //NON-NLS DataSourceIngestJob.taskScheduler.scheduleDataSourceIngestTask(this); } @@ -643,7 +643,7 @@ public final class DataSourceIngestJob { * job and starts the second stage, if appropriate. */ private void finishFirstStage() { - logger.log(Level.INFO, "Finished first stage analysis for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS + logInfoMessage("Finished first stage analysis"); //NON-NLS // Shut down the file ingest pipelines. Note that no shut down is // required for the data source ingest pipeline because data source @@ -693,7 +693,7 @@ public final class DataSourceIngestJob { * Shuts down the ingest pipelines and progress bars for this job. */ private void finish() { - logger.log(Level.INFO, "Finished analysis for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS + logInfoMessage("Finished analysis"); //NON-NLS this.stage = DataSourceIngestJob.Stages.FINALIZATION; if (this.doUI) { @@ -711,19 +711,19 @@ public final class DataSourceIngestJob { try { ingestJob.setIngestJobStatus(IngestJobStatusType.CANCELLED); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to set ingest status for ingest job in database.", ex); + logErrorMessage(Level.WARNING, "Failed to update ingest job status in case database", ex); } } else { try { ingestJob.setIngestJobStatus(IngestJobStatusType.COMPLETED); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to set ingest status for ingest job in database.", ex); + logErrorMessage(Level.WARNING, "Failed to update ingest job status in case database", ex); } } try { this.ingestJob.setEndDateTime(new Date()); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to set end date for ingest job in database.", ex); + logErrorMessage(Level.WARNING, "Failed to set job end date in case database", ex); } } this.parentJob.dataSourceJobFinished(this); @@ -842,6 +842,7 @@ public final class DataSourceIngestJob { if (DataSourceIngestJob.Stages.FIRST == this.stage) { DataSourceIngestJob.taskScheduler.fastTrackFileIngestTasks(this, files); } else { + logErrorMessage(Level.SEVERE, "Adding files to job during second stage analysis not supported"); DataSourceIngestJob.logger.log(Level.SEVERE, "Adding files during second stage not supported"); //NON-NLS } @@ -1066,6 +1067,40 @@ public final class DataSourceIngestJob { return this.cancellationReason; } + /** + * Writes an info message to the application log that includes the data + * source name, data source object id, and the job id. + * + * @param message The message. + */ + private void logInfoMessage(String message) { + logger.log(Level.INFO, String.format("%s (data source = %s, objId = %d, jobId = %d)", message, dataSource.getName(), dataSource.getId(), id)); //NON-NLS + } + + /** + * Writes an error message to the application log that includes the data + * source name, data source object id, and the job id. + * + * @param level The logging level for the message. + * @param message The message. + * @param throwable The error associated with the error, may be null. + */ + private void logErrorMessage(Level level, String message, Throwable throwable) { + logger.log(level, String.format("%s (data source = %s, objId = %d, jobId = %d)", message, dataSource.getName(), dataSource.getId(), id), throwable); //NON-NLS + } + + /** + * Writes an error message to the application log that includes the data + * source name, data source object id, and the job id. + * + * @param level The logging level for the message. + * @param message The message. + * @param ex The exception associated with the error, may be null. + */ + private void logErrorMessage(Level level, String message) { + logger.log(level, String.format("%s (data source = %s, objId = %d, jobId = %d)", message, dataSource.getName(), dataSource.getId(), id)); //NON-NLS + } + /** * Write ingest module errors to the log. * @@ -1073,7 +1108,7 @@ public final class DataSourceIngestJob { */ private void logIngestModuleErrors(List errors) { for (IngestModuleError error : errors) { - DataSourceIngestJob.logger.log(Level.SEVERE, String.format("%s experienced an error analyzing %s (jobId=%d)", error.getModuleDisplayName(), dataSource.getName(), this.id), error.getThrowable()); //NON-NLS + logErrorMessage(Level.SEVERE, String.format("%s experienced an error during analysis", error.getModuleDisplayName()), error.getThrowable()); //NON-NLS } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index d5a2240ca5..8205621450 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -403,10 +403,10 @@ public class IngestManager implements IngestProgressSnapshotProvider { synchronized (ingestJobsById) { ingestJobsById.put(job.getId(), job); } + IngestManager.logger.log(Level.INFO, "Starting ingest job {0}", job.getId()); //NON-NLS errors = job.start(); if (errors.isEmpty()) { this.fireIngestJobStarted(job.getId()); - IngestManager.logger.log(Level.INFO, "Ingest job {0} started", job.getId()); //NON-NLS } else { synchronized (ingestJobsById) { this.ingestJobsById.remove(job.getId()); From 8920e94dedeb85bc65609ee67362bea654e76268 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 19 Jun 2019 15:15:39 -0400 Subject: [PATCH 14/16] Add more info to DataSourceIngestJob logging --- Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java | 3 +-- Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java index bdf8d75505..674f8488af 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java @@ -843,7 +843,6 @@ public final class DataSourceIngestJob { DataSourceIngestJob.taskScheduler.fastTrackFileIngestTasks(this, files); } else { logErrorMessage(Level.SEVERE, "Adding files to job during second stage analysis not supported"); - DataSourceIngestJob.logger.log(Level.SEVERE, "Adding files during second stage not supported"); //NON-NLS } /** @@ -1095,7 +1094,7 @@ public final class DataSourceIngestJob { * * @param level The logging level for the message. * @param message The message. - * @param ex The exception associated with the error, may be null. + * @param ex The exception associated with the error. */ private void logErrorMessage(Level level, String message) { logger.log(level, String.format("%s (data source = %s, objId = %d, jobId = %d)", message, dataSource.getName(), dataSource.getId(), id)); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index 8205621450..b59e0a6ccb 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012-2018 Basis Technology Corp. + * Copyright 2012-2019 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); From cded8ca655d53a822b43b0ce1674c1f7465980a1 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 19 Jun 2019 15:17:20 -0400 Subject: [PATCH 15/16] Add more info to DataSourceIngestJob logging --- Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java index 674f8488af..22745a3c54 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java @@ -1082,7 +1082,7 @@ public final class DataSourceIngestJob { * * @param level The logging level for the message. * @param message The message. - * @param throwable The error associated with the error, may be null. + * @param throwable The throwable associated with the error. */ private void logErrorMessage(Level level, String message, Throwable throwable) { logger.log(level, String.format("%s (data source = %s, objId = %d, jobId = %d)", message, dataSource.getName(), dataSource.getId(), id), throwable); //NON-NLS @@ -1094,7 +1094,6 @@ public final class DataSourceIngestJob { * * @param level The logging level for the message. * @param message The message. - * @param ex The exception associated with the error. */ private void logErrorMessage(Level level, String message) { logger.log(level, String.format("%s (data source = %s, objId = %d, jobId = %d)", message, dataSource.getName(), dataSource.getId(), id)); //NON-NLS From 08d9b97bcd9d96cd48a862e823b5863d7a1146f7 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 21 Jun 2019 13:08:31 -0400 Subject: [PATCH 16/16] Update versioning for TSK 4.6.7, Autopsy 4.12.0 releases --- Core/nbproject/project.properties | 2 +- Core/nbproject/project.xml | 4 ++-- TSKVersion.xml | 2 +- docs/doxygen-user/Doxyfile | 4 ++-- docs/doxygen/Doxyfile | 4 ++-- nbproject/project.properties | 6 +++--- unix_setup.sh | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) 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/TSKVersion.xml b/TSKVersion.xml index 3c03006088..7e65087fae 100644 --- a/TSKVersion.xml +++ b/TSKVersion.xml @@ -1,3 +1,3 @@ - + diff --git a/docs/doxygen-user/Doxyfile b/docs/doxygen-user/Doxyfile index 6f16153151..7991a0cd95 100644 --- a/docs/doxygen-user/Doxyfile +++ b/docs/doxygen-user/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy User Documentation" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.11.0 +PROJECT_NUMBER = 4.12.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -1025,7 +1025,7 @@ GENERATE_HTML = YES # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_OUTPUT = 4.11.0 +HTML_OUTPUT = 4.12.0 # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index a7463ac441..bf66159b48 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.11.0 +PROJECT_NUMBER = 4.12.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears a the top of each page and should give viewer a @@ -1063,7 +1063,7 @@ GENERATE_HTML = YES # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_OUTPUT = api-docs/4.11.0/ +HTML_OUTPUT = api-docs/4.12.0/ # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). diff --git a/nbproject/project.properties b/nbproject/project.properties index dbc771a543..0014be6b88 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -4,10 +4,10 @@ app.title=Autopsy ### lowercase version of above app.name=${branding.token} ### if left unset, version will default to today's date -app.version=4.11.0 +app.version=4.12.0 ### build.type must be one of: DEVELOPMENT, RELEASE -#build.type=RELEASE -build.type=DEVELOPMENT +build.type=RELEASE +#build.type=DEVELOPMENT project.org.netbeans.progress=org-netbeans-api-progress project.org.sleuthkit.autopsy.experimental=Experimental diff --git a/unix_setup.sh b/unix_setup.sh index 0b252b2598..eecf1ed8c5 100644 --- a/unix_setup.sh +++ b/unix_setup.sh @@ -5,7 +5,7 @@ # NOTE: update_sleuthkit_version.pl updates this value and relies # on it keeping the same name and whitespace. Don't change it. -TSK_VERSION=4.6.6 +TSK_VERSION=4.6.7 # In the beginning...