interim commit of refresh updates in tree. Still need to do interestingitems.

This commit is contained in:
Brian Carrier 2014-05-05 01:07:58 -04:00
parent b37615e581
commit 33b463cd16
17 changed files with 1224 additions and 545 deletions

View File

@ -50,13 +50,13 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
protected void refreshDirectoryTree() { protected void refreshDirectoryTree() {
// The way the "directory tree" currently works, a new tags sub-tree // The way the "directory tree" currently works, a new tags sub-tree
// needs to be made to reflect the results of invoking tag Actions. The // needs to be made to reflect the results of invoking tag Actions. The
// way to do this is to call DirectoryTreeTopComponent.refreshTree(), // way to do this is to call DirectoryTreeTopComponent.refreshResultsTree(),
// which calls RootContentChildren.refreshKeys(BlackboardArtifact.ARTIFACT_TYPE... types) // which calls RootContentChildren.refreshKeys(BlackboardArtifact.ARTIFACT_TYPE... types)
// for the RootContentChildren object that is the child factory for the // for the RootContentChildren object that is the child factory for the
// ResultsNode that is the root of the tags sub-tree. There is a switch // ResultsNode that is the root of the tags sub-tree. There is a switch
// statement in RootContentChildren.refreshKeys() that maps both // statement in RootContentChildren.refreshKeys() that maps both
// BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE and BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT // BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE and BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT
// to making a call to refreshKey(TagsNodeKey). // to making a call to refreshKey(TagsNodeKey).
DirectoryTreeTopComponent.findInstance().refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); DirectoryTreeTopComponent.findInstance().refreshResultsTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
} }
} }

View File

