Autopsy  4.17.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
MessageArtifactViewer.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2017-2020 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.contentviewers.artifactviewers;
20 
22 import java.awt.Color;
23 import java.awt.Component;
24 import java.awt.ComponentOrientation;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Optional;
30 import java.util.Set;
31 import java.util.logging.Level;
32 import javax.swing.JScrollPane;
33 import javax.swing.text.JTextComponent;
34 import org.apache.commons.lang3.StringUtils;
35 import org.jsoup.Jsoup;
36 import org.jsoup.nodes.Document;
37 import org.openide.explorer.ExplorerManager;
38 import org.openide.nodes.AbstractNode;
39 import org.openide.nodes.Children;
40 import org.openide.nodes.Node;
41 import org.openide.util.NbBundle;
42 import org.openide.util.lookup.ServiceProvider;
53 import org.sleuthkit.datamodel.AbstractFile;
54 import org.sleuthkit.datamodel.BlackboardArtifact;
55 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG;
56 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT;
57 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE;
58 import org.sleuthkit.datamodel.BlackboardAttribute;
59 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT;
60 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME;
61 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_RCVD;
62 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION;
63 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CC;
64 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML;
65 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN;
66 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF;
67 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM;
68 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_TO;
69 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_HEADERS;
70 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM;
71 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO;
72 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT;
73 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT;
74 import org.sleuthkit.datamodel.Content;
75 import org.sleuthkit.datamodel.TskCoreException;
76 import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil;
77 import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments;
78 import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments.FileAttachment;
79 import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments.Attachment;
80 import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments.URLAttachment;
81 
85 @ServiceProvider(service = ArtifactContentViewer.class)
86 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
87 public class MessageArtifactViewer extends javax.swing.JPanel implements ArtifactContentViewer {
88 
93  class TextComponent implements TranslatablePanel.ContentComponent {
94 
95  private final Component rootComponent;
96  private final AutoWrappingJTextPane childTextComponent;
97 
98  TextComponent() {
99  childTextComponent = new AutoWrappingJTextPane();
100  childTextComponent.setEditable(false);
101 
102  JScrollPane parentComponent = new JScrollPane();
103  parentComponent.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
104  parentComponent.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
105  parentComponent.setViewportView(childTextComponent);
106  rootComponent = parentComponent;
107  }
108 
109  @Override
110  public Component getRootComponent() {
111  return rootComponent;
112  }
113 
114  @Override
115  public void setContent(String content, ComponentOrientation orientation) throws TranslatablePanelException {
116  childTextComponent.setText(content == null ? "" : content);
117  childTextComponent.setComponentOrientation(orientation);
118  childTextComponent.setCaretPosition(0);
119  }
120  }
121 
122  private static final long serialVersionUID = 1L;
123  private static final Logger LOGGER = Logger.getLogger(MessageArtifactViewer.class.getName());
124  private static final BlackboardAttribute.Type TSK_ASSOCIATED_TYPE = new BlackboardAttribute.Type(TSK_ASSOCIATED_ARTIFACT);
125 
126  private static final int HDR_TAB_INDEX = 0;
127  private static final int TEXT_TAB_INDEX = 1;
128  private static final int HTML_TAB_INDEX = 2;
129  private static final int RTF_TAB_INDEX = 3;
130  private static final int ATTM_TAB_INDEX = 4;
131  private static final int ACCT_TAB_INDEX = 5;
132 
133  private final List<JTextComponent> textAreas;
135  private final TranslatablePanel textPanel = new TranslatablePanel(new TextComponent());
139  private BlackboardArtifact artifact;
140  private final DataResultPanel drp;
141  private ExplorerManager drpExplorerManager;
142 
143  private MessageAccountPanel accountsPanel;
144 
145  public MessageArtifactViewer(List<JTextComponent> textAreas, DataResultPanel drp) {
146  this.textAreas = textAreas;
147  this.drp = drp;
148  }
149 
153  @NbBundle.Messages("MessageArtifactViewer.AttachmentPanel.title=Attachments")
155  initComponents();
156  accountsPanel = new MessageAccountPanel();
157 
158  htmlPane.add(htmlPanel);
159  envelopePanel.setBackground(new Color(0, 0, 0, 38));
160  drp = DataResultPanel.createInstanceUninitialized(Bundle.MessageArtifactViewer_AttachmentPanel_title(), "", new TableFilterNode(Node.EMPTY, false), 0, null);
161  attachmentsScrollPane.setViewportView(drp);
162 
163  msgbodyTabbedPane.insertTab(NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.textbodyScrollPane.TabConstraints.tabTitle"),
164  null,
165  textPanel,
166  null,
167  TEXT_TAB_INDEX);
168 
169  msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, true);
170 
171  accountScrollPane.setViewportView(accountsPanel);
172  msgbodyTabbedPane.setEnabledAt(ACCT_TAB_INDEX, CentralRepository.isEnabled());
173 
174  /*
175  * HTML tab uses the HtmlPanel instead of an internal text pane, so we
176  * use 'null' for that index.
177  */
178  textAreas = Arrays.asList(headersTextArea, null, null, rtfbodyTextPane);
179 
180  Utilities.configureTextPaneAsRtf(rtfbodyTextPane);
181  resetComponent();
182 
183  }
184 
185  @Override
186  public void addNotify() {
187  super.addNotify(); //To change body of generated methods, choose Tools | Templates.
188 
189  drp.open();
190  drpExplorerManager = drp.getExplorerManager();
191  drpExplorerManager.addPropertyChangeListener(evt
192  -> viewInNewWindowButton.setEnabled(drpExplorerManager.getSelectedNodes().length == 1));
193  }
194 
200  @SuppressWarnings("unchecked")
201  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
202  private void initComponents() {
203 
204  envelopePanel = new javax.swing.JPanel();
205  fromLabel = new javax.swing.JLabel();
206  datetimeText = new javax.swing.JLabel();
207  fromText = new javax.swing.JLabel();
208  toLabel = new javax.swing.JLabel();
209  toText = new javax.swing.JLabel();
210  ccLabel = new javax.swing.JLabel();
211  ccText = new javax.swing.JLabel();
212  subjectLabel = new javax.swing.JLabel();
213  subjectText = new javax.swing.JLabel();
214  directionText = new javax.swing.JLabel();
215  msgbodyTabbedPane = new javax.swing.JTabbedPane();
216  headersScrollPane = new javax.swing.JScrollPane();
217  headersTextArea = new javax.swing.JTextArea();
218  htmlPane = new javax.swing.JPanel();
219  rtfbodyScrollPane = new javax.swing.JScrollPane();
220  rtfbodyTextPane = new javax.swing.JTextPane();
221  attachmentsPanel = new javax.swing.JPanel();
222  viewInNewWindowButton = new javax.swing.JButton();
223  attachmentsScrollPane = new javax.swing.JScrollPane();
224  accountsTab = new javax.swing.JPanel();
225  accountScrollPane = new javax.swing.JScrollPane();
226 
227  envelopePanel.setBackground(new java.awt.Color(204, 204, 204));
228 
229  org.openide.awt.Mnemonics.setLocalizedText(fromLabel, org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.fromLabel.text")); // NOI18N
230 
231  datetimeText.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
232  org.openide.awt.Mnemonics.setLocalizedText(datetimeText, org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.datetimeText.text")); // NOI18N
233 
234  org.openide.awt.Mnemonics.setLocalizedText(fromText, org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.fromText.text")); // NOI18N
235 
236  org.openide.awt.Mnemonics.setLocalizedText(toLabel, org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.toLabel.text")); // NOI18N
237 
238  org.openide.awt.Mnemonics.setLocalizedText(toText, org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.toText.text")); // NOI18N
239  toText.setAutoscrolls(true);
240  toText.setMinimumSize(new java.awt.Dimension(27, 14));
241 
242  org.openide.awt.Mnemonics.setLocalizedText(ccLabel, org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.ccLabel.text")); // NOI18N
243 
244  org.openide.awt.Mnemonics.setLocalizedText(ccText, org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.ccText.text")); // NOI18N
245  ccText.setMinimumSize(new java.awt.Dimension(27, 14));
246 
247  org.openide.awt.Mnemonics.setLocalizedText(subjectLabel, org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.subjectLabel.text")); // NOI18N
248 
249  org.openide.awt.Mnemonics.setLocalizedText(subjectText, org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.subjectText.text")); // NOI18N
250  subjectText.setMinimumSize(new java.awt.Dimension(26, 14));
251 
252  directionText.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
253  org.openide.awt.Mnemonics.setLocalizedText(directionText, org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.directionText.text")); // NOI18N
254 
255  javax.swing.GroupLayout envelopePanelLayout = new javax.swing.GroupLayout(envelopePanel);
256  envelopePanel.setLayout(envelopePanelLayout);
257  envelopePanelLayout.setHorizontalGroup(
258  envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
259  .addGroup(envelopePanelLayout.createSequentialGroup()
260  .addGap(5, 5, 5)
261  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
262  .addGroup(envelopePanelLayout.createSequentialGroup()
263  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
264  .addComponent(fromLabel)
265  .addComponent(toLabel))
266  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
267  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
268  .addGroup(envelopePanelLayout.createSequentialGroup()
269  .addComponent(toText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
270  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
271  .addComponent(directionText, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE))
272  .addGroup(envelopePanelLayout.createSequentialGroup()
273  .addComponent(fromText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
274  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
275  .addComponent(datetimeText, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE))))
276  .addGroup(envelopePanelLayout.createSequentialGroup()
277  .addComponent(ccLabel)
278  .addGap(26, 26, 26)
279  .addComponent(ccText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
280  .addGroup(envelopePanelLayout.createSequentialGroup()
281  .addComponent(subjectLabel)
282  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
283  .addComponent(subjectText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
284  .addGap(5, 5, 5))
285  );
286  envelopePanelLayout.setVerticalGroup(
287  envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
288  .addGroup(envelopePanelLayout.createSequentialGroup()
289  .addGap(5, 5, 5)
290  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
291  .addComponent(fromLabel)
292  .addComponent(datetimeText)
293  .addComponent(fromText))
294  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
295  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
296  .addComponent(toLabel)
297  .addComponent(toText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
298  .addComponent(directionText))
299  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
300  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
301  .addComponent(ccLabel)
302  .addComponent(ccText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
303  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
304  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
305  .addComponent(subjectLabel)
306  .addComponent(subjectText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
307  .addGap(5, 5, 5))
308  );
309 
310  headersScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
311  headersScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
312 
313  headersTextArea.setEditable(false);
314  headersTextArea.setColumns(20);
315  headersTextArea.setLineWrap(true);
316  headersTextArea.setRows(5);
317  headersTextArea.setWrapStyleWord(true);
318  headersScrollPane.setViewportView(headersTextArea);
319 
320  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.headersScrollPane.TabConstraints.tabTitle"), headersScrollPane); // NOI18N
321 
322  htmlPane.setLayout(new java.awt.BorderLayout());
323  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.htmlPane.TabConstraints.tabTitle"), htmlPane); // NOI18N
324 
325  rtfbodyScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
326 
327  rtfbodyTextPane.setEditable(false);
328  rtfbodyScrollPane.setViewportView(rtfbodyTextPane);
329 
330  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.rtfbodyScrollPane.TabConstraints.tabTitle"), rtfbodyScrollPane); // NOI18N
331 
332  org.openide.awt.Mnemonics.setLocalizedText(viewInNewWindowButton, org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.viewInNewWindowButton.text")); // NOI18N
333  viewInNewWindowButton.addActionListener(new java.awt.event.ActionListener() {
334  public void actionPerformed(java.awt.event.ActionEvent evt) {
335  viewInNewWindowButtonActionPerformed(evt);
336  }
337  });
338 
339  javax.swing.GroupLayout attachmentsPanelLayout = new javax.swing.GroupLayout(attachmentsPanel);
340  attachmentsPanel.setLayout(attachmentsPanelLayout);
341  attachmentsPanelLayout.setHorizontalGroup(
342  attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
343  .addGroup(attachmentsPanelLayout.createSequentialGroup()
344  .addGap(0, 0, 0)
345  .addGroup(attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
346  .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, attachmentsPanelLayout.createSequentialGroup()
347  .addComponent(viewInNewWindowButton)
348  .addGap(3, 3, 3))
349  .addComponent(attachmentsScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 647, Short.MAX_VALUE)))
350  );
351  attachmentsPanelLayout.setVerticalGroup(
352  attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
353  .addGroup(attachmentsPanelLayout.createSequentialGroup()
354  .addGap(0, 0, 0)
355  .addComponent(viewInNewWindowButton)
356  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
357  .addComponent(attachmentsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 333, Short.MAX_VALUE)
358  .addGap(0, 0, 0))
359  );
360 
361  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.attachmentsPanel.TabConstraints.tabTitle"), attachmentsPanel); // NOI18N
362 
363  accountsTab.setLayout(new java.awt.BorderLayout());
364  accountsTab.add(accountScrollPane, java.awt.BorderLayout.CENTER);
365 
366  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageArtifactViewer.class, "MessageArtifactViewer.accountsTab.TabConstraints.tabTitle"), accountsTab); // NOI18N
367 
368  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
369  this.setLayout(layout);
370  layout.setHorizontalGroup(
371  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
372  .addGroup(layout.createSequentialGroup()
373  .addGap(5, 5, 5)
374  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
375  .addComponent(msgbodyTabbedPane)
376  .addComponent(envelopePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
377  .addGap(5, 5, 5))
378  );
379  layout.setVerticalGroup(
380  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
381  .addGroup(layout.createSequentialGroup()
382  .addGap(5, 5, 5)
383  .addComponent(envelopePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
384  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
385  .addComponent(msgbodyTabbedPane)
386  .addGap(5, 5, 5))
387  );
388  }// </editor-fold>//GEN-END:initComponents
389 
390  private void viewInNewWindowButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewInNewWindowButtonActionPerformed
391  new NewWindowViewAction("View in new window", drpExplorerManager.getSelectedNodes()[0]).actionPerformed(evt);
392  }//GEN-LAST:event_viewInNewWindowButtonActionPerformed
393 
394 
395  // Variables declaration - do not modify//GEN-BEGIN:variables
396  private javax.swing.JScrollPane accountScrollPane;
397  private javax.swing.JPanel accountsTab;
398  private javax.swing.JPanel attachmentsPanel;
399  private javax.swing.JScrollPane attachmentsScrollPane;
400  private javax.swing.JLabel ccLabel;
401  private javax.swing.JLabel ccText;
402  private javax.swing.JLabel datetimeText;
403  private javax.swing.JLabel directionText;
404  private javax.swing.JPanel envelopePanel;
405  private javax.swing.JLabel fromLabel;
406  private javax.swing.JLabel fromText;
407  private javax.swing.JScrollPane headersScrollPane;
408  private javax.swing.JTextArea headersTextArea;
409  private javax.swing.JPanel htmlPane;
410  private javax.swing.JTabbedPane msgbodyTabbedPane;
411  private javax.swing.JScrollPane rtfbodyScrollPane;
412  private javax.swing.JTextPane rtfbodyTextPane;
413  private javax.swing.JLabel subjectLabel;
414  private javax.swing.JLabel subjectText;
415  private javax.swing.JLabel toLabel;
416  private javax.swing.JLabel toText;
417  private javax.swing.JButton viewInNewWindowButton;
418  // End of variables declaration//GEN-END:variables
419 
420  @Override
421  public void setArtifact(BlackboardArtifact artifact) {
422  this.artifact = artifact;
423  if (artifact == null) {
424  resetComponent();
425  return;
426  }
427 
428  /*
429  * If the artifact is a keyword hit, use the associated artifact as the
430  * one to show in this viewer
431  */
432  if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) {
433  try {
434  getAssociatedArtifact(artifact).ifPresent(associatedArtifact -> {
435  this.artifact = associatedArtifact;
436  });
437  } catch (TskCoreException ex) {
438  LOGGER.log(Level.SEVERE, "error getting associated artifact", ex);
439  }
440  }
441 
442  if (this.artifact.getArtifactTypeID() == TSK_MESSAGE.getTypeID()) {
443  displayMsg();
444  } else if (this.artifact.getArtifactTypeID() == TSK_EMAIL_MSG.getTypeID()) {
445  displayEmailMsg();
446  } else {
447  resetComponent();
448  }
449 
450  msgbodyTabbedPane.setEnabledAt(ACCT_TAB_INDEX, true);
451  accountsPanel.setArtifact(artifact);
452  }
453 
464  private static Optional<BlackboardArtifact> getAssociatedArtifact(final BlackboardArtifact artifact) throws TskCoreException {
465  BlackboardAttribute attribute = artifact.getAttribute(TSK_ASSOCIATED_TYPE);
466  if (attribute != null) {
467  return Optional.of(artifact.getSleuthkitCase().getArtifactByArtifactId(attribute.getValueLong()));
468  }
469  return Optional.empty();
470  }
471 
472  @Override
473  public Component getComponent() {
474  return this;
475  }
476 
477  private void resetComponent() {
478  // reset all fields
479  fromText.setText("");
480  fromLabel.setEnabled(false);
481  toText.setText("");
482  toLabel.setEnabled(false);
483  ccText.setText("");
484  ccLabel.setEnabled(false);
485  subjectText.setText("");
486  subjectLabel.setEnabled(false);
487  datetimeText.setText("");
488  datetimeText.setEnabled(false);
489  directionText.setText("");
490  directionText.setEnabled(false);
491 
492  headersTextArea.setText("");
493  rtfbodyTextPane.setText("");
494  htmlPanel.reset();
495  textPanel.reset();
496  msgbodyTabbedPane.setEnabled(false);
497  drp.setNode(null);
498  }
499 
500  @Override
501  public boolean isSupported(BlackboardArtifact artifact) {
502  if (artifact == null) {
503  return false;
504  }
505  //if the artifact is a keyword hit, check if its associated artifact is a message or email.
506  if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) {
507  try {
508  if (getAssociatedArtifact(artifact).map(MessageArtifactViewer::isMessageArtifact).orElse(false)) {
509  return true;
510  }
511  } catch (TskCoreException ex) {
512  LOGGER.log(Level.SEVERE, "error getting associated artifact", ex);
513  }
514  }
515  return isMessageArtifact(artifact);
516  }
517 
527  public static boolean isMessageArtifact(BlackboardArtifact nodeArtifact) {
528  final int artifactTypeID = nodeArtifact.getArtifactTypeID();
529  return artifactTypeID == TSK_EMAIL_MSG.getTypeID()
530  || artifactTypeID == TSK_MESSAGE.getTypeID();
531  }
532 
542  private void configureTextArea(BlackboardAttribute.ATTRIBUTE_TYPE type, int index) throws TskCoreException {
543  String attributeText = getAttributeValueSafe(artifact, type);
544 
545  if (index == HTML_TAB_INDEX && StringUtils.isNotBlank(attributeText)) {
546  htmlPanel.setHtmlText(attributeText);
547  } else if (index == TEXT_TAB_INDEX && StringUtils.isNotBlank(attributeText)) {
548  textPanel.setContent(attributeText, artifact.toString());
549  } else {
550  JTextComponent textComponent = textAreas.get(index);
551  if (textComponent != null) {
552  textComponent.setText(attributeText);
553  textComponent.setCaretPosition(0); //make sure we start at the top
554  }
555  }
556 
557  final boolean hasText = attributeText.length() > 0;
558 
559  msgbodyTabbedPane.setEnabledAt(index, hasText);
560  if (hasText) {
561  msgbodyTabbedPane.setSelectedIndex(index);
562  }
563  }
564 
565  private void enableCommonFields() {
566  msgbodyTabbedPane.setEnabled(true);
567  fromLabel.setEnabled(true);
568  toLabel.setEnabled(true);
569  subjectLabel.setEnabled(true);
570  datetimeText.setEnabled(true);
571  }
572 
573  private void configureAttachments() throws TskCoreException {
574 
575  final Set<Attachment> attachments;
576 
577  // Attachments are specified in an attribute TSK_ATTACHMENTS as JSON attribute
578  BlackboardAttribute attachmentsAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS));
579  if (attachmentsAttr != null) {
580 
581  attachments = new HashSet<>();
582  try {
583  MessageAttachments msgAttachments = BlackboardJsonAttrUtil.fromAttribute(attachmentsAttr, MessageAttachments.class);
584  Collection<FileAttachment> fileAttachments = msgAttachments.getFileAttachments();
585  for (FileAttachment fileAttachment : fileAttachments) {
586  attachments.add(fileAttachment);
587  }
588  Collection<URLAttachment> urlAttachments = msgAttachments.getUrlAttachments();
589  for (URLAttachment urlAttachment : urlAttachments) {
590  attachments.add(urlAttachment);
591  }
592  } catch (BlackboardJsonAttrUtil.InvalidJsonException ex) {
593  LOGGER.log(Level.WARNING, String.format("Unable to parse json for MessageAttachments object in artifact: %s", artifact.getName()), ex);
594  }
595  } else { // For backward compatibility - email attachements are derived files and children of the email message artifact
596  attachments = new HashSet<>();
597  for (Content child : artifact.getChildren()) {
598  if (child instanceof AbstractFile) {
599  attachments.add(new FileAttachment((AbstractFile) child));
600  }
601  }
602  }
603 
604  final int numberOfAttachments = attachments.size();
605 
606  msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, numberOfAttachments > 0);
607  msgbodyTabbedPane.setTitleAt(ATTM_TAB_INDEX, "Attachments (" + numberOfAttachments + ")");
608  drp.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(
609  new AttachmentsChildren(attachments))), true));
610  }
611 
612  private void displayEmailMsg() {
613  enableCommonFields();
614 
615  directionText.setEnabled(false);
616  ccLabel.setEnabled(true);
617 
618  try {
619  this.fromText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_FROM));
620  this.fromText.setToolTipText(getAttributeValueSafe(artifact, TSK_EMAIL_FROM));
621  this.toText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_TO));
622  this.toText.setToolTipText(getAttributeValueSafe(artifact, TSK_EMAIL_TO));
623  this.directionText.setText("");
624  this.ccText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_CC));
625  this.ccText.setToolTipText(getAttributeValueSafe(artifact, TSK_EMAIL_CC));
626  this.subjectText.setText(getAttributeValueSafe(artifact, TSK_SUBJECT));
627  this.datetimeText.setText(getAttributeValueSafe(artifact, TSK_DATETIME_RCVD));
628 
629  configureTextArea(TSK_HEADERS, HDR_TAB_INDEX);
630  configureTextArea(TSK_EMAIL_CONTENT_PLAIN, TEXT_TAB_INDEX);
631  configureTextArea(TSK_EMAIL_CONTENT_HTML, HTML_TAB_INDEX);
632  configureTextArea(TSK_EMAIL_CONTENT_RTF, RTF_TAB_INDEX);
633  configureAttachments();
634  } catch (TskCoreException ex) {
635  LOGGER.log(Level.WARNING, "Failed to get attributes for email message.", ex); //NON-NLS
636  }
637  }
638 
639  private void displayMsg() {
640  enableCommonFields();
641 
642  directionText.setEnabled(true);
643  ccLabel.setEnabled(false);
644 
645  try {
646  this.fromText.setText(getAttributeValueSafe(artifact, TSK_PHONE_NUMBER_FROM));
647  this.toText.setText(getAttributeValueSafe(artifact, TSK_PHONE_NUMBER_TO));
648  this.directionText.setText(getAttributeValueSafe(artifact, TSK_DIRECTION));
649  this.ccText.setText("");
650  this.subjectText.setText(getAttributeValueSafe(artifact, TSK_SUBJECT));
651  this.datetimeText.setText(getAttributeValueSafe(artifact, TSK_DATETIME));
652 
653  msgbodyTabbedPane.setEnabledAt(HTML_TAB_INDEX, false);
654  msgbodyTabbedPane.setEnabledAt(RTF_TAB_INDEX, false);
655  msgbodyTabbedPane.setEnabledAt(HDR_TAB_INDEX, false);
656  msgbodyTabbedPane.setEnabledAt(HDR_TAB_INDEX, false);
657  configureTextArea(TSK_TEXT, TEXT_TAB_INDEX);
658  configureAttachments();
659  } catch (TskCoreException ex) {
660  LOGGER.log(Level.WARNING, "Failed to get attributes for message.", ex); //NON-NLS
661  }
662  }
663 
664  private static String getAttributeValueSafe(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) throws TskCoreException {
665  return Optional.ofNullable(artifact.getAttribute(new BlackboardAttribute.Type(type)))
666  .map(BlackboardAttribute::getDisplayString)
667  .orElse("");
668  }
669 
677  static private String cleanseHTML(String htmlInString) {
678 
679  Document doc = Jsoup.parse(htmlInString);
680 
681  //fix all img tags
682  doc.select("img[src]").forEach(img -> img.attr("src", ""));
683 
684  return doc.html();
685  }
686 
690  private static class AttachmentsChildren extends Children.Keys<Attachment> {
691 
692  private final Set<Attachment> attachments;
693 
694  AttachmentsChildren(Set<Attachment> attachments) {
695  this.attachments = attachments;
696  }
697 
698  @Override
699  protected Node[] createNodes(Attachment t) {
700  return new Node[]{new AttachmentNode(t)};
701  }
702 
703  @Override
704  protected void addNotify() {
705  super.addNotify();
706  setKeys(attachments);
707  }
708  }
709 }
static void configureTextPaneAsRtf(JTextPane pane)
Definition: Utilities.java:52
static String getAttributeValueSafe(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type)
void configureTextArea(BlackboardAttribute.ATTRIBUTE_TYPE type, int index)
void setContent(String content, String contentDescriptor)
MessageArtifactViewer(List< JTextComponent > textAreas, DataResultPanel drp)
static DataResultPanel createInstanceUninitialized(String title, String description, Node currentRootNode, int childNodeCount, DataContent customContentView)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static Optional< BlackboardArtifact > getAssociatedArtifact(final BlackboardArtifact artifact)

Copyright © 2012-2021 Basis Technology. Generated on: Tue Jan 19 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.