Autopsy  4.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
EmailExtracted.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2012-2014 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.datamodel;
20 
21 import java.beans.PropertyChangeEvent;
22 import java.beans.PropertyChangeListener;
23 import java.sql.ResultSet;
24 import java.sql.SQLException;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.LinkedHashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Observable;
31 import java.util.Observer;
32 import java.util.Set;
33 import java.util.logging.Level;
34 import org.openide.nodes.ChildFactory;
35 import org.openide.nodes.Children;
36 import org.openide.nodes.Node;
37 import org.openide.nodes.Sheet;
38 import org.openide.util.NbBundle;
39 import org.openide.util.lookup.Lookups;
44 import org.sleuthkit.datamodel.BlackboardArtifact;
45 import org.sleuthkit.datamodel.BlackboardAttribute;
46 import org.sleuthkit.datamodel.SleuthkitCase;
47 import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
48 import org.sleuthkit.datamodel.TskCoreException;
49 import org.sleuthkit.datamodel.TskException;
50 
57 public class EmailExtracted implements AutopsyVisitableItem {
58 
59  private static final String LABEL_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getLabel();
60  private static final String DISPLAY_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getDisplayName();
61  private static final Logger logger = Logger.getLogger(EmailExtracted.class.getName());
62  private static final String MAIL_ACCOUNT = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailAccount.text");
63  private static final String MAIL_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text");
64  private static final String MAIL_PATH_SEPARATOR = "/";
65  private SleuthkitCase skCase;
66  private final EmailResults emailResults;
67 
68  public EmailExtracted(SleuthkitCase skCase) {
69  this.skCase = skCase;
70  emailResults = new EmailResults();
71  }
72 
73  private final class EmailResults extends Observable {
74 
75  private final Map<String, Map<String, List<Long>>> accounts = new LinkedHashMap<>();
76 
77  EmailResults() {
78  update();
79  }
80 
81  public Set<String> getAccounts() {
82  return accounts.keySet();
83  }
84 
85  public Set<String> getFolders(String account) {
86  return accounts.get(account).keySet();
87  }
88 
89  public List<Long> getArtifactIds(String account, String folder) {
90  return accounts.get(account).get(folder);
91  }
92 
93  @SuppressWarnings("deprecation")
94  public void update() {
95  accounts.clear();
96  if (skCase == null) {
97  return;
98  }
99 
100  int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID();
101  int pathAttrId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID();
102  String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS
103  + "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
104  + "attribute_type_id=" + pathAttrId //NON-NLS
105  + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
106  + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
107 
108  try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
109  ResultSet resultSet = dbQuery.getResultSet();
110  while (resultSet.next()) {
111  final String path = resultSet.getString("value_text"); //NON-NLS
112  final long artifactId = resultSet.getLong("artifact_id"); //NON-NLS
113  final Map<String, String> parsedPath = parsePath(path);
114  final String account = parsedPath.get(MAIL_ACCOUNT);
115  final String folder = parsedPath.get(MAIL_FOLDER);
116 
117  Map<String, List<Long>> folders = accounts.get(account);
118  if (folders == null) {
119  folders = new LinkedHashMap<>();
120  accounts.put(account, folders);
121  }
122  List<Long> messages = folders.get(folder);
123  if (messages == null) {
124  messages = new ArrayList<>();
125  folders.put(folder, messages);
126  }
127  messages.add(artifactId);
128  }
129  } catch (TskCoreException | SQLException ex) {
130  logger.log(Level.WARNING, "Cannot initialize email extraction: ", ex); //NON-NLS
131  }
132  }
133 
134  private Map<String, String> parsePath(String path) {
135  Map<String, String> parsed = new HashMap<>();
136  String[] split = path.split(MAIL_PATH_SEPARATOR);
137  if (split.length < 4) {
138  parsed.put(MAIL_ACCOUNT, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text"));
139  parsed.put(MAIL_FOLDER, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text"));
140  return parsed;
141  }
142  parsed.put(MAIL_ACCOUNT, split[2]);
143  parsed.put(MAIL_FOLDER, split[3]);
144  return parsed;
145  }
146  }
147 
148  @Override
149  public <T> T accept(AutopsyItemVisitor<T> v) {
150  return v.visit(this);
151  }
152 
157  public class RootNode extends DisplayableItemNode {
158 
159  public RootNode() {
160  super(Children.create(new AccountFactory(), true), Lookups.singleton(DISPLAY_NAME));
161  super.setName(LABEL_NAME);
162  super.setDisplayName(DISPLAY_NAME);
163  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/mail-icon-16.png"); //NON-NLS
164  emailResults.update();
165  }
166 
167  @Override
168  public boolean isLeafTypeNode() {
169  return false;
170  }
171 
172  @Override
173  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
174  return v.visit(this);
175  }
176 
177  @Override
178  protected Sheet createSheet() {
179  Sheet s = super.createSheet();
180  Sheet.Set ss = s.get(Sheet.PROPERTIES);
181  if (ss == null) {
182  ss = Sheet.createPropertiesSet();
183  s.put(ss);
184  }
185 
186  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.name"),
187  NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.displayName"),
188  NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.desc"),
189  getName()));
190 
191  return s;
192  }
193 
194  /*
195  * TODO (AUT-1849): Correct or remove peristent column reordering code
196  *
197  * Added to support this feature.
198  */
199 // @Override
200 // public String getItemType() {
201 // return "EmailExtractedRoot"; //NON-NLS
202 // }
203  }
204 
208  private class AccountFactory extends ChildFactory.Detachable<String> implements Observer {
209 
210  /*
211  * The pcl is in the class because it has the easiest mechanisms to add
212  * and remove itself during its life cycles.
213  */
214  private final PropertyChangeListener pcl = new PropertyChangeListener() {
215  @Override
216  public void propertyChange(PropertyChangeEvent evt) {
217  String eventType = evt.getPropertyName();
218  if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
225  try {
233  ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
234  if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) {
235  emailResults.update();
236  }
237  } catch (IllegalStateException notUsed) {
241  }
242  } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
243  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
250  try {
252  emailResults.update();
253  } catch (IllegalStateException notUsed) {
257  }
258  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
259  // case was closed. Remove listeners so that we don't get called with a stale case handle
260  if (evt.getNewValue() == null) {
261  removeNotify();
262  skCase = null;
263  }
264  }
265  }
266  };
267 
268  @Override
269  protected void addNotify() {
273  emailResults.update();
274  emailResults.addObserver(this);
275  }
276 
277  @Override
278  protected void removeNotify() {
282  emailResults.deleteObserver(this);
283  }
284 
285  @Override
286  protected boolean createKeys(List<String> list) {
287  list.addAll(emailResults.getAccounts());
288  return true;
289  }
290 
291  @Override
292  protected Node createNodeForKey(String key) {
293  return new AccountNode(key);
294  }
295 
296  @Override
297  public void update(Observable o, Object arg) {
298  refresh(true);
299  }
300  }
301 
305  public class AccountNode extends DisplayableItemNode implements Observer {
306 
307  private final String accountName;
308 
309  public AccountNode(String accountName) {
310  super(Children.create(new FolderFactory(accountName), true), Lookups.singleton(accountName));
311  super.setName(accountName);
312  this.accountName = accountName;
313  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account-icon-16.png"); //NON-NLS
315  emailResults.addObserver(this);
316  }
317 
318  private void updateDisplayName() {
319  super.setDisplayName(accountName + " (" + emailResults.getFolders(accountName) + ")");
320  }
321 
322  @Override
323  protected Sheet createSheet() {
324  Sheet s = super.createSheet();
325  Sheet.Set ss = s.get(Sheet.PROPERTIES);
326  if (ss == null) {
327  ss = Sheet.createPropertiesSet();
328  s.put(ss);
329  }
330 
331  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.name"),
332  NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.displayName"),
333  NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.desc"),
334  getName()));
335 
336  return s;
337  }
338 
339  @Override
340  public boolean isLeafTypeNode() {
341  return false;
342  }
343 
344  @Override
345  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
346  return v.visit(this);
347  }
348 
349  @Override
350  public void update(Observable o, Object arg) {
352  }
353 
354  /*
355  * TODO (AUT-1849): Correct or remove peristent column reordering code
356  *
357  * Added to support this feature.
358  */
359 // @Override
360 // public String getItemType() {
361 // return "EmailExtractedAccount"; //NON-NLS
362 // }
363  }
364 
368  private class FolderFactory extends ChildFactory<String> implements Observer {
369 
370  private final String accountName;
371 
372  private FolderFactory(String accountName) {
373  super();
374  this.accountName = accountName;
375  emailResults.addObserver(this);
376  }
377 
378  @Override
379  protected boolean createKeys(List<String> list) {
380  list.addAll(emailResults.getFolders(accountName));
381  return true;
382  }
383 
384  @Override
385  protected Node createNodeForKey(String folderName) {
386  return new FolderNode(accountName, folderName);
387  }
388 
389  @Override
390  public void update(Observable o, Object arg) {
391  refresh(true);
392  }
393  }
394 
398  public class FolderNode extends DisplayableItemNode implements Observer {
399 
400  private final String accountName;
401  private final String folderName;
402 
403  public FolderNode(String accountName, String folderName) {
404  super(Children.create(new MessageFactory(accountName, folderName), true), Lookups.singleton(accountName));
405  super.setName(folderName);
406  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-16.png"); //NON-NLS
407  this.accountName = accountName;
408  this.folderName = folderName;
410  emailResults.addObserver(this);
411  }
412 
413  private void updateDisplayName() {
414  super.setDisplayName(folderName + " (" + emailResults.getArtifactIds(accountName, folderName).size() + ")");
415 
416  }
417 
418  @Override
419  public boolean isLeafTypeNode() {
420  return true;
421  }
422 
423  @Override
424  protected Sheet createSheet() {
425  Sheet s = super.createSheet();
426  Sheet.Set ss = s.get(Sheet.PROPERTIES);
427  if (ss == null) {
428  ss = Sheet.createPropertiesSet();
429  s.put(ss);
430  }
431 
432  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.name"),
433  NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.displayName"),
434  NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.desc"),
435  getName()));
436 
437  return s;
438  }
439 
440  @Override
441  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
442  return v.visit(this);
443  }
444 
445  @Override
446  public void update(Observable o, Object arg) {
448  }
449 
450  /*
451  * TODO (AUT-1849): Correct or remove peristent column reordering code
452  *
453  * Added to support this feature.
454  */
455 // @Override
456 // public String getItemType() {
457 // return "EmailExtractedFolder"; //NON-NLS
458 // }
459  }
460 
464  private class MessageFactory extends ChildFactory<Long> implements Observer {
465 
466  private final String accountName;
467  private final String folderName;
468 
469  private MessageFactory(String accountName, String folderName) {
470  super();
471  this.accountName = accountName;
472  this.folderName = folderName;
473  emailResults.addObserver(this);
474  }
475 
476  @Override
477  protected boolean createKeys(List<Long> list) {
478  list.addAll(emailResults.getArtifactIds(accountName, folderName));
479  return true;
480  }
481 
482  @Override
483  protected Node createNodeForKey(Long artifactId) {
484  if (skCase == null) {
485  return null;
486  }
487  try {
488  BlackboardArtifact artifact = skCase.getBlackboardArtifact(artifactId);
489  return new BlackboardArtifactNode(artifact);
490  } catch (TskException ex) {
491  logger.log(Level.WARNING, "Error creating mail messages nodes", ex); //NON-NLS
492  }
493  return null;
494  }
495 
496  @Override
497  public void update(Observable o, Object arg) {
498  refresh(true);
499  }
500  }
501 }
BlackboardArtifact.Type getBlackboardArtifactType()
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static synchronized IngestManager getInstance()
void removeIngestJobEventListener(final PropertyChangeListener listener)
void addIngestJobEventListener(final PropertyChangeListener listener)
List< Long > getArtifactIds(String account, String folder)
static synchronized void removePropertyChangeListener(PropertyChangeListener listener)
Definition: Case.java:1305
FolderNode(String accountName, String folderName)
void addIngestModuleEventListener(final PropertyChangeListener listener)
static synchronized void addPropertyChangeListener(PropertyChangeListener listener)
Definition: Case.java:1292
synchronized static Logger getLogger(String name)
Definition: Logger.java:166
final Map< String, Map< String, List< Long > > > accounts

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