@ -22,7 +22,6 @@ import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children.Keys; import org.openide.nodes.Children.Keys;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.Directory;
@ -119,8 +118,8 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
static class CreateAutopsyNodeVisitor extends AutopsyItemVisitor.Default<AbstractNode> { static class CreateAutopsyNodeVisitor extends AutopsyItemVisitor.Default<AbstractNode> {
@Override @Override
public ExtractedContentNode visit(ExtractedContent ec) { public ExtractedContent.RootNode visit(ExtractedContent ec) {
return new ExtractedContentNode(ec.getSleuthkitCase()); return ec.new RootNode(ec.getSleuthkitCase());
} }
@Override @Override
@ -145,22 +144,22 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
@Override @Override
public AbstractNode visit(KeywordHits kh) { public AbstractNode visit(KeywordHits kh) {
return kh.new KeywordHitsRootNode(); return kh.new RootNode();
} }
@Override @Override
public AbstractNode visit(HashsetHits hh) { public AbstractNode visit(HashsetHits hh) {
return hh.new HashsetHitsRootNode(); return hh.new RootNode();
} }
@Override @Override
public AbstractNode visit(InterestingHits ih) { public AbstractNode visit(InterestingHits ih) {
return ih.new InterestingHitsRootNode(); return ih.new RootNode();
} }
@Override @Override
public AbstractNode visit(EmailExtracted ee) { public AbstractNode visit(EmailExtracted ee) {
return ee.new EmailExtractedRootNode(); return ee.new RootNode();
} }
@Override @Override

View File

@ -19,8 +19,6 @@
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.datamodel;
/** /**
*
* @author dfickling
*/ */
interface AutopsyItemVisitor<T> { interface AutopsyItemVisitor<T> {

View File

@ -41,8 +41,8 @@ import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.TskException;
/** /**
* Node wrapping a blackboard artifact object. This represents a single artifact. * Node wrapping a blackboard artifact object. This is generated from several
* Its parent is typically an ArtifactTypeNode. * places in the tree.
*/ */
public class BlackboardArtifactNode extends DisplayableItemNode { public class BlackboardArtifactNode extends DisplayableItemNode {

View File

@ -20,18 +20,8 @@ package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode; import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode;
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode; import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedAccountNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedFolderNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedRootNode;
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode; import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode;
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode; import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode;
import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsRootNode;
import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode;
import org.sleuthkit.autopsy.datamodel.InterestingHits.InterestingHitsRootNode;
import org.sleuthkit.autopsy.datamodel.InterestingHits.InterestingHitsSetNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsKeywordNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsListNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode; import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode;
/** /**
@ -49,9 +39,9 @@ public interface DisplayableItemNodeVisitor<T> {
T visit(BlackboardArtifactNode ban); T visit(BlackboardArtifactNode ban);
T visit(ArtifactTypeNode atn); T visit(ExtractedContent.TypeNode atn);
T visit(ExtractedContentNode ecn); T visit(ExtractedContent.RootNode ecn);
T visit(FileTypeNode fsfn); T visit(FileTypeNode fsfn);
@ -69,27 +59,27 @@ public interface DisplayableItemNodeVisitor<T> {
T visit(RecentFilesFilterNode rffn); T visit(RecentFilesFilterNode rffn);
T visit(KeywordHitsRootNode khrn); T visit(KeywordHits.RootNode khrn);
T visit(KeywordHitsListNode khsn); T visit(KeywordHits.ListNode khsn);
T visit(KeywordHitsKeywordNode khmln); T visit(KeywordHits.TermNode khmln);
T visit(HashsetHitsRootNode hhrn); T visit(HashsetHits.RootNode hhrn);
T visit(HashsetHitsSetNode hhsn); T visit(HashsetHits.HashsetNameNode hhsn);
T visit(EmailExtractedRootNode eern); T visit(EmailExtracted.RootNode eern);
T visit(EmailExtractedAccountNode eean); T visit(EmailExtracted.AccountNode eean);
T visit(EmailExtractedFolderNode eefn); T visit(EmailExtracted.FolderNode eefn);
T visit(TagsNode node); T visit(TagsNode node);
T visit(InterestingHitsRootNode ihrn); T visit(InterestingHits.RootNode ihrn);
T visit(InterestingHitsSetNode ihsn); T visit(InterestingHits.SetNameNode ihsn);
T visit(TagNameNode node); T visit(TagNameNode node);
@ -155,12 +145,12 @@ public interface DisplayableItemNodeVisitor<T> {
} }
@Override @Override
public T visit(ArtifactTypeNode atn) { public T visit(ExtractedContent.TypeNode atn) {
return defaultVisit(atn); return defaultVisit(atn);
} }
@Override @Override
public T visit(ExtractedContentNode ecn) { public T visit(ExtractedContent.RootNode ecn) {
return defaultVisit(ecn); return defaultVisit(ecn);
} }
@ -205,17 +195,17 @@ public interface DisplayableItemNodeVisitor<T> {
} }
@Override @Override
public T visit(KeywordHitsRootNode khrn) { public T visit(KeywordHits.RootNode khrn) {
return defaultVisit(khrn); return defaultVisit(khrn);
} }
@Override @Override
public T visit(KeywordHitsListNode khsn) { public T visit(KeywordHits.ListNode khsn) {
return defaultVisit(khsn); return defaultVisit(khsn);
} }
@Override @Override
public T visit(KeywordHitsKeywordNode khmln) { public T visit(KeywordHits.TermNode khmln) {
return defaultVisit(khmln); return defaultVisit(khmln);
} }
@ -235,37 +225,37 @@ public interface DisplayableItemNodeVisitor<T> {
} }
@Override @Override
public T visit(HashsetHitsRootNode hhrn) { public T visit(HashsetHits.RootNode hhrn) {
return defaultVisit(hhrn); return defaultVisit(hhrn);
} }
@Override @Override
public T visit(HashsetHitsSetNode hhsn) { public T visit(HashsetHits.HashsetNameNode hhsn) {
return defaultVisit(hhsn); return defaultVisit(hhsn);
} }
@Override @Override
public T visit(InterestingHitsRootNode ihrn) { public T visit(InterestingHits.RootNode ihrn) {
return defaultVisit(ihrn); return defaultVisit(ihrn);
} }
@Override @Override
public T visit(InterestingHitsSetNode ihsn) { public T visit(InterestingHits.SetNameNode ihsn) {
return defaultVisit(ihsn); return defaultVisit(ihsn);
} }
@Override @Override
public T visit(EmailExtractedRootNode eern) { public T visit(EmailExtracted.RootNode eern) {
return defaultVisit(eern); return defaultVisit(eern);
} }
@Override @Override
public T visit(EmailExtractedAccountNode eean) { public T visit(EmailExtracted.AccountNode eean) {
return defaultVisit(eean); return defaultVisit(eean);
} }
@Override @Override
public T visit(EmailExtractedFolderNode eefn) { public T visit(EmailExtracted.FolderNode eefn) {
return defaultVisit(eefn); return defaultVisit(eefn);
} }

View File

@ -18,6 +18,8 @@
*/ */
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
@ -25,6 +27,9 @@ import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
@ -34,11 +39,14 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.TskException;
/** /**
* Support for TSK_EMAIL_MSG nodes and displaying emails in the directory tree * Support for TSK_EMAIL_MSG nodes and displaying emails in the directory tree
* Email messages are grouped into parent folders, and the folders are grouped * Email messages are grouped into parent folders, and the folders are grouped
@ -54,64 +62,85 @@ public class EmailExtracted implements AutopsyVisitableItem {
private static final String MAIL_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text"); private static final String MAIL_FOLDER = NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.mailFolder.text");
private static final String MAIL_PATH_SEPARATOR = "/"; private static final String MAIL_PATH_SEPARATOR = "/";
private SleuthkitCase skCase; private SleuthkitCase skCase;
private Map<String, Map<String, List<Long>>> accounts; private EmailResults emailResults;
public EmailExtracted(SleuthkitCase skCase) { public EmailExtracted(SleuthkitCase skCase) {
this.skCase = skCase; this.skCase = skCase;
accounts = new LinkedHashMap<>(); emailResults = new EmailResults();
} }
@SuppressWarnings("deprecation") private final class EmailResults extends Observable {
private void initArtifacts() { private Map<String, Map<String, List<Long>>> accounts = new LinkedHashMap<>();
accounts.clear();
try { EmailResults() {
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(); update();
int pathAttrId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID();
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS
+ "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
+ "attribute_type_id=" + pathAttrId //NON-NLS
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
ResultSet rs = skCase.runQuery(query);
while (rs.next()) {
final String path = rs.getString("value_text"); //NON-NLS
final long artifactId = rs.getLong("artifact_id"); //NON-NLS
final Map<String, String> parsedPath = parsePath(path);
final String account = parsedPath.get(MAIL_ACCOUNT);
final String folder = parsedPath.get(MAIL_FOLDER);
Map<String, List<Long>> folders = accounts.get(account);
if (folders == null) {
folders = new LinkedHashMap<>();
accounts.put(account, folders);
}
List<Long> messages = folders.get(folder);
if (messages == null) {
messages = new ArrayList<>();
folders.put(folder, messages);
}
messages.add(artifactId);
}
skCase.closeRunQuery(rs);
} catch (SQLException ex) {
logger.log(Level.WARNING, "Cannot initialize email extraction", ex); //NON-NLS
} }
}
public Set<String> getAccounts() {
return accounts.keySet();
}
public Set<String> getFolders(String account) {
return accounts.get(account).keySet();
}
public List<Long> getArtifactIds(String account, String folder) {
return accounts.get(account).get(folder);
}
public void update() {
accounts.clear();
try {
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID();
int pathAttrId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID();
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS
+ "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
+ "attribute_type_id=" + pathAttrId //NON-NLS
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
ResultSet rs = skCase.runQuery(query);
while (rs.next()) {
final String path = rs.getString("value_text"); //NON-NLS
final long artifactId = rs.getLong("artifact_id"); //NON-NLS
final Map<String, String> parsedPath = parsePath(path);
final String account = parsedPath.get(MAIL_ACCOUNT);
final String folder = parsedPath.get(MAIL_FOLDER);
private static Map<String, String> parsePath(String path) { Map<String, List<Long>> folders = accounts.get(account);
Map<String, String> parsed = new HashMap<>(); if (folders == null) {
String[] split = path.split(MAIL_PATH_SEPARATOR); folders = new LinkedHashMap<>();
if (split.length < 4) { accounts.put(account, folders);
logger.log(Level.WARNING, "Unexpected number of tokens when parsing email PATH: {0}, will use defaults", split.length); //NON-NLS }
parsed.put(MAIL_ACCOUNT, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text")); List<Long> messages = folders.get(folder);
parsed.put(MAIL_FOLDER, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text")); if (messages == null) {
messages = new ArrayList<>();
folders.put(folder, messages);
}
messages.add(artifactId);
}
skCase.closeRunQuery(rs);
} catch (SQLException ex) {
logger.log(Level.WARNING, "Cannot initialize email extraction", ex); //NON-NLS
}
}
private Map<String, String> parsePath(String path) {
Map<String, String> parsed = new HashMap<>();
String[] split = path.split(MAIL_PATH_SEPARATOR);
if (split.length < 4) {
logger.log(Level.WARNING, "Unexpected number of tokens when parsing email PATH: {0}, will use defaults", split.length); //NON-NLS
parsed.put(MAIL_ACCOUNT, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text"));
parsed.put(MAIL_FOLDER, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text"));
return parsed;
}
parsed.put(MAIL_ACCOUNT, split[2]);
parsed.put(MAIL_FOLDER, split[3]);
return parsed; return parsed;
} }
parsed.put(MAIL_ACCOUNT, split[2]);
parsed.put(MAIL_FOLDER, split[3]);
return parsed;
} }
@Override @Override
@ -122,94 +151,94 @@ public class EmailExtracted implements AutopsyVisitableItem {
/** /**
* Mail root node showing all emails * Mail root node showing all emails
*/ */
public class EmailExtractedRootNodeFlat extends DisplayableItemNode { // public class FlatRootNode extends DisplayableItemNode {
//
public EmailExtractedRootNodeFlat() { // public FlatRootNode() {
super(Children.create(new EmailExtractedRootChildrenFlat(), true), Lookups.singleton(DISPLAY_NAME)); // super(Children.create(new FlatRootFactory(), true), Lookups.singleton(DISPLAY_NAME));
super.setName(LABEL_NAME); // super.setName(LABEL_NAME);
super.setDisplayName(DISPLAY_NAME); // super.setDisplayName(DISPLAY_NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/mail-icon-16.png"); //NON-NLS // this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/mail-icon-16.png"); //NON-NLS
initArtifacts(); // initArtifacts();
} // }
//
@Override // @Override
public boolean isLeafTypeNode() { // public boolean isLeafTypeNode() {
return false; // return false;
} // }
//
@Override // @Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) { // public <T> T accept(DisplayableItemNodeVisitor<T> v) {
//return v.visit(this); // //return v.visit(this);
return null; // return null;
} // }
//
@Override // @Override
protected Sheet createSheet() { // protected Sheet createSheet() {
Sheet s = super.createSheet(); // Sheet s = super.createSheet();
Sheet.Set ss = s.get(Sheet.PROPERTIES); // Sheet.Set ss = s.get(Sheet.PROPERTIES);
if (ss == null) { // if (ss == null) {
ss = Sheet.createPropertiesSet(); // ss = Sheet.createPropertiesSet();
s.put(ss); // s.put(ss);
} // }
//
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.name"), // ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.displayName"), // NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.displayName"),
NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.desc"), // NbBundle.getMessage(this.getClass(), "EmailExtracted.createSheet.name.desc"),
getName())); // getName()));
return s; // return s;
} // }
} // }
//
/** // /**
* Mail root child node showing flattened emails // * Mail root child node showing flattened emails
*/ // */
private class EmailExtractedRootChildrenFlat extends ChildFactory<BlackboardArtifact> { // private class FlatRootFactory extends ChildFactory<BlackboardArtifact> {
//
private EmailExtractedRootChildrenFlat() { // private FlatRootFactory() {
super(); // super();
} // }
//
@Override // @Override
protected boolean createKeys(List<BlackboardArtifact> list) { // protected boolean createKeys(List<BlackboardArtifact> list) {
//flatten all emails // //flatten all emails
List<BlackboardArtifact> tempList = new ArrayList<>(); // List<BlackboardArtifact> tempList = new ArrayList<>();
for (String account : accounts.keySet()) { // for (String account : accounts.keySet()) {
Map<String, List<Long>> folders = accounts.get(account); // Map<String, List<Long>> folders = accounts.get(account);
for (String folder : folders.keySet()) { // for (String folder : folders.keySet()) {
List<Long> messages = folders.get(folder); // List<Long> messages = folders.get(folder);
for (long l : messages) { // for (long l : messages) {
try { // try {
//TODO: bulk artifact gettings // //TODO: bulk artifact gettings
tempList.add(skCase.getBlackboardArtifact(l)); // tempList.add(skCase.getBlackboardArtifact(l));
} catch (TskException ex) { // } catch (TskException ex) {
logger.log(Level.WARNING, "Error creating mail messages nodes", ex); //NON-NLS // logger.log(Level.WARNING, "Error creating mail messages nodes", ex); //NON-NLS
} // }
} // }
} // }
} // }
//
list.addAll(tempList); // list.addAll(tempList);
return true; // return true;
} // }
//
@Override // @Override
protected Node createNodeForKey(BlackboardArtifact artifact) { // protected Node createNodeForKey(BlackboardArtifact artifact) {
return new BlackboardArtifactNode(artifact); // return new BlackboardArtifactNode(artifact);
} // }
} // }
/** /**
* Mail root node grouping all mail accounts, supports account-> folder * Mail root node grouping all mail accounts, supports account-> folder
* structure * structure
*/ */
public class EmailExtractedRootNode extends DisplayableItemNode { public class RootNode extends DisplayableItemNode {
public EmailExtractedRootNode() { public RootNode() {
super(Children.create(new EmailExtractedRootChildren(), true), Lookups.singleton(DISPLAY_NAME)); super(Children.create(new AccountFactory(), true), Lookups.singleton(DISPLAY_NAME));
super.setName(LABEL_NAME); super.setName(LABEL_NAME);
super.setDisplayName(DISPLAY_NAME); super.setDisplayName(DISPLAY_NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/mail-icon-16.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/mail-icon-16.png"); //NON-NLS
initArtifacts(); emailResults.update();
} }
@Override @Override
@ -220,7 +249,6 @@ public class EmailExtracted implements AutopsyVisitableItem {
@Override @Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this); return v.visit(this);
//return null;
} }
@Override @Override
@ -244,30 +272,74 @@ public class EmailExtracted implements AutopsyVisitableItem {
/** /**
* Mail root child node creating each account node * Mail root child node creating each account node
*/ */
private class EmailExtractedRootChildren extends ChildFactory<String> { private class AccountFactory extends ChildFactory.Detachable<String> implements Observer {
/* The pcl is in the class because it has the easiest mechanisms to add and remove itself
* during its life cycles.
*/
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestEvent.DATA.toString())) {
if (((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG) {
emailResults.update();
}
}
else if (eventType.equals(IngestManager.IngestEvent.INGEST_JOB_COMPLETED.toString())
|| eventType.equals(IngestManager.IngestEvent.INGEST_JOB_CANCELLED.toString())) {
emailResults.update();
}
}
};
@Override
protected void addNotify() {
IngestManager.addPropertyChangeListener(pcl);
emailResults.addObserver(this);
}
@Override
protected void removeNotify() {
IngestManager.removePropertyChangeListener(pcl);
emailResults.deleteObserver(this);
}
@Override @Override
protected boolean createKeys(List<String> list) { protected boolean createKeys(List<String> list) {
list.addAll(accounts.keySet()); list.addAll(emailResults.getAccounts());
return true; return true;
} }
@Override @Override
protected Node createNodeForKey(String key) { protected Node createNodeForKey(String key) {
return new EmailExtractedAccountNode(key, accounts.get(key)); return new AccountNode(key);
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
} }
} }
/** /**
* Account node representation * Account node representation
*/ */
public class EmailExtractedAccountNode extends DisplayableItemNode { public class AccountNode extends DisplayableItemNode implements Observer {
private String accountName;
public EmailExtractedAccountNode(String name, Map<String, List<Long>> children) {
super(Children.create(new EmailExtractedAccountChildrenNode(children), true), Lookups.singleton(name)); public AccountNode(String accountName) {
super.setName(name); super(Children.create(new FolderFactory(accountName), true), Lookups.singleton(accountName));
super.setDisplayName(name + " (" + children.size() + ")"); super.setName(accountName);
this.accountName = accountName;
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account-icon-16.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account-icon-16.png"); //NON-NLS
updateDisplayName();
emailResults.addObserver(this);
}
private void updateDisplayName() {
super.setDisplayName(accountName + " (" + emailResults.getFolders(accountName) + ")");
} }
@Override @Override
@ -296,43 +368,61 @@ public class EmailExtracted implements AutopsyVisitableItem {
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this); return v.visit(this);
} }
@Override
public void update(Observable o, Object arg) {
updateDisplayName();
}
} }
/** /**
* Account node child creating sub nodes for every folder * Account node child creating sub nodes for every folder
*/ */
private class EmailExtractedAccountChildrenNode extends ChildFactory<String> { private class FolderFactory extends ChildFactory<String> implements Observer {
private Map<String, List<Long>> folders; private String accountName;
private EmailExtractedAccountChildrenNode(Map<String, List<Long>> folders) { private FolderFactory(String accountName) {
super(); super();
this.folders = folders; this.accountName = accountName;
emailResults.addObserver(this);
} }
@Override @Override
protected boolean createKeys(List<String> list) { protected boolean createKeys(List<String> list) {
list.addAll(folders.keySet()); list.addAll(emailResults.getFolders(accountName));
return true; return true;
} }
@Override @Override
protected Node createNodeForKey(String key) { protected Node createNodeForKey(String folderName) {
return new EmailExtractedFolderNode(key, folders.get(key)); return new FolderNode(accountName, folderName);
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
} }
} }
/** /**
* Node representing mail folder * Node representing mail folder
*/ */
public class EmailExtractedFolderNode extends DisplayableItemNode { public class FolderNode extends DisplayableItemNode implements Observer {
private String accountName;
public EmailExtractedFolderNode(String name, List<Long> children) { private String folderName;
super(Children.create(new EmailExtractedFolderChildrenNode(children), true), Lookups.singleton(name));
super.setName(name); public FolderNode(String accountName, String folderName) {
super.setDisplayName(name + " (" + children.size() + ")"); super(Children.create(new MessageFactory(accountName, folderName), true), Lookups.singleton(accountName));
super.setName(folderName);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-16.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-16.png"); //NON-NLS
updateDisplayName();
emailResults.addObserver(this);
}
private void updateDisplayName() {
super.setDisplayName(folderName + " (" + emailResults.getArtifactIds(accountName, folderName).size() + ")");
} }
@Override @Override
@ -361,38 +451,48 @@ public class EmailExtracted implements AutopsyVisitableItem {
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this); return v.visit(this);
} }
@Override
public void update(Observable o, Object arg) {
updateDisplayName();
}
} }
/** /**
* Node representing mail folder content (mail messages) * Node representing mail folder content (mail messages)
*/ */
private class EmailExtractedFolderChildrenNode extends ChildFactory<BlackboardArtifact> { private class MessageFactory extends ChildFactory<Long> implements Observer {
private List<Long> messages; private String accountName;
private String folderName;
private EmailExtractedFolderChildrenNode(List<Long> messages) { private MessageFactory(String accountName, String folderName) {
super(); super();
this.messages = messages; this.accountName = accountName;
this.folderName = folderName;
emailResults.addObserver(this);
} }
@Override @Override
protected boolean createKeys(List<BlackboardArtifact> list) { protected boolean createKeys(List<Long> list) {
List<BlackboardArtifact> tempList = new ArrayList<>(); list.addAll(emailResults.getArtifactIds(accountName, folderName));
for (long l : messages) {
try {
//TODO: bulk artifact gettings
tempList.add(skCase.getBlackboardArtifact(l));
} catch (TskException ex) {
logger.log(Level.WARNING, "Error creating mail messages nodes", ex); //NON-NLS
}
}
list.addAll(tempList);
return true; return true;
} }
@Override @Override
protected Node createNodeForKey(BlackboardArtifact artifact) { protected Node createNodeForKey(Long artifactId) {
return new BlackboardArtifactNode(artifact); try {
BlackboardArtifact artifact = skCase.getBlackboardArtifact(artifactId);
return new BlackboardArtifactNode(artifact);
} catch (TskException ex) {
logger.log(Level.WARNING, "Error creating mail messages nodes", ex); //NON-NLS
}
return null;
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
} }
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011 Basis Technology Corp. * Copyright 2011-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -18,17 +18,59 @@
*/ */
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CALENDAR_ENTRY;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_INSTALLED_PROG;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_SPEED_DIAL_ENTRY;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException;
/** /**
* Parent of the "extracted content" artifacts to be displayed in the tree. Other * Parent of the "extracted content" artifacts to be displayed in the tree.
* artifacts are displayed under other more specific parents. * Other artifacts are displayed under other more specific parents.
*/ */
class ExtractedContent implements AutopsyVisitableItem{ public class ExtractedContent implements AutopsyVisitableItem {
SleuthkitCase skCase; private SleuthkitCase skCase;
public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text");
public ExtractedContent(SleuthkitCase skCase){ public ExtractedContent(SleuthkitCase skCase) {
this.skCase = skCase; this.skCase = skCase;
} }
@ -37,7 +79,310 @@ import org.sleuthkit.datamodel.SleuthkitCase;
return v.visit(this); return v.visit(this);
} }
public SleuthkitCase getSleuthkitCase(){ public SleuthkitCase getSleuthkitCase() {
return skCase; return skCase;
} }
public class RootNode extends DisplayableItemNode {
public RootNode(SleuthkitCase skCase) {
super(Children.create(new TypeFactory(skCase), true), Lookups.singleton(NAME));
super.setName(NAME);
super.setDisplayName(NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png"); //NON-NLS
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
Sheet.Set ss = s.get(Sheet.PROPERTIES);
if (ss == null) {
ss = Sheet.createPropertiesSet();
s.put(ss);
}
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.displayName"),
NbBundle.getMessage(this.getClass(), "ExtractedContentNode.createSheet.name.desc"),
NAME));
return s;
}
}
/**
* Creates the children for the ExtractedContent area of the results tree.
* This area has all of the blackboard artifacts that are not displayed in a
* more specific form elsewhere in the tree.
*/
private class TypeFactory extends ChildFactory.Detachable<BlackboardArtifact.ARTIFACT_TYPE> {
private SleuthkitCase skCase;
private final ArrayList<BlackboardArtifact.ARTIFACT_TYPE> doNotShow;
// maps the artifact type to its child node
private HashMap<BlackboardArtifact.ARTIFACT_TYPE, TypeNode> typeNodeList = new HashMap<>();
public TypeFactory(SleuthkitCase skCase) {
super();
this.skCase = skCase;
// these are shown in other parts of the UI tree
doNotShow = new ArrayList<>();
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
doNotShow.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT);
}
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestEvent.DATA.toString())) {
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue();
if (doNotShow.contains(event.getArtifactType()) == false) {
refresh(true);
}
} else if (eventType.equals(IngestManager.IngestEvent.INGEST_JOB_COMPLETED.toString())
|| eventType.equals(IngestManager.IngestEvent.INGEST_JOB_CANCELLED.toString())) {
refresh(true);
}
}
};
@Override
protected void addNotify() {
IngestManager.addPropertyChangeListener(pcl);
}
@Override
protected void removeNotify() {
IngestManager.removePropertyChangeListener(pcl);
typeNodeList.clear();
}
@Override
protected boolean createKeys(List<BlackboardArtifact.ARTIFACT_TYPE> list) {
try {
List<BlackboardArtifact.ARTIFACT_TYPE> inUse = skCase.getBlackboardArtifactTypesInUse();
inUse.removeAll(doNotShow);
Collections.sort(inUse,
new Comparator<BlackboardArtifact.ARTIFACT_TYPE>() {
@Override
public int compare(BlackboardArtifact.ARTIFACT_TYPE a, BlackboardArtifact.ARTIFACT_TYPE b) {
return a.getDisplayName().compareTo(b.getDisplayName());
}
});
list.addAll(inUse);
// the create node method will get called only for new types
// refresh the counts if we already created them from a previous update
for (BlackboardArtifact.ARTIFACT_TYPE art : inUse) {
TypeNode node = typeNodeList.get(art);
if (node != null) {
node.updateDisplayName();
}
}
} catch (TskCoreException ex) {
Logger.getLogger(TypeFactory.class.getName()).log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage()); //NON-NLS
return false;
}
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact.ARTIFACT_TYPE key) {
TypeNode node = new TypeNode(key, skCase);
typeNodeList.put(key, node);
return node;
}
}
/**
* Node encapsulating blackboard artifact type. This is used on the
* left-hand navigation side of the Autopsy UI as the parent node for all of
* the artifacts of a given type. Its children will be
* BlackboardArtifactNode objects.
*/
public class TypeNode extends DisplayableItemNode {
private BlackboardArtifact.ARTIFACT_TYPE type;
private long childCount = 0;
private SleuthkitCase skCase;
TypeNode(BlackboardArtifact.ARTIFACT_TYPE type, SleuthkitCase skCase) {
super(Children.create(new ArtifactFactory(type, skCase), true), Lookups.singleton(type.getDisplayName()));
super.setName(type.getLabel());
this.skCase = skCase;
this.type = type;
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/" + getIcon(type)); //NON-NLS
updateDisplayName();
}
final void updateDisplayName() {
// NOTE: This completely destroys our lazy-loading ideal
// a performance increase might be had by adding a
// "getBlackboardArtifactCount()" method to skCase
try {
this.childCount = skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
} catch (TskException ex) {
Logger.getLogger(TypeNode.class.getName())
.log(Level.WARNING, "Error getting child count", ex); //NON-NLS
}
super.setDisplayName(type.getDisplayName() + " (" + childCount + ")");
}
@Override
protected Sheet createSheet() {
Sheet s = super.createSheet();
Sheet.Set ss = s.get(Sheet.PROPERTIES);
if (ss == null) {
ss = Sheet.createPropertiesSet();
s.put(ss);
}
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.name"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.displayName"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.artType.desc"),
type.getDisplayName()));
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.name"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.displayName"),
NbBundle.getMessage(this.getClass(), "ArtifactTypeNode.createSheet.childCnt.desc"),
childCount));
return s;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
}
// @@@ TODO: Merge with BlackboartArtifactNode.getIcon()
private String getIcon(BlackboardArtifact.ARTIFACT_TYPE type) {
switch (type) {
case TSK_WEB_BOOKMARK:
return "bookmarks.png"; //NON-NLS
case TSK_WEB_COOKIE:
return "cookies.png"; //NON-NLS
case TSK_WEB_HISTORY:
return "history.png"; //NON-NLS
case TSK_WEB_DOWNLOAD:
return "downloads.png"; //NON-NLS
case TSK_INSTALLED_PROG:
return "programs.png"; //NON-NLS
case TSK_RECENT_OBJECT:
return "recent_docs.png"; //NON-NLS
case TSK_DEVICE_ATTACHED:
return "usb_devices.png"; //NON-NLS
case TSK_WEB_SEARCH_QUERY:
return "searchquery.png"; //NON-NLS
case TSK_METADATA_EXIF:
return "camera-icon-16.png"; //NON-NLS
case TSK_CONTACT:
return "contact.png"; //NON-NLS
case TSK_MESSAGE:
return "message.png"; //NON-NLS
case TSK_CALLLOG:
return "calllog.png"; //NON-NLS
case TSK_CALENDAR_ENTRY:
return "calendar.png"; //NON-NLS
case TSK_SPEED_DIAL_ENTRY:
return "speeddialentry.png"; //NON-NLS
case TSK_BLUETOOTH_PAIRING:
return "bluetooth.png"; //NON-NLS
case TSK_GPS_BOOKMARK:
return "gpsfav.png"; //NON-NLS
case TSK_GPS_LAST_KNOWN_LOCATION:
return "gps-lastlocation.png"; //NON-NLS
case TSK_GPS_SEARCH:
return "gps-search.png"; //NON-NLS
case TSK_SERVICE_ACCOUNT:
return "account-icon-16.png"; //NON-NLS
case TSK_ENCRYPTION_DETECTED:
return "encrypted-file.png"; //NON-NLS
case TSK_EXT_MISMATCH_DETECTED:
return "mismatch-16.png"; //NON-NLS
}
return "artifact-icon.png"; //NON-NLS
}
@Override
public boolean isLeafTypeNode() {
return true;
}
}
/**
* Creates children for a given artifact type
*/
private static class ArtifactFactory extends ChildFactory.Detachable<BlackboardArtifact> {
private SleuthkitCase skCase;
private BlackboardArtifact.ARTIFACT_TYPE type;
public ArtifactFactory(BlackboardArtifact.ARTIFACT_TYPE type, SleuthkitCase skCase) {
super();
this.skCase = skCase;
this.type = type;
}
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestEvent.DATA.toString())) {
final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue();
if (event.getArtifactType() == type) {
refresh(true);
}
} else if (eventType.equals(IngestManager.IngestEvent.INGEST_JOB_COMPLETED.toString())
|| eventType.equals(IngestManager.IngestEvent.INGEST_JOB_CANCELLED.toString())) {
refresh(true);
}
}
};
@Override
protected void addNotify() {
IngestManager.addPropertyChangeListener(pcl);
}
@Override
protected void removeNotify() {
IngestManager.removePropertyChangeListener(pcl);
}
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
try {
List<BlackboardArtifact> arts = skCase.getBlackboardArtifacts(type.getTypeID());
list.addAll(arts);
} catch (TskException ex) {
Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS
}
return true;
}
@Override
protected Node createNodeForKey(BlackboardArtifact key) {
return new BlackboardArtifactNode(key);
}
}
} }

