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