Autopsy  4.9.1
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-2018 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 
21 import java.awt.Color;
22 import java.awt.Component;
23 import java.util.Arrays;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Optional;
27 import java.util.Set;
28 import java.util.logging.Level;
29 import java.util.stream.Collectors;
30 import javax.swing.text.JTextComponent;
31 import org.apache.commons.lang3.StringUtils;
32 import org.jsoup.Jsoup;
33 import org.jsoup.nodes.Document;
34 import org.openide.explorer.ExplorerManager;
35 import org.openide.nodes.AbstractNode;
36 import org.openide.nodes.Children;
37 import org.openide.nodes.Node;
38 import org.openide.nodes.Sheet;
39 import org.openide.util.NbBundle;
40 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.ContentTag;
75 import org.sleuthkit.datamodel.TskCoreException;
76 
80 @ServiceProvider(service = DataContentViewer.class, position = 5)
81 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
82 public class MessageContentViewer extends javax.swing.JPanel implements DataContentViewer {
83 
84  private static final long serialVersionUID = 1L;
85  private static final Logger LOGGER = Logger.getLogger(MessageContentViewer.class.getName());
86  private static final BlackboardAttribute.Type TSK_ASSOCIATED_TYPE = new BlackboardAttribute.Type(TSK_ASSOCIATED_ARTIFACT);
87 
88  private static final int HDR_TAB_INDEX = 0;
89  private static final int TEXT_TAB_INDEX = 1;
90  private static final int HTML_TAB_INDEX = 2;
91  private static final int RTF_TAB_INDEX = 3;
92  private static final int ATTM_TAB_INDEX = 4;
93 
94  private final List<JTextComponent> textAreas;
95 
99  private BlackboardArtifact artifact;
100  private final DataResultPanel drp;
101  private ExplorerManager drpExplorerManager;
102 
106  @NbBundle.Messages("MessageContentViewer.AtrachmentsPanel.title=Attachments")
108  initComponents();
109  envelopePanel.setBackground(new Color(0, 0, 0, 38));
110  drp = DataResultPanel.createInstanceUninitialized(Bundle.MessageContentViewer_AtrachmentsPanel_title(), "", new TableFilterNode(Node.EMPTY, false), 0, null);
111  attachmentsScrollPane.setViewportView(drp);
112  msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, true);
113 
114  textAreas = Arrays.asList(headersTextArea, textbodyTextArea, htmlbodyTextPane, rtfbodyTextPane);
115 
116  Utilities.configureTextPaneAsHtml(htmlbodyTextPane);
117  Utilities.configureTextPaneAsRtf(rtfbodyTextPane);
118  resetComponent();
119 
120  }
121 
122  @Override
123  public void addNotify() {
124  super.addNotify(); //To change body of generated methods, choose Tools | Templates.
125 
126  drp.open();
127  drpExplorerManager = drp.getExplorerManager();
128  drpExplorerManager.addPropertyChangeListener(evt
129  -> viewInNewWindowButton.setEnabled(drpExplorerManager.getSelectedNodes().length == 1));
130  }
131 
137  @SuppressWarnings("unchecked")
138  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
139  private void initComponents() {
140 
141  envelopePanel = new javax.swing.JPanel();
142  fromLabel = new javax.swing.JLabel();
143  datetimeText = new javax.swing.JLabel();
144  fromText = new javax.swing.JLabel();
145  toLabel = new javax.swing.JLabel();
146  toText = new javax.swing.JLabel();
147  ccLabel = new javax.swing.JLabel();
148  ccText = new javax.swing.JLabel();
149  subjectLabel = new javax.swing.JLabel();
150  subjectText = new javax.swing.JLabel();
151  directionText = new javax.swing.JLabel();
152  msgbodyTabbedPane = new javax.swing.JTabbedPane();
153  headersScrollPane = new javax.swing.JScrollPane();
154  headersTextArea = new javax.swing.JTextArea();
155  textbodyScrollPane = new javax.swing.JScrollPane();
156  textbodyTextArea = new javax.swing.JTextArea();
157  htmlPane = new javax.swing.JPanel();
158  htmlScrollPane = new javax.swing.JScrollPane();
159  htmlbodyTextPane = new javax.swing.JTextPane();
160  showImagesToggleButton = new javax.swing.JToggleButton();
161  rtfbodyScrollPane = new javax.swing.JScrollPane();
162  rtfbodyTextPane = new javax.swing.JTextPane();
163  attachmentsPanel = new javax.swing.JPanel();
164  viewInNewWindowButton = new javax.swing.JButton();
165  attachmentsScrollPane = new javax.swing.JScrollPane();
166 
167  envelopePanel.setBackground(new java.awt.Color(204, 204, 204));
168 
169  org.openide.awt.Mnemonics.setLocalizedText(fromLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.fromLabel.text")); // NOI18N
170 
171  datetimeText.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
172  org.openide.awt.Mnemonics.setLocalizedText(datetimeText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.datetimeText.text")); // NOI18N
173 
174  org.openide.awt.Mnemonics.setLocalizedText(fromText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.fromText.text")); // NOI18N
175 
176  org.openide.awt.Mnemonics.setLocalizedText(toLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.toLabel.text")); // NOI18N
177 
178  org.openide.awt.Mnemonics.setLocalizedText(toText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.toText.text")); // NOI18N
179  toText.setAutoscrolls(true);
180  toText.setMinimumSize(new java.awt.Dimension(27, 14));
181 
182  org.openide.awt.Mnemonics.setLocalizedText(ccLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.ccLabel.text")); // NOI18N
183 
184  org.openide.awt.Mnemonics.setLocalizedText(ccText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.ccText.text")); // NOI18N
185  ccText.setMinimumSize(new java.awt.Dimension(27, 14));
186 
187  org.openide.awt.Mnemonics.setLocalizedText(subjectLabel, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.subjectLabel.text")); // NOI18N
188 
189  org.openide.awt.Mnemonics.setLocalizedText(subjectText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.subjectText.text")); // NOI18N
190  subjectText.setMinimumSize(new java.awt.Dimension(26, 14));
191 
192  directionText.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
193  org.openide.awt.Mnemonics.setLocalizedText(directionText, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.directionText.text")); // NOI18N
194 
195  javax.swing.GroupLayout envelopePanelLayout = new javax.swing.GroupLayout(envelopePanel);
196  envelopePanel.setLayout(envelopePanelLayout);
197  envelopePanelLayout.setHorizontalGroup(
198  envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
199  .addGroup(envelopePanelLayout.createSequentialGroup()
200  .addGap(5, 5, 5)
201  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
202  .addGroup(envelopePanelLayout.createSequentialGroup()
203  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
204  .addComponent(fromLabel)
205  .addComponent(toLabel))
206  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
207  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
208  .addGroup(envelopePanelLayout.createSequentialGroup()
209  .addComponent(toText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
210  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
211  .addComponent(directionText, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE))
212  .addGroup(envelopePanelLayout.createSequentialGroup()
213  .addComponent(fromText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
214  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
215  .addComponent(datetimeText, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE))))
216  .addGroup(envelopePanelLayout.createSequentialGroup()
217  .addComponent(ccLabel)
218  .addGap(26, 26, 26)
219  .addComponent(ccText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
220  .addGroup(envelopePanelLayout.createSequentialGroup()
221  .addComponent(subjectLabel)
222  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
223  .addComponent(subjectText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
224  .addGap(5, 5, 5))
225  );
226  envelopePanelLayout.setVerticalGroup(
227  envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
228  .addGroup(envelopePanelLayout.createSequentialGroup()
229  .addGap(5, 5, 5)
230  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
231  .addComponent(fromLabel)
232  .addComponent(datetimeText)
233  .addComponent(fromText))
234  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
235  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
236  .addComponent(toLabel)
237  .addComponent(toText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
238  .addComponent(directionText))
239  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
240  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
241  .addComponent(ccLabel)
242  .addComponent(ccText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
243  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
244  .addGroup(envelopePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
245  .addComponent(subjectLabel)
246  .addComponent(subjectText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
247  .addGap(5, 5, 5))
248  );
249 
250  headersScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
251  headersScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
252 
253  headersTextArea.setEditable(false);
254  headersTextArea.setColumns(20);
255  headersTextArea.setLineWrap(true);
256  headersTextArea.setRows(5);
257  headersTextArea.setWrapStyleWord(true);
258  headersScrollPane.setViewportView(headersTextArea);
259 
260  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.headersScrollPane.TabConstraints.tabTitle"), headersScrollPane); // NOI18N
261 
262  textbodyScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
263  textbodyScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
264 
265  textbodyTextArea.setEditable(false);
266  textbodyTextArea.setLineWrap(true);
267  textbodyTextArea.setRows(5);
268  textbodyTextArea.setWrapStyleWord(true);
269  textbodyScrollPane.setViewportView(textbodyTextArea);
270 
271  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle"), textbodyScrollPane); // NOI18N
272 
273  htmlScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
274 
275  htmlbodyTextPane.setEditable(false);
276  htmlScrollPane.setViewportView(htmlbodyTextPane);
277 
278  org.openide.awt.Mnemonics.setLocalizedText(showImagesToggleButton, "Show Images");
279  showImagesToggleButton.addActionListener(new java.awt.event.ActionListener() {
280  public void actionPerformed(java.awt.event.ActionEvent evt) {
281  showImagesToggleButtonActionPerformed(evt);
282  }
283  });
284 
285  javax.swing.GroupLayout htmlPaneLayout = new javax.swing.GroupLayout(htmlPane);
286  htmlPane.setLayout(htmlPaneLayout);
287  htmlPaneLayout.setHorizontalGroup(
288  htmlPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
289  .addComponent(htmlScrollPane)
290  .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, htmlPaneLayout.createSequentialGroup()
291  .addContainerGap(533, Short.MAX_VALUE)
292  .addComponent(showImagesToggleButton)
293  .addGap(3, 3, 3))
294  );
295  htmlPaneLayout.setVerticalGroup(
296  htmlPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
297  .addGroup(htmlPaneLayout.createSequentialGroup()
298  .addComponent(showImagesToggleButton)
299  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
300  .addComponent(htmlScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 333, Short.MAX_VALUE)
301  .addGap(0, 0, 0))
302  );
303 
304  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.htmlPane.TabConstraints.tabTitle"), htmlPane); // NOI18N
305 
306  rtfbodyScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
307 
308  rtfbodyTextPane.setEditable(false);
309  rtfbodyScrollPane.setViewportView(rtfbodyTextPane);
310 
311  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.rtfbodyScrollPane.TabConstraints.tabTitle"), rtfbodyScrollPane); // NOI18N
312 
313  org.openide.awt.Mnemonics.setLocalizedText(viewInNewWindowButton, org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.viewInNewWindowButton.text")); // NOI18N
314  viewInNewWindowButton.addActionListener(new java.awt.event.ActionListener() {
315  public void actionPerformed(java.awt.event.ActionEvent evt) {
316  viewInNewWindowButtonActionPerformed(evt);
317  }
318  });
319 
320  javax.swing.GroupLayout attachmentsPanelLayout = new javax.swing.GroupLayout(attachmentsPanel);
321  attachmentsPanel.setLayout(attachmentsPanelLayout);
322  attachmentsPanelLayout.setHorizontalGroup(
323  attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
324  .addGroup(attachmentsPanelLayout.createSequentialGroup()
325  .addGap(0, 0, 0)
326  .addGroup(attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
327  .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, attachmentsPanelLayout.createSequentialGroup()
328  .addComponent(viewInNewWindowButton)
329  .addGap(3, 3, 3))
330  .addComponent(attachmentsScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 647, Short.MAX_VALUE)))
331  );
332  attachmentsPanelLayout.setVerticalGroup(
333  attachmentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
334  .addGroup(attachmentsPanelLayout.createSequentialGroup()
335  .addGap(0, 0, 0)
336  .addComponent(viewInNewWindowButton)
337  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
338  .addComponent(attachmentsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 333, Short.MAX_VALUE)
339  .addGap(0, 0, 0))
340  );
341 
342  msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.attachmentsPanel.TabConstraints.tabTitle"), attachmentsPanel); // NOI18N
343 
344  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
345  this.setLayout(layout);
346  layout.setHorizontalGroup(
347  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
348  .addGroup(layout.createSequentialGroup()
349  .addGap(5, 5, 5)
350  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
351  .addComponent(msgbodyTabbedPane)
352  .addComponent(envelopePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
353  .addGap(5, 5, 5))
354  );
355  layout.setVerticalGroup(
356  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
357  .addGroup(layout.createSequentialGroup()
358  .addGap(5, 5, 5)
359  .addComponent(envelopePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
360  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
361  .addComponent(msgbodyTabbedPane)
362  .addGap(5, 5, 5))
363  );
364  }// </editor-fold>//GEN-END:initComponents
365 
366  @NbBundle.Messages({
367  "MessageContentViewer.showImagesToggleButton.hide.text=Hide Images",
368  "MessageContentViewer.showImagesToggleButton.text=Show Images"})
369  private void showImagesToggleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showImagesToggleButtonActionPerformed
370  try {
371  String htmlText = getAttributeValueSafe(artifact, TSK_EMAIL_CONTENT_HTML);
372  if (false == htmlText.isEmpty()) {
373  if (showImagesToggleButton.isSelected()) {
374  showImagesToggleButton.setText(Bundle.MessageContentViewer_showImagesToggleButton_hide_text());
375  this.htmlbodyTextPane.setText(wrapInHtmlBody(htmlText));
376  } else {
377  showImagesToggleButton.setText(Bundle.MessageContentViewer_showImagesToggleButton_text());
378  this.htmlbodyTextPane.setText(wrapInHtmlBody(cleanseHTML(htmlText)));
379  }
380  }
381  } catch (TskCoreException ex) {
382  LOGGER.log(Level.WARNING, "Failed to get attributes for email message.", ex); //NON-NLS
383  }
384  }//GEN-LAST:event_showImagesToggleButtonActionPerformed
385 
386  private void viewInNewWindowButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewInNewWindowButtonActionPerformed
387  new NewWindowViewAction("View in new window", drpExplorerManager.getSelectedNodes()[0]).actionPerformed(evt);
388  }//GEN-LAST:event_viewInNewWindowButtonActionPerformed
389 
390 
391  // Variables declaration - do not modify//GEN-BEGIN:variables
392  private javax.swing.JPanel attachmentsPanel;
393  private javax.swing.JScrollPane attachmentsScrollPane;
394  private javax.swing.JLabel ccLabel;
395  private javax.swing.JLabel ccText;
396  private javax.swing.JLabel datetimeText;
397  private javax.swing.JLabel directionText;
398  private javax.swing.JPanel envelopePanel;
399  private javax.swing.JLabel fromLabel;
400  private javax.swing.JLabel fromText;
401  private javax.swing.JScrollPane headersScrollPane;
402  private javax.swing.JTextArea headersTextArea;
403  private javax.swing.JPanel htmlPane;
404  private javax.swing.JScrollPane htmlScrollPane;
405  private javax.swing.JTextPane htmlbodyTextPane;
406  private javax.swing.JTabbedPane msgbodyTabbedPane;
407  private javax.swing.JScrollPane rtfbodyScrollPane;
408  private javax.swing.JTextPane rtfbodyTextPane;
409  private javax.swing.JToggleButton showImagesToggleButton;
410  private javax.swing.JLabel subjectLabel;
411  private javax.swing.JLabel subjectText;
412  private javax.swing.JScrollPane textbodyScrollPane;
413  private javax.swing.JTextArea textbodyTextArea;
414  private javax.swing.JLabel toLabel;
415  private javax.swing.JLabel toText;
416  private javax.swing.JButton viewInNewWindowButton;
417  // End of variables declaration//GEN-END:variables
418 
419  @Override
420  public void setNode(Node node) {
421  if (node == null) {
422  resetComponent();
423  return;
424  }
425 
426  artifact = node.getLookup().lookup(BlackboardArtifact.class);
427  if (artifact == null) {
428  resetComponent();
429  return;
430  }
431 
432  /*
433  * If the artifact is a keyword hit, use the associated artifact as the
434  * one to show in this viewer
435  */
436  if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) {
437  try {
438  getAssociatedArtifact(artifact).ifPresent(associatedArtifact -> {
439  artifact = associatedArtifact;
440  });
441  } catch (TskCoreException ex) {
442  LOGGER.log(Level.SEVERE, "error getting associated artifact", ex);
443  }
444  }
445 
446  if (artifact.getArtifactTypeID() == TSK_MESSAGE.getTypeID()) {
447  displayMsg();
448  } else if (artifact.getArtifactTypeID() == TSK_EMAIL_MSG.getTypeID()) {
449  displayEmailMsg();
450  } else {
451  resetComponent();
452  }
453  }
454 
465  private static Optional<BlackboardArtifact> getAssociatedArtifact(final BlackboardArtifact artifact) throws TskCoreException {
466  BlackboardAttribute attribute = artifact.getAttribute(TSK_ASSOCIATED_TYPE);
467  if (attribute != null) {
468  return Optional.of(artifact.getSleuthkitCase().getArtifactByArtifactId(attribute.getValueLong()));
469  }
470  return Optional.empty();
471  }
472 
473  @Override
474  @NbBundle.Messages("MessageContentViewer.title=Message")
475  public String getTitle() {
476  return Bundle.MessageContentViewer_title();
477  }
478 
479  @Override
480  @NbBundle.Messages("MessageContentViewer.toolTip=Displays messages.")
481  public String getToolTip() {
482  return Bundle.MessageContentViewer_toolTip();
483  }
484 
485  @Override
486  public DataContentViewer createInstance() {
487  return new MessageContentViewer();
488  }
489 
490  @Override
491  public Component getComponent() {
492  return this;
493  }
494 
495  @Override
496  final public void resetComponent() {
497  // reset all fields
498  fromText.setText("");
499  fromLabel.setEnabled(false);
500  toText.setText("");
501  toLabel.setEnabled(false);
502  ccText.setText("");
503  ccLabel.setEnabled(false);
504  subjectText.setText("");
505  subjectLabel.setEnabled(false);
506  datetimeText.setText("");
507  datetimeText.setEnabled(false);
508  directionText.setText("");
509  directionText.setEnabled(false);
510 
511  headersTextArea.setText("");
512  rtfbodyTextPane.setText("");
513  htmlbodyTextPane.setText("");
514  textbodyTextArea.setText("");
515  showImagesToggleButton.setEnabled(false);
516  msgbodyTabbedPane.setEnabled(false);
517  }
518 
519  @Override
520  public boolean isSupported(Node node) {
521  BlackboardArtifact nodeArtifact = node.getLookup().lookup(BlackboardArtifact.class);
522 
523  if (nodeArtifact == null) {
524  return false;
525  }
526  //if the artifact is a keyword hit, check if its associated artifact is a message or email.
527  if (nodeArtifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID()) {
528  try {
529  if (getAssociatedArtifact(nodeArtifact).map(MessageContentViewer::isMessageArtifact).orElse(false)) {
530  return true;
531  }
532  } catch (TskCoreException ex) {
533  LOGGER.log(Level.SEVERE, "error getting associated artifact", ex);
534  }
535  }
536  return isMessageArtifact(nodeArtifact);
537  }
538 
548  private static boolean isMessageArtifact(BlackboardArtifact nodeArtifact) {
549  final int artifactTypeID = nodeArtifact.getArtifactTypeID();
550  return artifactTypeID == TSK_EMAIL_MSG.getTypeID()
551  || artifactTypeID == TSK_MESSAGE.getTypeID();
552  }
553 
554  @Override
555  public int isPreferred(Node node) {
556  if (isSupported(node)) {
557  return 7;
558  }
559  return 0;
560  }
561 
571  private void configureTextArea(BlackboardAttribute.ATTRIBUTE_TYPE type, int index) throws TskCoreException {
572  String attributeText = getAttributeValueSafe(artifact, type);
573 
574  if (index == HTML_TAB_INDEX && StringUtils.isNotBlank(attributeText)) {
575  //special case for HTML, we need to 'cleanse' it
576  attributeText = wrapInHtmlBody(cleanseHTML(attributeText));
577  }
578  JTextComponent textComponent = textAreas.get(index);
579  textComponent.setText(attributeText);
580  textComponent.setCaretPosition(0); //make sure we start at the top
581  final boolean hasText = attributeText.length() > 0;
582 
583  msgbodyTabbedPane.setEnabledAt(index, hasText);
584  if (hasText) {
585  msgbodyTabbedPane.setSelectedIndex(index);
586  }
587  }
588 
589  private void enableCommonFields() {
590  msgbodyTabbedPane.setEnabled(true);
591  fromLabel.setEnabled(true);
592  toLabel.setEnabled(true);
593  subjectLabel.setEnabled(true);
594  datetimeText.setEnabled(true);
595  }
596 
597  private void configureAttachments() throws TskCoreException {
598  //TODO: Replace this with code to get the actual attachements!
599  final Set<AbstractFile> attachments = artifact.getChildren().stream()
600  .filter(AbstractFile.class::isInstance)
601  .map(AbstractFile.class::cast)
602  .collect(Collectors.toSet());
603  final int numberOfAttachments = attachments.size();
604 
605  msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, numberOfAttachments > 0);
606  msgbodyTabbedPane.setTitleAt(ATTM_TAB_INDEX, "Attachments (" + numberOfAttachments + ")");
607  drp.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(
608  new AttachmentsChildren(attachments)), null), true));
609  }
610 
611  private static String wrapInHtmlBody(String htmlText) {
612  return "<html><body>" + htmlText + "</body></html>";
613  }
614 
615  private void displayEmailMsg() {
616  enableCommonFields();
617 
618  directionText.setEnabled(false);
619  ccLabel.setEnabled(true);
620 
621  showImagesToggleButton.setEnabled(true);
622  showImagesToggleButton.setText("Show Images");
623  showImagesToggleButton.setSelected(false);
624 
625  try {
626  this.fromText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_FROM));
627  this.fromText.setToolTipText(getAttributeValueSafe(artifact, TSK_EMAIL_FROM));
628  this.toText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_TO));
629  this.toText.setToolTipText(getAttributeValueSafe(artifact, TSK_EMAIL_TO));
630  this.directionText.setText("");
631  this.ccText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_CC));
632  this.ccText.setToolTipText(getAttributeValueSafe(artifact, TSK_EMAIL_CC));
633  this.subjectText.setText(getAttributeValueSafe(artifact, TSK_SUBJECT));
634  this.datetimeText.setText(getAttributeValueSafe(artifact, TSK_DATETIME_RCVD));
635 
636  configureTextArea(TSK_HEADERS, HDR_TAB_INDEX);
637  configureTextArea(TSK_EMAIL_CONTENT_PLAIN, TEXT_TAB_INDEX);
638  configureTextArea(TSK_EMAIL_CONTENT_HTML, HTML_TAB_INDEX);
639  configureTextArea(TSK_EMAIL_CONTENT_RTF, RTF_TAB_INDEX);
640  configureAttachments();
641  } catch (TskCoreException ex) {
642  LOGGER.log(Level.WARNING, "Failed to get attributes for email message.", ex); //NON-NLS
643  }
644  }
645 
646  private void displayMsg() {
647  enableCommonFields();
648 
649  directionText.setEnabled(true);
650  ccLabel.setEnabled(false);
651 
652  try {
653  this.fromText.setText(getAttributeValueSafe(artifact, TSK_PHONE_NUMBER_FROM));
654  this.toText.setText(getAttributeValueSafe(artifact, TSK_PHONE_NUMBER_TO));
655  this.directionText.setText(getAttributeValueSafe(artifact, TSK_DIRECTION));
656  this.ccText.setText("");
657  this.subjectText.setText(getAttributeValueSafe(artifact, TSK_SUBJECT));
658  this.datetimeText.setText(getAttributeValueSafe(artifact, TSK_DATETIME));
659 
660  msgbodyTabbedPane.setEnabledAt(HTML_TAB_INDEX, false);
661  msgbodyTabbedPane.setEnabledAt(RTF_TAB_INDEX, false);
662  msgbodyTabbedPane.setEnabledAt(HDR_TAB_INDEX, false);
663  msgbodyTabbedPane.setEnabledAt(HDR_TAB_INDEX, false);
664  configureTextArea(TSK_TEXT, TEXT_TAB_INDEX);
665  configureAttachments();
666  } catch (TskCoreException ex) {
667  LOGGER.log(Level.WARNING, "Failed to get attributes for message.", ex); //NON-NLS
668  }
669  }
670 
671  private static String getAttributeValueSafe(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) throws TskCoreException {
672  return Optional.ofNullable(artifact.getAttribute(new BlackboardAttribute.Type(type)))
673  .map(BlackboardAttribute::getDisplayString)
674  .orElse("");
675  }
676 
684  static private String cleanseHTML(String htmlInString) {
685 
686  Document doc = Jsoup.parse(htmlInString);
687 
688  //fix all img tags
689  doc.select("img[src]").forEach(img -> img.attr("src", ""));
690 
691  return doc.html();
692  }
693 
694  private static class AttachmentsChildren extends Children.Keys<AbstractFile> {
695 
696  private final Set<AbstractFile> attachments;
697 
698  AttachmentsChildren(Set<AbstractFile> attachments) {
699  this.attachments = attachments;
700  }
701 
702  @Override
703  protected Node[] createNodes(AbstractFile t) {
704  return new Node[]{new AttachmentNode(t)};
705  }
706 
707  @Override
708  protected void addNotify() {
709  super.addNotify();
710  setKeys(attachments);
711  }
712  }
713 
720  private static class AttachmentNode extends FileNode {
721 
722  AttachmentNode(AbstractFile file) {
723  super(file, false);
724  }
725 
726  @Override
727  protected Sheet createSheet() {
728  Sheet sheet = super.createSheet();
729  Set<String> keepProps = new HashSet<>(Arrays.asList(
730  NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"),
731  NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"),
732  NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"),
733  NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"),
734  NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.sizeColLbl"),
735  NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.mimeType"),
736  NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.knownColLbl")));
737 
738  //Remove all other props except for the ones above
739  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
740  for(Property<?> p : sheetSet.getProperties()) {
741  if(!keepProps.contains(p.getName())){
742  sheetSet.remove(p.getName());
743  }
744  }
745 
746  return sheet;
747  }
748  }
749 }
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)
void showImagesToggleButtonActionPerformed(java.awt.event.ActionEvent evt)
static void configureTextPaneAsHtml(JTextPane pane)
Definition: Utilities.java:32
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
void viewInNewWindowButtonActionPerformed(java.awt.event.ActionEvent evt)

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