View File

@ -18,12 +18,16 @@
*/ */
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
@ -34,13 +38,16 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.TskException;
/** /**
* Hash set hits node support * Hash set hits node support. Inner classes have all of the nodes in the tree.
*/ */
public class HashsetHits implements AutopsyVisitableItem { public class HashsetHits implements AutopsyVisitableItem {
@ -48,65 +55,85 @@ public class HashsetHits implements AutopsyVisitableItem {
private static final String DISPLAY_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(); private static final String DISPLAY_NAME = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName();
private static final Logger logger = Logger.getLogger(HashsetHits.class.getName()); private static final Logger logger = Logger.getLogger(HashsetHits.class.getName());
private SleuthkitCase skCase; private SleuthkitCase skCase;
private Map<String, Set<Long>> hashSetHitsMap; private HashsetResults hashsetResults;
public HashsetHits(SleuthkitCase skCase) { public HashsetHits(SleuthkitCase skCase) {
this.skCase = skCase; this.skCase = skCase;
hashSetHitsMap = new LinkedHashMap<>(); hashsetResults = new HashsetResults();
}
@SuppressWarnings("deprecation")
private void initArtifacts() {
hashSetHitsMap.clear();
ResultSet rs = null;
try {
int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID();
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS
+ "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
+ "attribute_type_id=" + setNameId //NON-NLS
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
rs = skCase.runQuery(query);
while (rs.next()) {
String value = rs.getString("value_text"); //NON-NLS
long artifactId = rs.getLong("artifact_id"); //NON-NLS
if (!hashSetHitsMap.containsKey(value)) {
hashSetHitsMap.put(value, new HashSet<Long>());
}
hashSetHitsMap.get(value).add(artifactId);
}
} catch (SQLException ex) {
logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS
} finally {
if (rs != null) {
try {
skCase.closeRunQuery(rs);
} catch (SQLException ex) {
logger.log(Level.WARNING, "Error closing result set after getting hashset hits", ex); //NON-NLS
}
}
}
} }
@Override @Override
public <T> T accept(AutopsyItemVisitor<T> v) { public <T> T accept(AutopsyItemVisitor<T> v) {
return v.visit(this); return v.visit(this);
} }
/**
* Stores all of the hashset results in a single class that is observable for the
* child nodes
*/
private class HashsetResults extends Observable {
// maps hashset name to list of artifacts for that set
private Map<String, Set<Long>> hashSetHitsMap = new LinkedHashMap<>();
HashsetResults() {
update();
}
Set<String> getSetNames() {
return hashSetHitsMap.keySet();
}
Set<Long> getArtifactIds(String hashSetName) {
return hashSetHitsMap.get(hashSetName);
}
final void update() {
hashSetHitsMap.clear();
ResultSet rs = null;
try {
int setNameId = ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
int artId = ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID();
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS
+ "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
+ "attribute_type_id=" + setNameId //NON-NLS
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
rs = skCase.runQuery(query);
while (rs.next()) {
String setName = rs.getString("value_text"); //NON-NLS
long artifactId = rs.getLong("artifact_id"); //NON-NLS
if (!hashSetHitsMap.containsKey(setName)) {
hashSetHitsMap.put(setName, new HashSet<Long>());
}
hashSetHitsMap.get(setName).add(artifactId);
}
} catch (SQLException ex) {
logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS
} finally {
if (rs != null) {
try {
skCase.closeRunQuery(rs);
} catch (SQLException ex) {
logger.log(Level.WARNING, "Error closing result set after getting hashset hits", ex); //NON-NLS
}
}
}
setChanged();
notifyObservers();
}
}
/** /**
* Node for the hash set hits * Top-level node for all hash sets
*/ */
public class HashsetHitsRootNode extends DisplayableItemNode { public class RootNode extends DisplayableItemNode {
public HashsetHitsRootNode() { public RootNode() {
super(Children.create(new HashsetHitsRootChildren(), true), Lookups.singleton(DISPLAY_NAME)); super(Children.create(new HashsetNameFactory(), true), Lookups.singleton(DISPLAY_NAME));
super.setName(HASHSET_HITS); super.setName(HASHSET_HITS);
super.setDisplayName(DISPLAY_NAME); super.setDisplayName(DISPLAY_NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); //NON-NLS
initArtifacts();
} }
@Override @Override
@ -137,27 +164,80 @@ public class HashsetHits implements AutopsyVisitableItem {
} }
} }
private class HashsetHitsRootChildren extends ChildFactory<String> { /**
* Creates child nodes for each hashset name
*/
private class HashsetNameFactory extends ChildFactory.Detachable<String> implements Observer {
/* This should probably be in the HashsetHits class, but the factory has nice methods
* for its startup and shutdown, so it seemed like a cleaner place to register the
* property change listener.
*/
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestEvent.DATA.toString())) {
if (((ModuleDataEvent) evt.getOldValue()).getArtifactType() == ARTIFACT_TYPE.TSK_HASHSET_HIT) {
hashsetResults.update();
}
}
else if (eventType.equals(IngestManager.IngestEvent.INGEST_JOB_COMPLETED.toString())
|| eventType.equals(IngestManager.IngestEvent.INGEST_JOB_CANCELLED.toString())) {
hashsetResults.update();
}
}
};
@Override @Override
protected boolean createKeys(List<String> list) { protected void addNotify() {
list.addAll(hashSetHitsMap.keySet()); IngestManager.addPropertyChangeListener(pcl);
hashsetResults.addObserver(this);
}
@Override
protected void removeNotify() {
IngestManager.removePropertyChangeListener(pcl);
hashsetResults.deleteObserver(this);
}
@Override
protected boolean createKeys(List<String> list) {
list.addAll(hashsetResults.getSetNames());
return true; return true;
} }
@Override @Override
protected Node createNodeForKey(String key) { protected Node createNodeForKey(String key) {
return new HashsetHitsSetNode(key, hashSetHitsMap.get(key)); return new HashsetNameNode(key);
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
} }
} }
public class HashsetHitsSetNode extends DisplayableItemNode { /**
* Node for a hash set name
public HashsetHitsSetNode(String name, Set<Long> children) { */
super(Children.create(new HashsetHitsSetChildren(children), true), Lookups.singleton(name)); public class HashsetNameNode extends DisplayableItemNode implements Observer {
super.setName(name); private String hashSetName;
super.setDisplayName(name + " (" + children.size() + ")"); public HashsetNameNode(String hashSetName) {
super(Children.create(new HitFactory(hashSetName), true), Lookups.singleton(hashSetName));
super.setName(hashSetName);
super.setDisplayName(hashSetName + " (0)");
this.hashSetName = hashSetName;
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); //NON-NLS
hashsetResults.addObserver(this);
}
/**
* Update the count in the display name
*/
private void updateName() {
super.setDisplayName(hashSetName + " (" + hashsetResults.getArtifactIds(hashSetName).size() + ")");
} }
@Override @Override
@ -186,33 +266,54 @@ public class HashsetHits implements AutopsyVisitableItem {
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this); return v.visit(this);
} }
@Override
public void update(Observable o, Object arg) {
updateName();
}
} }
private class HashsetHitsSetChildren extends ChildFactory<BlackboardArtifact> { /**
* Creates the nodes for the hits in a given set.
private Set<Long> children; */
private class HitFactory extends ChildFactory.Detachable<Long> implements Observer {
private HashsetHitsSetChildren(Set<Long> children) { private String hashsetName;
private HitFactory(String hashsetName) {
super(); super();
this.children = children; this.hashsetName = hashsetName;
}
@Override
protected void addNotify() {
hashsetResults.addObserver(this);
} }
@Override @Override
protected boolean createKeys(List<BlackboardArtifact> list) { protected void removeNotify() {
for (long l : children) { hashsetResults.deleteObserver(this);
try { }
//TODO: bulk artifact gettings
list.add(skCase.getBlackboardArtifact(l)); @Override
} catch (TskException ex) { protected boolean createKeys(List<Long> list) {
logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS list.addAll(hashsetResults.getArtifactIds(hashsetName));
}
}
return true; return true;
} }
@Override @Override
protected Node createNodeForKey(BlackboardArtifact artifact) { protected Node createNodeForKey(Long id) {
return new BlackboardArtifactNode(artifact); try {
BlackboardArtifact art = skCase.getBlackboardArtifact(id);
return new BlackboardArtifactNode(art);
} catch (TskException ex) {
logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
}
return null;
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
} }
} }
} }

