Autopsy  3.1
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;
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 = "/";
66  private final EmailResults emailResults;
67 
68 
69  public EmailExtracted(SleuthkitCase skCase) {
70  this.skCase = skCase;
71  emailResults = new EmailResults();
72  }
73 
74  private final class EmailResults extends Observable {
75 
76  private final Map<String, Map<String, List<Long>>> accounts = new LinkedHashMap<>();
77 
78  EmailResults() {
79  update();
80  }
81 
82  public Set<String> getAccounts() {
83  return accounts.keySet();
84  }
85 
86  public Set<String> getFolders(String account) {
87  return accounts.get(account).keySet();
88  }
89 
90  public List<Long> getArtifactIds(String account, String folder) {
91  return accounts.get(account).get(folder);
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 
198  private class AccountFactory extends ChildFactory.Detachable<String> implements Observer {
199 
200  /* The pcl is in the class because it has the easiest mechanisms to add and remove itself
201  * during its life cycles.
202  */
203  private final PropertyChangeListener pcl = new PropertyChangeListener() {
204  @Override
205  public void propertyChange(PropertyChangeEvent evt) {
206  String eventType = evt.getPropertyName();
207 
208  if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
209  if (((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG) {
210  emailResults.update();
211  }
212  }
213  else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
214  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
215  emailResults.update();
216  }
217  else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
218  // case was closed. Remove listeners so that we don't get called with a stale case handle
219  if (evt.getNewValue() == null) {
220  removeNotify();
221  skCase = null;
222  }
223  }
224  }
225  };
226 
227  @Override
228  protected void addNotify() {
232  emailResults.update();
233  emailResults.addObserver(this);
234  }
235 
236  @Override
237  protected void removeNotify() {
241  emailResults.deleteObserver(this);
242  }
243 
244  @Override
245  protected boolean createKeys(List<String> list) {
246  list.addAll(emailResults.getAccounts());
247  return true;
248  }
249 
250  @Override
251  protected Node createNodeForKey(String key) {
252  return new AccountNode(key);
253  }
254 
255  @Override
256  public void update(Observable o, Object arg) {
257  refresh(true);
258  }
259  }
260 
264  public class AccountNode extends DisplayableItemNode implements Observer {
265 
266  private final String accountName;
267 
268  public AccountNode(String accountName) {
269  super(Children.create(new FolderFactory(accountName), true), Lookups.singleton(accountName));
270  super.setName(accountName);
271  this.accountName = accountName;
272  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account-icon-16.png"); //NON-NLS
274  emailResults.addObserver(this);
275  }
276 
277  private void updateDisplayName() {
278  super.setDisplayName(accountName + " (" + emailResults.getFolders(accountName) + ")");
279  }
280 
281  @Override
282  protected Sheet createSheet() {
283  Sheet s = super.createSheet();
284  Sheet.Set ss = s.get(Sheet.PROPERTIES);
285  if (ss == null) {
286  ss = Sheet.createPropertiesSet();
287  s.put(ss);
288  }
289 
290  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.name"),
291  NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.displayName"),
292  NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.desc"),
293  getName()));
294 
295  return s;
296  }
297 
298  @Override
299  public boolean isLeafTypeNode() {
300  return false;
301  }
302 
303  @Override
304  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
305  return v.visit(this);
306  }
307 
308  @Override
309  public void update(Observable o, Object arg) {
311  }
312  }
313 
317  private class FolderFactory extends ChildFactory<String> implements Observer {
318 
319  private final String accountName;
320 
321  private FolderFactory(String accountName) {
322  super();
323  this.accountName = accountName;
324  emailResults.addObserver(this);
325  }
326 
327  @Override
328  protected boolean createKeys(List<String> list) {
329  list.addAll(emailResults.getFolders(accountName));
330  return true;
331  }
332 
333  @Override
334  protected Node createNodeForKey(String folderName) {
335  return new FolderNode(accountName, folderName);
336  }
337 
338  @Override
339  public void update(Observable o, Object arg) {
340  refresh(true);
341  }
342  }
343 
347  public class FolderNode extends DisplayableItemNode implements Observer {
348 
349  private final String accountName;
350  private final String folderName;
351 
352  public FolderNode(String accountName, String folderName) {
353  super(Children.create(new MessageFactory(accountName, folderName), true), Lookups.singleton(accountName));
354  super.setName(folderName);
355  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-16.png"); //NON-NLS
356  this.accountName = accountName;
357  this.folderName = folderName;
359  emailResults.addObserver(this);
360  }
361 
362  private void updateDisplayName() {
363  super.setDisplayName(folderName + " (" + emailResults.getArtifactIds(accountName, folderName).size() + ")");
364 
365  }
366 
367  @Override
368  public boolean isLeafTypeNode() {
369  return true;
370  }
371 
372  @Override
373  protected Sheet createSheet() {
374  Sheet s = super.createSheet();
375  Sheet.Set ss = s.get(Sheet.PROPERTIES);
376  if (ss == null) {
377  ss = Sheet.createPropertiesSet();
378  s.put(ss);
379  }
380 
381  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.name"),
382  NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.displayName"),
383  NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.desc"),
384  getName()));
385 
386  return s;
387  }
388 
389  @Override
390  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
391  return v.visit(this);
392  }
393 
394  @Override
395  public void update(Observable o, Object arg) {
397  }
398  }
399 
403  private class MessageFactory extends ChildFactory<Long> implements Observer {
404 
405  private final String accountName;
406  private final String folderName;
407 
408  private MessageFactory(String accountName, String folderName) {
409  super();
410  this.accountName = accountName;
411  this.folderName = folderName;
412  emailResults.addObserver(this);
413  }
414 
415  @Override
416  protected boolean createKeys(List<Long> list) {
417  list.addAll(emailResults.getArtifactIds(accountName, folderName));
418  return true;
419  }
420 
421  @Override
422  protected Node createNodeForKey(Long artifactId) {
423  if (skCase == null) {
424  return null;
425  }
426  try {
427  BlackboardArtifact artifact = skCase.getBlackboardArtifact(artifactId);
428  return new BlackboardArtifactNode(artifact);
429  } catch (TskException ex) {
430  logger.log(Level.WARNING, "Error creating mail messages nodes", ex); //NON-NLS
431  }
432  return null;
433  }
434 
435  @Override
436  public void update(Observable o, Object arg) {
437  refresh(true);
438  }
439  }
440 }
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static synchronized IngestManager getInstance()
BlackboardArtifact getBlackboardArtifact(long artifactID)
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:837
void addIngestModuleEventListener(final PropertyChangeListener listener)
static synchronized void addPropertyChangeListener(PropertyChangeListener listener)
Definition: Case.java:833
final Map< String, Map< String, List< Long > > > accounts
static Logger getLogger(String name)
Definition: Logger.java:131
CaseDbQuery executeQuery(String query)

Copyright © 2012-2015 Basis Technology. Generated on: Mon Oct 19 2015
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.