Autopsy  4.14.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
MessageContentViewer.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;
20 
22 import com.google.gson.Gson;
23 import java.awt.Color;
24 import java.awt.Component;
25 import java.awt.ComponentOrientation;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Optional;
31 import java.util.Set;
32 import java.util.logging.Level;
33 import javax.swing.JScrollPane;
34 import javax.swing.text.JTextComponent;
35 import org.apache.commons.lang3.StringUtils;
36 import org.jsoup.Jsoup;
37 import org.jsoup.nodes.Document;
38 import org.openide.explorer.ExplorerManager;
39 import org.openide.nodes.AbstractNode;
40 import org.openide.nodes.Children;
41 import org.openide.nodes.Node;
42 import org.openide.util.NbBundle;
43 import org.openide.util.lookup.ServiceProvider;
54 import org.sleuthkit.datamodel.AbstractFile;
55 import org.sleuthkit.datamodel.BlackboardArtifact;
56 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
57 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG;
58 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT;
59 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE;
60 import org.sleuthkit.datamodel.BlackboardAttribute;
61 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT;
62 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME;
63 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_RCVD;
64 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION;
65 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CC;
66 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML;
67 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN;
68 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF;
69 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM;
70 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_TO;
71 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_HEADERS;
72 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM;
73 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO;
74 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT;
75 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT;
76 import org.sleuthkit.datamodel.Content;
77 import org.sleuthkit.datamodel.SleuthkitCase;
78 import org.sleuthkit.datamodel.TskCoreException;
79 import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments;
80 import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments.FileAttachment;
81 import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments.Attachment;
82 import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments.URLAttachment;
83 
87 @ServiceProvider(service = DataContentViewer.class, position = 5)
88 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
89 public class MessageContentViewer extends javax.swing.JPanel implements DataContentViewer {
90 
94  class TextComponent implements TranslatablePanel.ContentComponent {
95 
96  private final Component rootComponent;
97  private final AutoWrappingJTextPane childTextComponent;
98 
99  TextComponent() {
100  childTextComponent = new AutoWrappingJTextPane();
101  childTextComponent.setEditable(false);
102 
103  JScrollPane parentComponent = new JScrollPane();
104  parentComponent.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
105  parentComponent.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
106  parentComponent.setViewportView(childTextComponent);
107  rootComponent = parentComponent;
108  }
109 
110  @Override
111  public Component getRootComponent() {
112  return rootComponent;
113  }
114 
115  @Override
116  public void setContent(String content, ComponentOrientation orientation) throws TranslatablePanelException {
117  childTextComponent.setText(content == null ? "" : content);
118  childTextComponent.setComponentOrientation(orientation);
119  childTextComponent.setCaretPosition(0);
120  }
121  }
122 
123  private static final long serialVersionUID = 1L;
124  private static final Logger LOGGER = Logger.getLogger(MessageContentViewer.class.getName());
125  private static final BlackboardAttribute.Type TSK_ASSOCIATED_TYPE = new BlackboardAttribute.Type(TSK_ASSOCIATED_ARTIFACT);
126 
127  private static final int HDR_TAB_INDEX = 0;
128  private static final int TEXT_TAB_INDEX = 1;
129  private static final int HTML_TAB_INDEX = 2;
130  private static final int RTF_TAB_INDEX = 3;
131  private static final int ATTM_TAB_INDEX = 4;
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 
146  @NbBundle.Messages("MessageContentViewer.AtrachmentsPanel.title=Attachments")
148  initComponents();
149  htmlPane.add(htmlPanel);
150  envelopePanel.setBackground(new Color(0, 0, 0, 38));
151  drp = DataResultPanel.createInstanceUninitialized(Bundle.MessageContentViewer_AtrachmentsPanel_title(), "", new TableFilterNode(Node.EMPTY, false), 0, null);
152  attachmentsScrollPane.setViewportView(drp);
153 
154  msgbodyTabbedPane.insertTab(
155  NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle"),
156  null,
157  textPanel,
158  null,
159  TEXT_TAB_INDEX);
160 
161  msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, true);
162 
163  /*
164  * HTML tab uses the HtmlPanel instead of an internal text pane, so we
165  * use 'null' for that index.
166  */
167  textAreas = Arrays.asList(headersTextArea, null, null, rtfbodyTextPane);
168 
169  Utilities.configureTextPaneAsRtf(rtfbodyTextPane);
170  resetComponent();
171 
172  }
173 
174  @Override
175  public void addNotify() {
176  super.addNotify(); //To change body of generated methods, choose Tools | Templates.
177 
178  drp.open();
179  drpExplorerManager = drp.getExplorerManager();
180  drpExplorerManager.addPropertyChangeListener(evt
181  -> viewInNewWindowButton.setEnabled(drpExplorerManager.getSelectedNodes().length == 1));
182  }
183 
189  @SuppressWarnings("unchecked")
190  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
191  private void initComponents() {
192 
193  envelopePanel = new javax.swing.JPanel();
194  fromLabel = new javax.swing.JLabel();
195  datetimeText = new javax.swing.JLabel();
196  fromText = new javax.swing.JLabel();
197  toLabel = new javax.swing.JLabel();
198  toText = new javax.swing.JLabel();
199  ccLabel = new javax.swing.JLabel();
200  ccText = new javax.swing.JLabel();
201  subjectLabel = new javax.swing.JLabel();
202  subjectText = new javax.swing.JLabel();
203  directionText = new javax.swing.JLabel();
204  msgbodyTabbedPane = new javax.swing.JTabbedPane();
205  headersScrollPane = new javax.swing.JScrollPane();
206  headersTextArea = new javax.swing.JTextArea();
207  htmlPane = new javax.swing.JPanel();
208  rtfbodyScrollPane = new javax.swing.JScrollPane();
209  rtfbodyTextPane = new javax.swing.JTextPane();
210  attachmentsPanel = new javax.swing.JPanel();
211  viewInNewWindowButton = new javax.swing.JButton();
212  attachmentsScrollPane = new javax.swing.JScrollPane();
213 
214  envelopePanel.setBackground(new java.awt.Color(204, 204, 204));
215 
216  org.openide.awt.Mnemonics.setLocalizedText(fromLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.fromLabel.text")); // NOI18N
217 
218  datetimeText.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
219  org.openide.awt.Mnemonics.setLocalizedText(datetimeText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.datetimeText.text")); // NOI18N
220 
221  org.openide.awt.Mnemonics.setLocalizedText(fromText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.fromText.text")); // NOI18N
222 
223  org.openide.awt.Mnemonics.setLocalizedText(toLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.toLabel.text")); // NOI18N
224 
225  org.openide.awt.Mnemonics.setLocalizedText(toText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.toText.text")); // NOI18N
226  toText.setAutoscrolls(true);
227  toText.setMinimumSize(new java.awt.Dimension(27, 14));
228 
229  org.openide.awt.Mnemonics.setLocalizedText(ccLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.ccLabel.text")); // NOI18N
230 
231  org.openide.awt.Mnemonics.setLocalizedText(ccText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.ccText.text")); // NOI18N
232  ccText.setMinimumSize(new java.awt.Dimension(27, 14));
233 
234  org.openide.awt.Mnemonics.setLocalizedText(subjectLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.subjectLabel.text")); // NOI18N
235 
236  org.openide.awt.Mnemonics.setLocalizedText(subjectText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.subjectText.text")); // NOI18N
237  subjectText.setMinimumSize(new java.awt.Dimension(26, 14));
238 
239  directionText.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
240  org.openide.awt.Mnemonics.setLocalizedText(directionText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.directionText.text")); // NOI18N
241 
242  javax.swing.GroupLayout envelopePanelLayout = new javax.swing.GroupLayout(envelopePanel);
243  envelopePanel.setLayout(envelopePanelLayout);
244  envelopePanelLayout.setHorizontalGroup(
245  envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
246  .addGroup(envelopePanelLayout.createSequentialGroup()
247  .addGap(5, 5, 5)
248  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
249  .addGroup(envelopePanelLayout.createSequentialGroup()
250  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
251  .addComponent(fromLabel)
252  .addComponent(toLabel))
253  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
254  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
255  .addGroup(envelopePanelLayout.createSequentialGroup()
256  .addComponent(toText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
257  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
258  .addComponent(directionText, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE))
259  .addGroup(envelopePanelLayout.createSequentialGroup()
260  .addComponent(fromText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
261  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
262  .addComponent(datetimeText, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE))))
263  .addGroup(envelopePanelLayout.createSequentialGroup()
264  .addComponent(ccLabel)
265  .addGap(26, 26, 26)
266  .addComponent(ccText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
267  .addGroup(envelopePanelLayout.createSequentialGroup()
268  .addComponent(subjectLabel)
269  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
270  .addComponent(subjectText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
271  .addGap(5, 5, 5))
272  );
273  envelopePanelLayout.setVerticalGroup(
274  envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
275  .addGroup(envelopePanelLayout.createSequentialGroup()
276  .addGap(5, 5, 5)
277  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
278  .addComponent(fromLabel)
279  .addComponent(datetimeText)
280  .addComponent(fromText))
281  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
282  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
283  .addComponent(toLabel)
284  .addComponent(toText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
285  .addComponent(directionText))
286  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
287  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
288  .addComponent(ccLabel)
289  .addComponent(ccText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
290  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
291  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
292  .addComponent(subjectLabel)
293  .addComponent(subjectText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
294  .addGap(5, 5, 5))
295  );
296 
297  headersScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
298  headersScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
299 
300  headersTextArea.setEditable(false);
301  headersTextArea.setColumns(20);
302  headersTextArea.setLineWrap(true);
303  headersTextArea.setRows(5);
304  headersTextArea.setWrapStyleWord(true);
305  headersScrollPane.setViewportView(headersTextArea);
306 
307  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.headersScrollPane.TabConstraints.tabTitle"), headersScrollPane); // NOI18N
308 
309  htmlPane.setLayout(new java.awt.BorderLayout());
310  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.htmlPane.TabConstraints.tabTitle"), htmlPane); // NOI18N
311 
312  rtfbodyScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
313 
314  rtfbodyTextPane.setEditable(false);
315  rtfbodyScrollPane.setViewportView(rtfbodyTextPane);
316 
317  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.rtfbodyScrollPane.TabConstraints.tabTitle"), rtfbodyScrollPane); // NOI18N
318 
319  org.openide.awt.Mnemonics.setLocalizedText(viewInNewWindowButton, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.viewInNewWindowButton.text")); // NOI18N
320  viewInNewWindowButton.addActionListener(new java.awt.event.ActionListener() {
321  public void actionPerformed(java.awt.event.ActionEvent evt) {
322  viewInNewWindowButtonActionPerformed(evt);
323  }
324  });
325 
326  javax.swing.GroupLayout attachmentsPanelLayout = new javax.swing.GroupLayout(attachmentsPanel);
327  attachmentsPanel.setLayout(attachmentsPanelLayout);
328  attachmentsPanelLayout.setHorizontalGroup(
329  attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
330  .addGroup(attachmentsPanelLayout.createSequentialGroup()
331  .addGap(0, 0, 0)
332  .addGroup(attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
333  .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, attachmentsPanelLayout.createSequentialGroup()
334  .addComponent(viewInNewWindowButton)
335  .addGap(3, 3, 3))
336  .addComponent(attachmentsScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 647, Short.MAX_VALUE)))
337  );
338  attachmentsPanelLayout.setVerticalGroup(
339  attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
340  .addGroup(attachmentsPanelLayout.createSequentialGroup()
341  .addGap(0, 0, 0)
342  .addComponent(viewInNewWindowButton)
343  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
344  .addComponent(attachmentsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 333, Short.MAX_VALUE)
345  .addGap(0, 0, 0))
346  );
347 
348  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.attachmentsPanel.TabConstraints.tabTitle"), attachmentsPanel); // NOI18N
349 
350  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
351  this.setLayout(layout);
352  layout.setHorizontalGroup(
353  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
354  .addGroup(layout.createSequentialGroup()
355  .addGap(5, 5, 5)
356  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
357  .addComponent(msgbodyTabbedPane)
358  .addComponent(envelopePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
359  .addGap(5, 5, 5))
360  );
361  layout.setVerticalGroup(
362  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
363  .addGroup(layout.createSequentialGroup()
364  .addGap(5, 5, 5)
365  .addComponent(envelopePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
366  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
367  .addComponent(msgbodyTabbedPane)
368  .addGap(5, 5, 5))
369  );
370 
371  msgbodyTabbedPane.getAccessibleContext().setAccessibleParent(null);
372  }// </editor-fold>//GEN-END:initComponents
373 
374  private void viewInNewWindowButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewInNewWindowButtonActionPerformed
375  new NewWindowViewAction("View in new window", drpExplorerManager.getSelectedNodes()[0]).actionPerformed(evt);
376  }//GEN-LAST:event_viewInNewWindowButtonActionPerformed
377 
378 
379  // Variables declaration - do not modify//GEN-BEGIN:variables
380  private javax.swing.JPanel attachmentsPanel;
381  private javax.swing.JScrollPane attachmentsScrollPane;
382  private javax.swing.JLabel ccLabel;
383  private javax.swing.JLabel ccText;
384  private javax.swing.JLabel datetimeText;
385  private javax.swing.JLabel directionText;
386  private javax.swing.JPanel envelopePanel;
387  private javax.swing.JLabel fromLabel;
388  private javax.swing.JLabel fromText;
389  private javax.swing.JScrollPane headersScrollPane;
390  private javax.swing.JTextArea headersTextArea;
391  private javax.swing.JPanel htmlPane;
392  private javax.swing.JTabbedPane msgbodyTabbedPane;
393  private javax.swing.JScrollPane rtfbodyScrollPane;
394  private javax.swing.JTextPane rtfbodyTextPane;
395  private javax.swing.JLabel subjectLabel;
396  private javax.swing.JLabel subjectText;
397  private javax.swing.JLabel toLabel;
398  private javax.swing.JLabel toText;
399  private javax.swing.JButton viewInNewWindowButton;
400  // End of variables declaration//GEN-END:variables
401 
402  @Override
403  public void setNode(Node node) {
404  if (node == null) {
405  resetComponent();
406  return;
407  }
408 
409  artifact = getNodeArtifact(node);
410  if (artifact == null) {
411  resetComponent();
412  return;
413  }
414 
415  /*
416  * If the artifact is a keyword hit, use the associated artifact as the
417  * one to show in this viewer
418  */
419  if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) {
420  try {
421  getAssociatedArtifact(artifact).ifPresent(associatedArtifact -> {
422  artifact = associatedArtifact;
423  });
424  } catch (TskCoreException ex) {
425  LOGGER.log(Level.SEVERE, "error getting associated artifact", ex);
426  }
427  }
428 
429  if (artifact.getArtifactTypeID() == TSK_MESSAGE.getTypeID()) {
430  displayMsg();
431  } else if (artifact.getArtifactTypeID() == TSK_EMAIL_MSG.getTypeID()) {
432  displayEmailMsg();
433  } else {
434  resetComponent();
435  }
436  }
437 
448  private static Optional<BlackboardArtifact> getAssociatedArtifact(final BlackboardArtifact artifact) throws TskCoreException {
449  BlackboardAttribute attribute = artifact.getAttribute(TSK_ASSOCIATED_TYPE);
450  if (attribute != null) {
451  return Optional.of(artifact.getSleuthkitCase().getArtifactByArtifactId(attribute.getValueLong()));
452  }
453  return Optional.empty();
454  }
455 
456  @Override
457  @NbBundle.Messages("MessageContentViewer.title=Message")
458  public String getTitle() {
459  return Bundle.MessageContentViewer_title();
460  }
461 
462  @Override
463  @NbBundle.Messages("MessageContentViewer.toolTip=Displays messages.")
464  public String getToolTip() {
465  return Bundle.MessageContentViewer_toolTip();
466  }
467 
468  @Override
469  public DataContentViewer createInstance() {
470  return new MessageContentViewer();
471  }
472 
473  @Override
474  public Component getComponent() {
475  return this;
476  }
477 
478  @Override
479  final public void resetComponent() {
480  // reset all fields
481  fromText.setText("");
482  fromLabel.setEnabled(false);
483  toText.setText("");
484  toLabel.setEnabled(false);
485  ccText.setText("");
486  ccLabel.setEnabled(false);
487  subjectText.setText("");
488  subjectLabel.setEnabled(false);
489  datetimeText.setText("");
490  datetimeText.setEnabled(false);
491  directionText.setText("");
492  directionText.setEnabled(false);
493 
494  headersTextArea.setText("");
495  rtfbodyTextPane.setText("");
496  htmlPanel.reset();
497  textPanel.reset();
498  msgbodyTabbedPane.setEnabled(false);
499  drp.setNode(null);
500  }
501 
502  @Override
503  public boolean isSupported(Node node) {
504  BlackboardArtifact nodeArtifact = getNodeArtifact(node);
505 
506  if (nodeArtifact == null) {
507  return false;
508  }
509  //if the artifact is a keyword hit, check if its associated artifact is a message or email.
510  if (nodeArtifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) {
511  try {
512  if (getAssociatedArtifact(nodeArtifact).map(MessageContentViewer::isMessageArtifact).orElse(false)) {
513  return true;
514  }
515  } catch (TskCoreException ex) {
516  LOGGER.log(Level.SEVERE, "error getting associated artifact", ex);
517  }
518  }
519  return isMessageArtifact(nodeArtifact);
520  }
521 
531  private static boolean isMessageArtifact(BlackboardArtifact nodeArtifact) {
532  final int artifactTypeID = nodeArtifact.getArtifactTypeID();
533  return artifactTypeID == TSK_EMAIL_MSG.getTypeID()
534  || artifactTypeID == TSK_MESSAGE.getTypeID();
535  }
536 
548  private BlackboardArtifact getNodeArtifact(Node node) {
549  BlackboardArtifact nodeArtifact = node.getLookup().lookup(BlackboardArtifact.class);
550 
551  if (nodeArtifact == null) {
552  try {
553  SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
554  AbstractFile file = node.getLookup().lookup(AbstractFile.class);
555  if (file != null) {
556  List<BlackboardArtifact> artifactsList = tskCase.getBlackboardArtifacts(TSK_ASSOCIATED_OBJECT, file.getId());
557 
558  for (BlackboardArtifact fileArtifact : artifactsList) {
559  BlackboardAttribute associatedArtifactAttribute = fileArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
560  if (associatedArtifactAttribute != null) {
561  BlackboardArtifact associatedArtifact = fileArtifact.getSleuthkitCase().getBlackboardArtifact(associatedArtifactAttribute.getValueLong());
562  if (isMessageArtifact(associatedArtifact)) {
563  nodeArtifact = associatedArtifact;
564  }
565  }
566  }
567  }
568  } catch (NoCurrentCaseException | TskCoreException ex) {
569  LOGGER.log(Level.SEVERE, "Failed to get file for selected node.", ex); //NON-NLS
570  }
571  }
572 
573  return nodeArtifact;
574  }
575 
576  @Override
577  public int isPreferred(Node node) {
578  // For message artifacts this is a high priority viewer,
579  // but for attachment files, this a lower priority vewer.
580  if (isSupported(node)) {
581  BlackboardArtifact nodeArtifact = node.getLookup().lookup(BlackboardArtifact.class);
582  if (nodeArtifact != null) {
583  return 7;
584  } else {
585  return 1;
586  }
587  }
588  return 0;
589  }
590 
600  private void configureTextArea(BlackboardAttribute.ATTRIBUTE_TYPE type, int index) throws TskCoreException {
601  String attributeText = getAttributeValueSafe(artifact, type);
602 
603  if (index == HTML_TAB_INDEX && StringUtils.isNotBlank(attributeText)) {
604  htmlPanel.setHtmlText(attributeText);
605  } else if (index == TEXT_TAB_INDEX && StringUtils.isNotBlank(attributeText)) {
606  textPanel.setContent(attributeText, artifact.toString());
607  } else {
608  JTextComponent textComponent = textAreas.get(index);
609  if (textComponent != null) {
610  textComponent.setText(attributeText);
611  textComponent.setCaretPosition(0); //make sure we start at the top
612  }
613  }
614 
615  final boolean hasText = attributeText.length() > 0;
616 
617  msgbodyTabbedPane.setEnabledAt(index, hasText);
618  if (hasText) {
619  msgbodyTabbedPane.setSelectedIndex(index);
620  }
621  }
622 
623  private void enableCommonFields() {
624  msgbodyTabbedPane.setEnabled(true);
625  fromLabel.setEnabled(true);
626  toLabel.setEnabled(true);
627  subjectLabel.setEnabled(true);
628  datetimeText.setEnabled(true);
629  }
630 
631  private void configureAttachments() throws TskCoreException {
632 
633  final Set<Attachment> attachments;
634 
635  // Attachments are specified in an attribute TSK_ATTACHMENTS as JSON attribute
636  BlackboardAttribute attachmentsAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS));
637  if (attachmentsAttr != null) {
638 
639  attachments = new HashSet<>();
640  String jsonVal = attachmentsAttr.getValueString();
641  MessageAttachments msgAttachments = new Gson().fromJson(jsonVal, MessageAttachments.class);
642 
643  Collection<FileAttachment> fileAttachments = msgAttachments.getFileAttachments();
644  for (FileAttachment fileAttachment : fileAttachments) {
645  attachments.add(fileAttachment);
646  }
647  Collection<URLAttachment> urlAttachments = msgAttachments.getUrlAttachments();
648  for (URLAttachment urlAttachment : urlAttachments) {
649  attachments.add(urlAttachment);
650  }
651  } else { // For backward compatibility - email attachements are derived files and children of the email message artifact
652  attachments = new HashSet<>();
653  for (Content child : artifact.getChildren()) {
654  if (child instanceof AbstractFile) {
655  attachments.add(new FileAttachment((AbstractFile) child));
656  }
657  }
658  }
659 
660  final int numberOfAttachments = attachments.size();
661 
662  msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, numberOfAttachments > 0);
663  msgbodyTabbedPane.setTitleAt(ATTM_TAB_INDEX, "Attachments (" + numberOfAttachments + ")");
664  drp.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(
665  new AttachmentsChildren(attachments))), true));
666  }
667 
668  private static String wrapInHtmlBody(String htmlText) {
669  return "<html><body>" + htmlText + "</body></html>";
670  }
671 
672  private void displayEmailMsg() {
673  enableCommonFields();
674 
675  directionText.setEnabled(false);
676  ccLabel.setEnabled(true);
677 
678  try {
679  this.fromText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_FROM));
680  this.fromText.setToolTipText(getAttributeValueSafe(artifact, TSK_EMAIL_FROM));
681  this.toText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_TO));
682  this.toText.setToolTipText(getAttributeValueSafe(artifact, TSK_EMAIL_TO));
683  this.directionText.setText("");
684  this.ccText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_CC));
685  this.ccText.setToolTipText(getAttributeValueSafe(artifact, TSK_EMAIL_CC));
686  this.subjectText.setText(getAttributeValueSafe(artifact, TSK_SUBJECT));
687  this.datetimeText.setText(getAttributeValueSafe(artifact, TSK_DATETIME_RCVD));
688 
689  configureTextArea(TSK_HEADERS, HDR_TAB_INDEX);
690  configureTextArea(TSK_EMAIL_CONTENT_PLAIN, TEXT_TAB_INDEX);
691  configureTextArea(TSK_EMAIL_CONTENT_HTML, HTML_TAB_INDEX);
692  configureTextArea(TSK_EMAIL_CONTENT_RTF, RTF_TAB_INDEX);
693  configureAttachments();
694  } catch (TskCoreException ex) {
695  LOGGER.log(Level.WARNING, "Failed to get attributes for email message.", ex); //NON-NLS
696  }
697  }
698 
699  private void displayMsg() {
700  enableCommonFields();
701 
702  directionText.setEnabled(true);
703  ccLabel.setEnabled(false);
704 
705  try {
706  this.fromText.setText(getAttributeValueSafe(artifact, TSK_PHONE_NUMBER_FROM));
707  this.toText.setText(getAttributeValueSafe(artifact, TSK_PHONE_NUMBER_TO));
708  this.directionText.setText(getAttributeValueSafe(artifact, TSK_DIRECTION));
709  this.ccText.setText("");
710  this.subjectText.setText(getAttributeValueSafe(artifact, TSK_SUBJECT));
711  this.datetimeText.setText(getAttributeValueSafe(artifact, TSK_DATETIME));
712 
713  msgbodyTabbedPane.setEnabledAt(HTML_TAB_INDEX, false);
714  msgbodyTabbedPane.setEnabledAt(RTF_TAB_INDEX, false);
715  msgbodyTabbedPane.setEnabledAt(HDR_TAB_INDEX, false);
716  msgbodyTabbedPane.setEnabledAt(HDR_TAB_INDEX, false);
717  configureTextArea(TSK_TEXT, TEXT_TAB_INDEX);
718  configureAttachments();
719  } catch (TskCoreException ex) {
720  LOGGER.log(Level.WARNING, "Failed to get attributes for message.", ex); //NON-NLS
721  }
722  }
723 
724  private static String getAttributeValueSafe(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) throws TskCoreException {
725  return Optional.ofNullable(artifact.getAttribute(new BlackboardAttribute.Type(type)))
726  .map(BlackboardAttribute::getDisplayString)
727  .orElse("");
728  }
729 
737  static private String cleanseHTML(String htmlInString) {
738 
739  Document doc = Jsoup.parse(htmlInString);
740 
741  //fix all img tags
742  doc.select("img[src]").forEach(img -> img.attr("src", ""));
743 
744  return doc.html();
745  }
746 
750  private static class AttachmentsChildren extends Children.Keys<Attachment> {
751 
752  private final Set<Attachment> attachments;
753 
754  AttachmentsChildren(Set<Attachment> attachments) {
755  this.attachments = attachments;
756  }
757 
758  @Override
759  protected Node[] createNodes(Attachment t) {
760  return new Node[]{new AttachmentNode(t)};
761  }
762 
763  @Override
764  protected void addNotify() {
765  super.addNotify();
766  setKeys(attachments);
767  }
768  }
769 }
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)
static boolean isMessageArtifact(BlackboardArtifact nodeArtifact)
static DataResultPanel createInstanceUninitialized(String title, String description, Node currentRootNode, int childNodeCount, DataContent customContentView)
static Optional< BlackboardArtifact > getAssociatedArtifact(final BlackboardArtifact artifact)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
void viewInNewWindowButtonActionPerformed(java.awt.event.ActionEvent evt)

Copyright © 2012-2020 Basis Technology. Generated on: Wed Apr 8 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.