View File

@ -106,10 +106,10 @@ public class InterestingHits implements AutopsyVisitableItem {
/** /**
* Node for the interesting items * Node for the interesting items
*/ */
public class InterestingHitsRootNode extends DisplayableItemNode { public class RootNode extends DisplayableItemNode {
public InterestingHitsRootNode() { public RootNode() {
super(Children.create(new InterestingHitsRootChildren(), true), Lookups.singleton(DISPLAY_NAME)); super(Children.create(new SetNameFactory(), true), Lookups.singleton(DISPLAY_NAME));
super.setName(INTERESTING_ITEMS); super.setName(INTERESTING_ITEMS);
super.setDisplayName(DISPLAY_NAME); super.setDisplayName(DISPLAY_NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS
@ -144,7 +144,7 @@ public class InterestingHits implements AutopsyVisitableItem {
} }
} }
private class InterestingHitsRootChildren extends ChildFactory<String> { private class SetNameFactory extends ChildFactory<String> {
@Override @Override
protected boolean createKeys(List<String> list) { protected boolean createKeys(List<String> list) {
@ -154,14 +154,14 @@ public class InterestingHits implements AutopsyVisitableItem {
@Override @Override
protected Node createNodeForKey(String key) { protected Node createNodeForKey(String key) {
return new InterestingHitsSetNode(key, interestingItemsMap.get(key)); return new SetNameNode(key, interestingItemsMap.get(key));
} }
} }
public class InterestingHitsSetNode extends DisplayableItemNode { public class SetNameNode extends DisplayableItemNode {
public InterestingHitsSetNode(String name, Set<Long> children) { public SetNameNode(String name, Set<Long> children) {
super(Children.create(new InterestingHitsSetChildren(children), true), Lookups.singleton(name)); super(Children.create(new HitFactory(children), true), Lookups.singleton(name));
super.setName(name); super.setName(name);
super.setDisplayName(name + " (" + children.size() + ")"); super.setDisplayName(name + " (" + children.size() + ")");
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/interesting_item.png"); //NON-NLS
@ -195,11 +195,11 @@ public class InterestingHits implements AutopsyVisitableItem {
} }
} }
private class InterestingHitsSetChildren extends ChildFactory<BlackboardArtifact> { private class HitFactory extends ChildFactory<BlackboardArtifact> {
private Set<Long> children; private Set<Long> children;
private InterestingHitsSetChildren(Set<Long> children) { private HitFactory(Set<Long> children) {
super(); super();
this.children = children; this.children = children;
} }

View File

@ -18,13 +18,16 @@
*/ */
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
@ -34,6 +37,8 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
@ -54,101 +59,123 @@ public class KeywordHits implements AutopsyVisitableItem {
.getMessage(KeywordHits.class, "KeywordHits.simpleLiteralSearch.text"); .getMessage(KeywordHits.class, "KeywordHits.simpleLiteralSearch.text");
public static final String SIMPLE_REGEX_SEARCH = NbBundle public static final String SIMPLE_REGEX_SEARCH = NbBundle
.getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text"); .getMessage(KeywordHits.class, "KeywordHits.singleRegexSearch.text");
// Map from String (list name) to Map from string (keyword) to set<long> (artifact ids) private KeywordResults keywordResults;
private Map<String, Map<String, Set<Long>>> topLevelMap;
private Map<String, Map<String, Set<Long>>> listsMap;
// Map from String (literal keyword) to set<long> (artifact ids)
private Map<String, Set<Long>> literalMap;
// Map from String (regex keyword) to set<long> (artifact ids);
private Map<String, Set<Long>> regexMap;
Map<Long, Map<Long, String>> artifacts;
public KeywordHits(SleuthkitCase skCase) { public KeywordHits(SleuthkitCase skCase) {
this.skCase = skCase; this.skCase = skCase;
artifacts = new LinkedHashMap<>(); keywordResults = new KeywordResults();
listsMap = new LinkedHashMap<>();
literalMap = new LinkedHashMap<>();
regexMap = new LinkedHashMap<>();
topLevelMap = new LinkedHashMap<>();
} }
private void initMaps() { private final class KeywordResults extends Observable {
topLevelMap.clear(); // Map from listName/Type to Map of keyword to set of artifact Ids
topLevelMap.put(SIMPLE_LITERAL_SEARCH, literalMap); private Map<String, Map<String, Set<Long>>> topLevelMap;
topLevelMap.put(SIMPLE_REGEX_SEARCH, regexMap);
listsMap.clear(); KeywordResults() {
regexMap.clear(); topLevelMap = new LinkedHashMap<>();
literalMap.clear(); update();
for (Map.Entry<Long, Map<Long, String>> art : artifacts.entrySet()) { }
long id = art.getKey();
Map<Long, String> attributes = art.getValue(); Set<String> getListNames() {
// I think we can use attributes.remove(...) here? return topLevelMap.keySet();
String listName = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID())); }
String word = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()));
String reg = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID())); Set<String> getKeywords(String listName) {
if (listName != null) { return topLevelMap.get(listName).keySet();
if (!listsMap.containsKey(listName)) { }
listsMap.put(listName, new LinkedHashMap<String, Set<Long>>());
} Set<Long> getArtifactIds(String listName, String keyword) {
if (!listsMap.get(listName).containsKey(word)) { return topLevelMap.get(listName).get(keyword);
listsMap.get(listName).put(word, new HashSet<Long>());
}
listsMap.get(listName).get(word).add(id);
} else if (reg != null) {
if (!regexMap.containsKey(reg)) {
regexMap.put(reg, new HashSet<Long>());
}
regexMap.get(reg).add(id);
} else {
if (!literalMap.containsKey(word)) {
literalMap.put(word, new HashSet<Long>());
}
literalMap.get(word).add(id);
}
topLevelMap.putAll(listsMap);
} }
}
@SuppressWarnings("deprecation") // populate maps based on artifactIds
private void initArtifacts() { void populateMaps(Map<Long, Map<Long, String>> artifactIds) {
artifacts.clear(); topLevelMap.clear();
ResultSet rs = null;
try { Map<String, Map<String, Set<Long>>> listsMap = new LinkedHashMap<>();
int setId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(); // Map from String (literal keyword) to set<long> (artifact ids)
int wordId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID(); Map<String, Set<Long>> literalMap = new LinkedHashMap<>();
int regexId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID(); // Map from String (regex keyword) to set<long> (artifact ids);
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(); Map<String, Set<Long>> regexMap = new LinkedHashMap<>();
String query = "SELECT blackboard_attributes.value_text,blackboard_attributes.artifact_id," //NON-NLS
+ "blackboard_attributes.attribute_type_id FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
+ "(blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id AND " //NON-NLS // top-level nodes
+ "blackboard_artifacts.artifact_type_id=" + artId //NON-NLS topLevelMap.put(SIMPLE_LITERAL_SEARCH, literalMap);
+ ") AND (attribute_type_id=" + setId + " OR " //NON-NLS topLevelMap.put(SIMPLE_REGEX_SEARCH, regexMap);
+ "attribute_type_id=" + wordId + " OR " //NON-NLS
+ "attribute_type_id=" + regexId + ")"; //NON-NLS for (Map.Entry<Long, Map<Long, String>> art : artifactIds.entrySet()) {
rs = skCase.runQuery(query); long id = art.getKey();
while (rs.next()) { Map<Long, String> attributes = art.getValue();
String value = rs.getString("value_text"); //NON-NLS
long artifactId = rs.getLong("artifact_id"); //NON-NLS // I think we can use attributes.remove(...) here?
long typeId = rs.getLong("attribute_type_id"); //NON-NLS String listName = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()));
if (!artifacts.containsKey(artifactId)) { String word = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()));
artifacts.put(artifactId, new LinkedHashMap<Long, String>()); String reg = attributes.get(Long.valueOf(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()));
if (listName != null) {
if (!listsMap.containsKey(listName)) {
listsMap.put(listName, new LinkedHashMap<String, Set<Long>>());
}
if (!listsMap.get(listName).containsKey(word)) {
listsMap.get(listName).put(word, new HashSet<Long>());
}
listsMap.get(listName).get(word).add(id);
} else if (reg != null) {
if (!regexMap.containsKey(reg)) {
regexMap.put(reg, new HashSet<Long>());
}
regexMap.get(reg).add(id);
} else {
if (!literalMap.containsKey(word)) {
literalMap.put(word, new HashSet<Long>());
}
literalMap.get(word).add(id);
} }
if (!value.equals("")) { topLevelMap.putAll(listsMap);
artifacts.get(artifactId).put(typeId, value);
}
} }
} catch (SQLException ex) { setChanged();
logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS notifyObservers();
} finally { }
if (rs != null) {
try { public void update() {
skCase.closeRunQuery(rs); Map<Long, Map<Long, String>> artifactIds = new LinkedHashMap<>();
} catch (SQLException ex) {
logger.log(Level.WARNING, "Error closing result set after getting keyword hits", ex); //NON-NLS ResultSet rs = null;
try {
int setId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
int wordId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID();
int regexId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID();
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID();
String query = "SELECT blackboard_attributes.value_text,blackboard_attributes.artifact_id," //NON-NLS
+ "blackboard_attributes.attribute_type_id FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS
+ "(blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id AND " //NON-NLS
+ "blackboard_artifacts.artifact_type_id=" + artId //NON-NLS
+ ") AND (attribute_type_id=" + setId + " OR " //NON-NLS
+ "attribute_type_id=" + wordId + " OR " //NON-NLS
+ "attribute_type_id=" + regexId + ")"; //NON-NLS
rs = skCase.runQuery(query);
while (rs.next()) {
String value = rs.getString("value_text"); //NON-NLS
long artifactId = rs.getLong("artifact_id"); //NON-NLS
long typeId = rs.getLong("attribute_type_id"); //NON-NLS
if (!artifactIds.containsKey(artifactId)) {
artifactIds.put(artifactId, new LinkedHashMap<Long, String>());
}
if (!value.equals("")) {
artifactIds.get(artifactId).put(typeId, value);
}
}
} catch (SQLException ex) {
logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS
} finally {
if (rs != null) {
try {
skCase.closeRunQuery(rs);
} catch (SQLException ex) {
logger.log(Level.WARNING, "Error closing result set after getting keyword hits", ex); //NON-NLS
}
} }
} }
populateMaps(artifactIds);
} }
} }
@ -157,15 +184,14 @@ public class KeywordHits implements AutopsyVisitableItem {
return v.visit(this); return v.visit(this);
} }
public class KeywordHitsRootNode extends DisplayableItemNode { // Created by CreateAutopsyNodeVisitor
public class RootNode extends DisplayableItemNode {
public KeywordHitsRootNode() { public RootNode() {
super(Children.create(new KeywordHitsRootChildren(), true), Lookups.singleton(KEYWORD_HITS)); super(Children.create(new ListFactory(), true), Lookups.singleton(KEYWORD_HITS));
super.setName(NAME); super.setName(NAME);
super.setDisplayName(KEYWORD_HITS); super.setDisplayName(KEYWORD_HITS);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
initArtifacts();
initMaps();
} }
@Override @Override
@ -196,36 +222,73 @@ public class KeywordHits implements AutopsyVisitableItem {
} }
} }
private class KeywordHitsRootChildren extends ChildFactory<String> { private class ListFactory extends ChildFactory.Detachable<String> implements Observer {
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestEvent.DATA.toString())) {
if (((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT) {
keywordResults.update();
}
}
else if (eventType.equals(IngestManager.IngestEvent.INGEST_JOB_COMPLETED.toString())
|| eventType.equals(IngestManager.IngestEvent.INGEST_JOB_CANCELLED.toString())) {
keywordResults.update();
}
}
};
@Override
protected void addNotify() {
IngestManager.addPropertyChangeListener(pcl);
keywordResults.addObserver(this);
}
@Override
protected void removeNotify() {
IngestManager.removePropertyChangeListener(pcl);
keywordResults.deleteObserver(this);
}
@Override @Override
protected boolean createKeys(List<String> list) { protected boolean createKeys(List<String> list) {
list.addAll(topLevelMap.keySet()); list.addAll(keywordResults.getListNames());
return true; return true;
} }
@Override @Override
protected Node createNodeForKey(String key) { protected Node createNodeForKey(String key) {
return new KeywordHitsListNode(key, topLevelMap.get(key)); return new ListNode(key);
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
} }
} }
public class KeywordHitsListNode extends DisplayableItemNode { public class ListNode extends DisplayableItemNode implements Observer {
private String listName;
private String name; public ListNode(String listName) {
private Map<String, Set<Long>> children; super(Children.create(new TermFactory(listName), true), Lookups.singleton(listName));
super.setName(listName);
public KeywordHitsListNode(String name, Map<String, Set<Long>> children) {
super(Children.create(new KeywordHitsListChildren(children), true), Lookups.singleton(name));
super.setName(name);
int totalDescendants = 0;
for (Set<Long> grandChildren : children.values()) {
totalDescendants += grandChildren.size();
}
super.setDisplayName(name + " (" + totalDescendants + ")");
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
this.name = name; this.listName = listName;
this.children = children; updateDisplayName();
keywordResults.addObserver(this);
}
private void updateDisplayName() {
int totalDescendants = 0;
for (String word : keywordResults.getKeywords(listName)) {
Set<Long> ids = keywordResults.getArtifactIds(listName, word);
totalDescendants += ids.size();
}
super.setDisplayName(listName + " (" + totalDescendants + ")");
} }
@Override @Override
@ -240,13 +303,13 @@ public class KeywordHits implements AutopsyVisitableItem {
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.name"), ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.name"),
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.displayName"), NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.displayName"),
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.desc"), NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.listName.desc"),
name)); listName));
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.numChildren.name"), ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.numChildren.name"),
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.numChildren.displayName"), NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.numChildren.displayName"),
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.numChildren.desc"), NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.numChildren.desc"),
children.size())); keywordResults.getKeywords(listName).size()));
return s; return s;
} }
@ -260,39 +323,71 @@ public class KeywordHits implements AutopsyVisitableItem {
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this); return v.visit(this);
} }
@Override
public void update(Observable o, Object arg) {
updateDisplayName();
}
} }
private class KeywordHitsListChildren extends ChildFactory<String> { private class TermFactory extends ChildFactory.Detachable<String> implements Observer {
private String setName;
private Map<String, Set<Long>> children;
private TermFactory(String setName) {
private KeywordHitsListChildren(Map<String, Set<Long>> children) {
super(); super();
this.children = children; this.setName = setName;
} }
@Override
protected void addNotify() {
keywordResults.addObserver(this);
}
@Override
protected void removeNotify() {
keywordResults.deleteObserver(this);
}
@Override @Override
protected boolean createKeys(List<String> list) { protected boolean createKeys(List<String> list) {
list.addAll(children.keySet()); list.addAll(keywordResults.getKeywords(setName));
return true; return true;
} }
@Override @Override
protected Node createNodeForKey(String key) { protected Node createNodeForKey(String key) {
return new KeywordHitsKeywordNode(key, children.get(key)); return new TermNode(setName, key);
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
} }
} }
public class KeywordHitsKeywordNode extends DisplayableItemNode { public class TermNode extends DisplayableItemNode implements Observer {
private Set<Long> children; private String setName;
private String keyword;
public KeywordHitsKeywordNode(String name, Set<Long> children) { public TermNode(String setName, String keyword) {
super(Children.create(new KeywordHitsKeywordChildren(children), true), Lookups.singleton(name)); super(Children.create(new HitsFactory (setName, keyword), true), Lookups.singleton(keyword));
super.setName(name); super.setName(keyword);
super.setDisplayName(name + " (" + children.size() + ")"); this.setName = setName;
this.keyword = keyword;
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/keyword_hits.png"); //NON-NLS
this.children = children; updateDisplayName();
keywordResults.addObserver(this);
}
private void updateDisplayName() {
super.setDisplayName(keyword + " (" + keywordResults.getArtifactIds(setName, keyword).size() + ")");
}
@Override
public void update(Observable o, Object arg) {
updateDisplayName();
} }
@Override @Override
@ -322,70 +417,83 @@ public class KeywordHits implements AutopsyVisitableItem {
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.name"), ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.name"),
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.displayName"), NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.displayName"),
NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.desc"), NbBundle.getMessage(this.getClass(), "KeywordHits.createSheet.filesWithHits.desc"),
children.size())); keywordResults.getArtifactIds(setName, keyword).size()));
return s; return s;
} }
} }
private class KeywordHitsKeywordChildren extends ChildFactory<BlackboardArtifact> { public class HitsFactory extends ChildFactory.Detachable<Long> implements Observer {
private String keyword;
private Set<Long> children; private String setName;
private KeywordHitsKeywordChildren(Set<Long> children) { public HitsFactory(String setName, String keyword) {
super(); super();
this.children = children; this.setName = setName;
this.keyword = keyword;
}
@Override
protected void addNotify() {
keywordResults.addObserver(this);
} }
@Override @Override
protected boolean createKeys(List<BlackboardArtifact> list) { protected void removeNotify() {
List<BlackboardArtifact> tempList = new ArrayList<>(); keywordResults.deleteObserver(this);
for (long l : children) { }
try {
//TODO: bulk artifact gettings @Override
tempList.add(skCase.getBlackboardArtifact(l)); protected boolean createKeys(List<Long> list) {
} catch (TskException ex) { list.addAll(keywordResults.getArtifactIds(setName, keyword));
logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
}
}
list.addAll(tempList);
return true; return true;
} }
@Override @Override
protected Node createNodeForKey(BlackboardArtifact artifact) { protected Node createNodeForKey(Long artifactId) {
BlackboardArtifactNode n = new BlackboardArtifactNode(artifact);
AbstractFile file;
try { try {
file = artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID()); BlackboardArtifact art = skCase.getBlackboardArtifact(artifactId);
} catch (TskCoreException ex) { BlackboardArtifactNode n = new BlackboardArtifactNode(art);
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren"); //NON-NLS AbstractFile file;
return n; try {
file = art.getSleuthkitCase().getAbstractFileById(art.getObjectID());
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren"); //NON-NLS
return n;
}
n.addNodeProperty(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.modTime.name"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.modTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.modTime.desc"),
ContentUtils.getStringTime(file.getMtime(), file)));
n.addNodeProperty(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.accessTime.name"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.accessTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.accessTime.desc"),
ContentUtils.getStringTime(file.getAtime(), file)));
n.addNodeProperty(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.chgTime.name"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.chgTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.chgTime.desc"),
ContentUtils.getStringTime(file.getCtime(), file)));
return n;
} catch (TskException ex) {
logger.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
} }
return null;
}
n.addNodeProperty(new NodeProperty<>( @Override
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.modTime.name"), public void update(Observable o, Object arg) {
NbBundle.getMessage(this.getClass(), refresh(true);
"KeywordHits.createNodeForKey.modTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.modTime.desc"),
ContentUtils.getStringTime(file.getMtime(), file)));
n.addNodeProperty(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.accessTime.name"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.accessTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.accessTime.desc"),
ContentUtils.getStringTime(file.getAtime(), file)));
n.addNodeProperty(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "KeywordHits.createNodeForKey.chgTime.name"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.chgTime.displayName"),
NbBundle.getMessage(this.getClass(),
"KeywordHits.createNodeForKey.chgTime.desc"),
ContentUtils.getStringTime(file.getCtime(), file)));
return n;
} }
} }
} }

