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