View File

@ -65,6 +65,8 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
//TODO this will be removed, Children should be listening for interesting //TODO this will be removed, Children should be listening for interesting
//events from datamodel and calling refresh / refreshKey() themselves //events from datamodel and calling refresh / refreshKey() themselves
public void refreshKeys(BlackboardArtifact.ARTIFACT_TYPE... types) { public void refreshKeys(BlackboardArtifact.ARTIFACT_TYPE... types) {
// find the corresponding top-level node and refresh its children.
// should be more effeciently stored than a list.
for (Object o : contentKeys) { for (Object o : contentKeys) {
for (BlackboardArtifact.ARTIFACT_TYPE type : types) { for (BlackboardArtifact.ARTIFACT_TYPE type : types) {
switch (type) { switch (type) {
@ -91,8 +93,10 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
this.refreshKey(o); this.refreshKey(o);
break; break;
default: default:
if (o instanceof ExtractedContent) if (o instanceof ExtractedContent) {
this.refreshKey(o); this.refreshKey(o);
}
break; break;
} }
} }

View File

@ -27,6 +27,7 @@ import org.openide.nodes.Sheet;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode; import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
@ -52,22 +53,26 @@ public class TagNameNode extends DisplayableItemNode {
NbBundle.getMessage(TagNameNode.class, "TagNameNode.namePlusTags.text", tagName.getDisplayName()))); NbBundle.getMessage(TagNameNode.class, "TagNameNode.namePlusTags.text", tagName.getDisplayName())));
this.tagName = tagName; this.tagName = tagName;
long tagsCount = 0; setName(tagName.getDisplayName());
try { updateDisplayName();
tagsCount = Case.getCurrentCase().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
tagsCount += Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
} catch (TskCoreException ex) {
Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS
}
super.setName(tagName.getDisplayName());
super.setDisplayName(tagName.getDisplayName() + " (" + tagsCount + ")");
if (tagName.getDisplayName().equals(NbBundle.getMessage(this.getClass(), "TagNameNode.bookmark.text"))) { if (tagName.getDisplayName().equals(NbBundle.getMessage(this.getClass(), "TagNameNode.bookmark.text"))) {
setIconBaseWithExtension(BOOKMARK_TAG_ICON_PATH); setIconBaseWithExtension(BOOKMARK_TAG_ICON_PATH);
} else { } else {
setIconBaseWithExtension(ICON_PATH); setIconBaseWithExtension(ICON_PATH);
} }
} }
private void updateDisplayName() {
long tagsCount = 0;
try {
TagsManager tm = Case.getCurrentCase().getServices().getTagsManager();
tagsCount = tm.getContentTagsCountByTagName(tagName);
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName);
} catch (TskCoreException ex) {
Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS
}
setDisplayName(tagName.getDisplayName() + " (" + tagsCount + ")");
}
@Override @Override
protected Sheet createSheet() { protected Sheet createSheet() {

View File

@ -18,6 +18,8 @@
*/ */
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.nodes.ChildFactory; import org.openide.nodes.ChildFactory;
@ -28,6 +30,9 @@ import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -76,8 +81,36 @@ class TagsNode extends DisplayableItemNode {
return propertySheet; return propertySheet;
} }
private static class TagNameNodeFactory extends ChildFactory<TagName> { private static class TagNameNodeFactory extends ChildFactory.Detachable<TagName> {
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestEvent.DATA.toString())) {
if ((((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT) ||
((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) {
refresh(true);
}
}
else if (eventType.equals(IngestManager.IngestEvent.INGEST_JOB_COMPLETED.toString())
|| eventType.equals(IngestManager.IngestEvent.INGEST_JOB_CANCELLED.toString())) {
refresh(true);
}
}
};
@Override
protected void addNotify() {
IngestManager.addPropertyChangeListener(pcl);
}
@Override
protected void removeNotify() {
IngestManager.removePropertyChangeListener(pcl);
}
@Override @Override
protected boolean createKeys(List<TagName> keys) { protected boolean createKeys(List<TagName> keys) {
try { try {

View File

@ -33,14 +33,12 @@ import javax.swing.AbstractAction;
import javax.swing.Action; import javax.swing.Action;
import org.openide.explorer.ExplorerManager; import org.openide.explorer.ExplorerManager;
import org.openide.nodes.AbstractNode; import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.FilterNode; import org.openide.nodes.FilterNode;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType; import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType;
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
import org.sleuthkit.autopsy.datamodel.ArtifactTypeNode;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.ContentTagTypeNode; import org.sleuthkit.autopsy.datamodel.ContentTagTypeNode;
import org.sleuthkit.autopsy.datamodel.LocalFileNode; import org.sleuthkit.autopsy.datamodel.LocalFileNode;
@ -48,27 +46,27 @@ import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.De
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode; import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedAccountNode; import org.sleuthkit.autopsy.datamodel.EmailExtracted.AccountNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedFolderNode; import org.sleuthkit.autopsy.datamodel.EmailExtracted.FolderNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.EmailExtractedRootNode; import org.sleuthkit.autopsy.datamodel.EmailExtracted;
import org.sleuthkit.autopsy.datamodel.ExtractedContentNode; import org.sleuthkit.autopsy.datamodel.ExtractedContent.TypeNode;
import org.sleuthkit.autopsy.datamodel.ExtractedContent;
import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.datamodel.FileTypeNode; import org.sleuthkit.autopsy.datamodel.FileTypeNode;
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode; import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode;
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode; import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode;
import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsRootNode; import org.sleuthkit.autopsy.datamodel.HashsetHits;
import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode; import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetNameNode;
import org.sleuthkit.autopsy.datamodel.InterestingHits.InterestingHitsRootNode;
import org.sleuthkit.autopsy.datamodel.InterestingHits.InterestingHitsSetNode;
import org.sleuthkit.autopsy.datamodel.ImageNode; import org.sleuthkit.autopsy.datamodel.ImageNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsKeywordNode; import org.sleuthkit.autopsy.datamodel.InterestingHits;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsListNode; import org.sleuthkit.autopsy.datamodel.KeywordHits.TermNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode; import org.sleuthkit.autopsy.datamodel.KeywordHits.ListNode;
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode; import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
import org.sleuthkit.autopsy.datamodel.LayoutFileNode; import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode; import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode;
import org.sleuthkit.autopsy.datamodel.RecentFilesNode; import org.sleuthkit.autopsy.datamodel.RecentFilesNode;
import org.sleuthkit.autopsy.datamodel.FileTypesNode; import org.sleuthkit.autopsy.datamodel.FileTypesNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits;
import org.sleuthkit.autopsy.datamodel.TagNameNode; import org.sleuthkit.autopsy.datamodel.TagNameNode;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
@ -367,47 +365,47 @@ public class DataResultFilterNode extends FilterNode {
} }
@Override @Override
public AbstractAction visit(ExtractedContentNode ecn) { public AbstractAction visit(ExtractedContent.RootNode ecn) {
return openChild(ecn); return openChild(ecn);
} }
@Override @Override
public AbstractAction visit(KeywordHitsRootNode khrn) { public AbstractAction visit(KeywordHits.RootNode khrn) {
return openChild(khrn); return openChild(khrn);
} }
@Override @Override
public AbstractAction visit(HashsetHitsRootNode hhrn) { public AbstractAction visit(HashsetHits.RootNode hhrn) {
return openChild(hhrn); return openChild(hhrn);
} }
@Override @Override
public AbstractAction visit(HashsetHitsSetNode hhsn) { public AbstractAction visit(HashsetNameNode hhsn) {
return openChild(hhsn); return openChild(hhsn);
} }
@Override @Override
public AbstractAction visit(InterestingHitsRootNode iarn) { public AbstractAction visit(InterestingHits.RootNode iarn) {
return openChild(iarn); return openChild(iarn);
} }
@Override @Override
public AbstractAction visit(InterestingHitsSetNode iasn) { public AbstractAction visit(InterestingHits.SetNameNode iasn) {
return openChild(iasn); return openChild(iasn);
} }
@Override @Override
public AbstractAction visit(EmailExtractedRootNode eern) { public AbstractAction visit(EmailExtracted.RootNode eern) {
return openChild(eern); return openChild(eern);
} }
@Override @Override
public AbstractAction visit(EmailExtractedAccountNode eean) { public AbstractAction visit(AccountNode eean) {
return openChild(eean); return openChild(eean);
} }
@Override @Override
public AbstractAction visit(EmailExtractedFolderNode eefn) { public AbstractAction visit(FolderNode eefn) {
return openChild(eefn); return openChild(eefn);
} }
@ -443,7 +441,7 @@ public class DataResultFilterNode extends FilterNode {
} }
@Override @Override
public AbstractAction visit(ArtifactTypeNode atn) { public AbstractAction visit(TypeNode atn) {
return openChild(atn); return openChild(atn);
} }
@ -516,12 +514,12 @@ public class DataResultFilterNode extends FilterNode {
} }
@Override @Override
public AbstractAction visit(KeywordHitsListNode khsn) { public AbstractAction visit(ListNode khsn) {
return openChild(khsn); return openChild(khsn);
} }
@Override @Override
public AbstractAction visit(KeywordHitsKeywordNode khmln) { public AbstractAction visit(TermNode khmln) {
return openChild(khmln); return openChild(khmln);
} }

View File

@ -53,7 +53,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.ExtractedContentNode; import org.sleuthkit.autopsy.datamodel.ExtractedContent.RootNode;
import org.sleuthkit.autopsy.datamodel.DataSources; import org.sleuthkit.autopsy.datamodel.DataSources;
import org.sleuthkit.autopsy.datamodel.DataSourcesNode; import org.sleuthkit.autopsy.datamodel.DataSourcesNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits; import org.sleuthkit.autopsy.datamodel.KeywordHits;
@ -73,6 +73,7 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.datamodel.ExtractedContent;
/** /**
* Top component which displays something. * Top component which displays something.
@ -387,7 +388,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
Children resultsChilds = results.getChildren(); Children resultsChilds = results.getChildren();
tree.expandNode(resultsChilds.findChild(KeywordHits.NAME)); tree.expandNode(resultsChilds.findChild(KeywordHits.NAME));
tree.expandNode(resultsChilds.findChild(ExtractedContentNode.NAME)); tree.expandNode(resultsChilds.findChild(ExtractedContent.NAME));
Node views = childNodes.findChild(ViewsNode.NAME); Node views = childNodes.findChild(ViewsNode.NAME);
@ -587,7 +588,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
// change in node selection // change in node selection
else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) { else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) {
respondSelection((Node[]) oldValue, (Node[]) newValue); respondSelection((Node[]) oldValue, (Node[]) newValue);
} else if (changed.equals(IngestEvent.DATA.toString())) { }
else if (changed.equals(IngestEvent.DATA.toString())) {
final ModuleDataEvent event = (ModuleDataEvent) oldValue; final ModuleDataEvent event = (ModuleDataEvent) oldValue;
if (event.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO) { if (event.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO) {
return; return;
@ -595,7 +597,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
refreshTree(event.getArtifactType()); // @@@ refreshResultsTree(event.getArtifactType());
} }
}); });
} else if (changed.equals(IngestEvent.INGEST_JOB_COMPLETED.toString()) } else if (changed.equals(IngestEvent.INGEST_JOB_COMPLETED.toString())
@ -603,15 +605,15 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
refreshContentTree(); refreshDataSourceTree();
refreshTree(); refreshResultsTree();
} }
}); });
} else if (changed.equals(IngestEvent.CONTENT_CHANGED.toString())) { } else if (changed.equals(IngestEvent.CONTENT_CHANGED.toString())) {
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
refreshContentTree(); refreshDataSourceTree();
} }
}); });
} }
@ -768,7 +770,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
refreshContentTree(); refreshDataSourceTree();
} }
}); });
} }
@ -776,7 +778,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
/** /**
* Refreshes changed content nodes * Refreshes changed content nodes
*/ */
void refreshContentTree() { private void refreshDataSourceTree() {
Node selectedNode = getSelectedNode(); Node selectedNode = getSelectedNode();
final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext()); final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
@ -809,7 +811,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
* Refreshes the nodes in the tree to reflect updates in the database should * Refreshes the nodes in the tree to reflect updates in the database should
* be called in the gui thread * be called in the gui thread
*/ */
public void refreshTree(final BlackboardArtifact.ARTIFACT_TYPE... types) { public void refreshResultsTree(final BlackboardArtifact.ARTIFACT_TYPE... types) {
//save current selection //save current selection
Node selectedNode = getSelectedNode(); Node selectedNode = getSelectedNode();
final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext()); final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
@ -820,44 +822,40 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
Children dirChilds = em.getRootContext().getChildren(); Children dirChilds = em.getRootContext().getChildren();
Node results = dirChilds.findChild(ResultsNode.NAME); Node results = dirChilds.findChild(ResultsNode.NAME);
if (results == null) { if (results == null) {
logger.log(Level.SEVERE, "Cannot find Results filter node, won't refresh the bb tree"); //NON-NLS logger.log(Level.SEVERE, "Cannot find Results filter node, won't refresh the bb tree"); //NON-NLS
return; return;
} }
OriginalNode original = results.getLookup().lookup(OriginalNode.class); OriginalNode original = results.getLookup().lookup(OriginalNode.class);
ResultsNode resultsNode = (ResultsNode) original.getNode(); ResultsNode resultsNode = (ResultsNode) original.getNode();
RootContentChildren resultsNodeChilds = (RootContentChildren) resultsNode.getChildren(); RootContentChildren resultsNodeChilds = (RootContentChildren) resultsNode.getChildren();
resultsNodeChilds.refreshKeys(types); resultsNodeChilds.refreshKeys(types);
final TreeView tree = getTree(); final TreeView tree = getTree();
// @@@ tree.expandNode(results);
tree.expandNode(results);
Children resultsChilds = results.getChildren(); Children resultsChilds = results.getChildren();
if (resultsChilds == null) {
if (resultsChilds == null) //intermediate state check
{
return; return;
} }
Node childNode = resultsChilds.findChild(KeywordHits.NAME); Node childNode = resultsChilds.findChild(KeywordHits.NAME);
if (childNode == null) //intermediate state check if (childNode == null) {
{
return; return;
} }
tree.expandNode(childNode); // @@@tree.expandNode(childNode);
childNode = resultsChilds.findChild(ExtractedContentNode.NAME); childNode = resultsChilds.findChild(ExtractedContent.NAME);
if (childNode == null) //intermediate state check if (childNode == null) {
{
return; return;
} }
tree.expandNode(childNode); tree.expandNode(childNode);
//restores selection if it was under the Results node //restores selection if it was under the Results node
setSelectedNode(selectedPath, ResultsNode.NAME); //@@@ setSelectedNode(selectedPath, ResultsNode.NAME);
} }
/** /**
@ -983,7 +981,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS logger.log(Level.WARNING, "Error retrieving attributes", ex); //NON-NLS
} }
} else { } else {
Node extractedContent = resultsChilds.findChild(ExtractedContentNode.NAME); Node extractedContent = resultsChilds.findChild(ExtractedContent.NAME);
Children extractedChilds = extractedContent.getChildren(); Children extractedChilds = extractedContent.getChildren();
treeNode = extractedChilds.findChild(type.getLabel()); treeNode = extractedChilds.findChild(type.getLabel());
} }

View File

@ -1,5 +1,5 @@
#Updated by build script #Updated by build script
#Tue, 22 Apr 2014 16:06:14 -0400 #Sat, 03 May 2014 22:45:39 -0400
LBL_splash_window_title=Starting Autopsy LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=288 SPLASH_HEIGHT=288
SPLASH_WIDTH=538 SPLASH_WIDTH=538

View File

@ -1,5 +1,5 @@
#Updated by build script #Updated by build script
#Tue, 22 Apr 2014 16:06:14 -0400 #Sat, 03 May 2014 22:45:39 -0400
CTL_MainWindow_Title=Autopsy 3.1.0_Beta CTL_MainWindow_Title=Autopsy 3.1.0_Beta
CTL_MainWindow_Title_No_Project=Autopsy 3.1.0_Beta CTL_MainWindow_Title_No_Project=Autopsy 3.1.0_Beta