From d4c69e3c962a5a75da14260cb05a06a401680673 Mon Sep 17 00:00:00 2001 From: Devin148 Date: Fri, 28 Dec 2012 15:58:51 -0500 Subject: [PATCH 01/30] Add right click tagging and display tags in directory tree --- .../datamodel/AbstractContentChildren.java | 17 +- .../autopsy/datamodel/AutopsyItemVisitor.java | 6 + .../datamodel/DisplayableItemNodeVisitor.java | 14 + .../autopsy/datamodel/ResultsNode.java | 3 +- .../datamodel/RootContentChildren.java | 7 +- .../org/sleuthkit/autopsy/datamodel/Tags.java | 196 ++++++++++- .../autopsy/directorytree/BookmarkAction.java | 122 ------- .../autopsy/directorytree/Bundle.properties | 8 + .../directorytree/CreateTagDialog.form | 212 ++++++++++++ .../directorytree/CreateTagDialog.java | 319 ++++++++++++++++++ .../directorytree/DataResultFilterNode.java | 20 +- .../autopsy/directorytree/TagFileAction.java | 179 ++++++++++ .../directorytree/TagResultAction.java | 136 ++++++++ .../hashdatabase/KeyValueFileNode.java | 22 +- .../KeywordSearchFilterNode.java | 4 +- 15 files changed, 1115 insertions(+), 150 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/directorytree/BookmarkAction.java create mode 100644 Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.form create mode 100644 Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.java create mode 100644 Core/src/org/sleuthkit/autopsy/directorytree/TagFileAction.java create mode 100644 Core/src/org/sleuthkit/autopsy/directorytree/TagResultAction.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index 3f7de13f83..c4983506d8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -26,12 +26,12 @@ import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode; import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.File; import org.sleuthkit.datamodel.Image; -import org.sleuthkit.datamodel.VirtualDirectory; -import org.sleuthkit.datamodel.SleuthkitVisitableItem; -import org.sleuthkit.datamodel.SleuthkitItemVisitor; -import org.sleuthkit.datamodel.TskException; -import org.sleuthkit.datamodel.Volume; import org.sleuthkit.datamodel.LayoutFile; +import org.sleuthkit.datamodel.SleuthkitItemVisitor; +import org.sleuthkit.datamodel.SleuthkitVisitableItem; +import org.sleuthkit.datamodel.TskException; +import org.sleuthkit.datamodel.VirtualDirectory; +import org.sleuthkit.datamodel.Volume; /** * Abstract subclass for ContentChildren and RootContentChildren implementations @@ -137,11 +137,16 @@ abstract class AbstractContentChildren extends Keys { return ee.new EmailExtractedRootNode(); } - @Override + @Override public AbstractNode visit(Bookmarks bks) { return bks.new BookmarksRootNode(); } + @Override + public AbstractNode visit(Tags t) { + return t.new TagsRootNode(); + } + @Override public AbstractNode visit(Images i) { try { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java index ce365205a5..ff5e62c2b9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java @@ -34,6 +34,7 @@ public interface AutopsyItemVisitor { T visit(HashsetHits hh); T visit(EmailExtracted ee); T visit(Bookmarks bks); + T visit(Tags t); T visit(Images i); T visit(Views v); T visit(Results r); @@ -92,6 +93,11 @@ public interface AutopsyItemVisitor { return defaultVisit(bks); } + @Override + public T visit(Tags t) { + return defaultVisit(t); + } + @Override public T visit(Images i) { return defaultVisit(i); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 789c7094ab..c7aa1e3713 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -28,6 +28,8 @@ import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode; 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.datamodel.Tags.TagsNodeRoot; +import org.sleuthkit.autopsy.datamodel.Tags.TagsRootNode; /** * Visitor pattern for DisplayableItemNodes @@ -55,6 +57,8 @@ public interface DisplayableItemNodeVisitor { T visit(EmailExtractedFolderNode eefn); T visit(BookmarksRootNode bksrn); T visit(BookmarksNodeRoot bksrn); + T visit(TagsRootNode bksrn); + T visit(TagsNodeRoot bksrn); T visit(ViewsNode vn); T visit(ResultsNode rn); T visit(ImagesNode in); @@ -204,5 +208,15 @@ public interface DisplayableItemNodeVisitor { public T visit(BookmarksNodeRoot bksnr) { return defaultVisit(bksnr); } + + @Override + public T visit(TagsRootNode bksrn) { + return defaultVisit(bksrn); + } + + @Override + public T visit(TagsNodeRoot bksnr) { + return defaultVisit(bksnr); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java index 078e9aa621..5af390a335 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java @@ -36,7 +36,8 @@ public class ResultsNode extends DisplayableItemNode { new KeywordHits(sleuthkitCase), new HashsetHits(sleuthkitCase), new EmailExtracted(sleuthkitCase), - new Bookmarks(sleuthkitCase) //TODO move to the top of the tree + new Bookmarks(sleuthkitCase), //TODO move to the top of the tree + new Tags(sleuthkitCase) //TODO move to the top of the tree )), Lookups.singleton(NAME)); setName(NAME); setDisplayName(NAME); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index 405db21970..90e4065df8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel; import java.util.Collection; import java.util.Collections; -import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; /** @@ -73,12 +72,16 @@ public class RootContentChildren extends AbstractContentChildren { case TSK_TAG_FILE: if (o instanceof Bookmarks) this.refreshKey(o); + if (o instanceof Tags) + this.refreshKey(o); break; //TODO check case TSK_TAG_ARTIFACT: if (o instanceof Bookmarks) this.refreshKey(o); + if (o instanceof Tags) + this.refreshKey(o); break; default: if (o instanceof ExtractedContent) @@ -95,6 +98,8 @@ public class RootContentChildren extends AbstractContentChildren { this.refreshKey(o); else if (o instanceof Bookmarks) this.refreshKey(o); + else if (o instanceof Tags) + this.refreshKey(o); else if (o instanceof ExtractedContent) this.refreshKey(o); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 5ebbd2585a..78f8ce1a08 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012 Basis Technology Corp. + * Copyright 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,8 +21,17 @@ package org.sleuthkit.autopsy.datamodel; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Random; 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.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; @@ -32,15 +41,194 @@ import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; -public class Tags { +public class Tags implements AutopsyVisitableItem { private static final Logger logger = Logger.getLogger(Tags.class.getName()); + private SleuthkitCase skCase; + public static final String NAME = "Tags"; + private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png"; + private Map> tags = new HashMap>(); + + Tags(SleuthkitCase skCase) { + this.skCase = skCase; + } + + @Override + public T accept(AutopsyItemVisitor v) { + return v.visit(this); + } + + /** + * Root of all Tag nodes. This node is shown directly under Results + * in the directory tree. + */ + public class TagsRootNode extends DisplayableItemNode { + + public TagsRootNode() { + super(Children.create(new Tags.TagsRootChildren(), true), Lookups.singleton(NAME)); + super.setName(NAME); + super.setDisplayName(NAME); + this.setIconBaseWithExtension(TAG_ICON_PATH); + initData(); + } + + private void initData() { + try { + // Get all file and artifact tags + tags = new HashMap>(); + List tagArtifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); + tagArtifacts.addAll(skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)); + + for (BlackboardArtifact artifact : tagArtifacts) { + for (BlackboardAttribute attribute : artifact.getAttributes()) { + if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) { + String tagName = attribute.getValueString(); + if (tagName.equals(Bookmarks.BOOKMARK_TAG_NAME)) { + break; // Don't add bookmarks + } else if (tags.containsKey(tagName)) { + List list = new ArrayList(tags.get(tagName)); + list.add(artifact); + tags.put(tagName, list); + } else { + tags.put(tagName, Arrays.asList(artifact)); + } + break; + } + } + } + + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Count not initialize bookmark nodes, ", ex); + } + } + + @Override + public T accept(DisplayableItemNodeVisitor 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("Name", + "Name", + "no description", + getName())); + + return s; + } + + @Override + public DisplayableItemNode.TYPE getDisplayableItemNodeType() { + return DisplayableItemNode.TYPE.ARTIFACT; + } + } + + /** + * Child factory to add all the Tag artifacts to a TagsRootNode + * with the tag name. + */ + private class TagsRootChildren extends ChildFactory { + + @Override + protected boolean createKeys(List list) { + for (String tagName : tags.keySet()) { + list.add(tagName); + } + + return true; + } + + @Override + protected Node createNodeForKey(String key) { + return new Tags.TagsNodeRoot(key, tags.get(key)); + } + } + + /** + * Node for each unique tag name. Shown directly under Results > Tags. + */ + public class TagsNodeRoot extends DisplayableItemNode { + + public TagsNodeRoot(String tagName, List artifacts) { + super(Children.create(new Tags.TagsChildrenNode(artifacts), true), Lookups.singleton(tagName)); + + super.setName(tagName); + super.setDisplayName(tagName + " (" + tags.get(tagName).size() + ")"); + + this.setIconBaseWithExtension(TAG_ICON_PATH); + } + + @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("Name", + "Name", + "no description", + getName())); + + return s; + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + @Override + public DisplayableItemNode.TYPE getDisplayableItemNodeType() { + return DisplayableItemNode.TYPE.ARTIFACT; + } + + @Override + public boolean isLeafTypeNode() { + return true; + } + } + + /** + * Node representing an individual Tag artifact. For each TagsNodeRoot + * under Results > Tags, this is one of the nodes listed in the result viewer. + */ + private class TagsChildrenNode extends ChildFactory { + + private List artifacts; + + private TagsChildrenNode(List artifacts) { + super(); + this.artifacts = artifacts; + } + + @Override + protected boolean createKeys(List list) { + list.addAll(artifacts); + return true; + } + + @Override + protected Node createNodeForKey(BlackboardArtifact artifact) { + return new BlackboardArtifactNode(artifact, TAG_ICON_PATH); + } + } + /** * Create a tag for a file with TSK_TAG_NAME as tagName. * @param file to create tag for * @param tagName TSK_TAG_NAME */ - static void createTag(AbstractFile file, String tagName, String comment) { + public static void createTag(AbstractFile file, String tagName, String comment) { try { final BlackboardArtifact bookArt = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); List attrs = new ArrayList(); @@ -63,7 +251,7 @@ public class Tags { * @param artifact to create tag for * @param tagName TSK_TAG_NAME */ - static void createTag(BlackboardArtifact artifact, String tagName, String comment) { + public static void createTag(BlackboardArtifact artifact, String tagName, String comment) { try { Case currentCase = Case.getCurrentCase(); SleuthkitCase skCase = currentCase.getSleuthkitCase(); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/BookmarkAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/BookmarkAction.java deleted file mode 100644 index d350733944..0000000000 --- a/Core/src/org/sleuthkit/autopsy/directorytree/BookmarkAction.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.directorytree; - -import java.awt.event.ActionEvent; -import javax.swing.AbstractAction; -import javax.swing.JOptionPane; -import org.openide.nodes.Node; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.autopsy.datamodel.Tags; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentVisitor; -import org.sleuthkit.datamodel.Directory; - -/** - * Action on a file or artifact that bookmarks a file and/or artifact - * and reloads the bookmark view. - * Supports bookmarking of a fs file, directory and layout file and layout - * directory (virtual files/dirs for unalloc content) - * - * TODO add use enters description and hierarchy (TSK_TAG_NAME with slashes) - */ -public class BookmarkAction extends AbstractAction { - - private static final Logger logger = Logger.getLogger(BookmarkAction.class.getName()); - //content to bookmark - private AbstractFile bookmarkFile; - private BlackboardArtifact bookmarkArtifact; - private final InitializeBookmarkFileV initializer = new InitializeBookmarkFileV(); - - public BookmarkAction(String title, Node contentNode) { - super(title); - Content content = contentNode.getLookup().lookup(Content.class); - - bookmarkArtifact = null; - bookmarkFile = content.accept(initializer); - this.setEnabled(bookmarkFile != null); - } - - public BookmarkAction(String title, Content content) { - super(title); - - bookmarkArtifact = null; - bookmarkFile = content.accept(initializer); - this.setEnabled(bookmarkFile != null); - } - - public BookmarkAction(String title, BlackboardArtifact art) { - super(title); - - bookmarkArtifact = art; - bookmarkFile = null; - this.setEnabled(bookmarkArtifact != null); - } - - /** - * Returns the FsContent if it is supported, otherwise null - */ - private static class InitializeBookmarkFileV extends ContentVisitor.Default { - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.File f) { - return f; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.LayoutFile lf) { - return lf; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.VirtualDirectory ld) { - return ld; - } - - @Override - public AbstractFile visit(Directory dir) { - return ContentUtils.isDotDirectory(dir) ? null : dir; - } - - @Override - protected AbstractFile defaultVisit(Content cntnt) { - return null; - } - } - - @Override - public void actionPerformed(ActionEvent e) { - String comment = JOptionPane.showInputDialog(null, "Please enter a comment for the bookmark:", "Bookmark Comment", JOptionPane.PLAIN_MESSAGE); - if(comment == null || comment.isEmpty()) { - comment = "No Comment"; - } - if(bookmarkArtifact != null) { - Tags.createBookmark(bookmarkArtifact, comment); - } else if(bookmarkFile != null) { - Tags.createBookmark(bookmarkFile, comment); - } - - DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance(); - viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); - viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); - } -} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties index 12abeb5237..3caf53f432 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties @@ -47,3 +47,11 @@ ImageDetailsPanel.imgSectorSizeLabel.text=Sector Size: ImageDetailsPanel.imgSectorSizeValue.text=... DirectoryTreeTopComponent.backButton.text= DirectoryTreeTopComponent.forwardButton.text= +CreateTagDialog.cancelButton.text=Cancel +CreateTagDialog.okButton.text=OK +CreateTagDialog.tagNameField.text= +CreateTagDialog.tagCommentField.text= +CreateTagDialog.tagNameLabel.text=Tag Name: +CreateTagDialog.tagCommentLabel.text=Tag Comment: +CreateTagDialog.preexistingLabel.text=Pre-exising Tags: +CreateTagDialog.newTagPanel.border.title=New Tag diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.form b/Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.form new file mode 100644 index 0000000000..3373f1887d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.form @@ -0,0 +1,212 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.java b/Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.java new file mode 100644 index 0000000000..3b39445f88 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.java @@ -0,0 +1,319 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.directorytree; + +import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.event.KeyEvent; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.swing.JOptionPane; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.table.AbstractTableModel; +import org.sleuthkit.autopsy.datamodel.Tags; + +public class CreateTagDialog extends javax.swing.JDialog { + private Map tagMap = null; + TagsTableModel tagsTableModel; + TagSelectionListener tagSelectionListener; + + /** + * Creates new form CreateTagDialog + */ + public CreateTagDialog(java.awt.Frame parent, boolean modal) { + super(parent, modal); + initComponents(); + + tagsTableModel = new TagsTableModel(); + tagSelectionListener = new TagSelectionListener(); + tagsTable.setModel(tagsTableModel); + tagsTable.getSelectionModel().addListSelectionListener(tagSelectionListener); + tagsTable.setTableHeader(null); + tagsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + tagsTable.setRowHeight(tagsTable.getRowHeight() + 5); + } + + public Map display() { + this.setTitle("Create a new tag"); + + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); + // set the popUp window / JFrame + int w = this.getSize().width; + int h = this.getSize().height; + + // set the location of the popUp Window on the center of the screen + setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); + this.setVisible(true); + + return this.tagMap; + } + + private boolean containsIllegalCharacters(String content) { + if ((content.contains("\\") || content.contains(":") || content.contains("*") + || content.contains("?") || content.contains("\"") || content.contains("<") + || content.contains(">") || content.contains("|"))) { + return true; + } + return false; + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + cancelButton = new javax.swing.JButton(); + okButton = new javax.swing.JButton(); + jScrollPane1 = new javax.swing.JScrollPane(); + tagsTable = new javax.swing.JTable(); + preexistingLabel = new javax.swing.JLabel(); + newTagPanel = new javax.swing.JPanel(); + tagCommentField = new javax.swing.JTextField(); + tagNameLabel = new javax.swing.JLabel(); + tagCommentLabel = new javax.swing.JLabel(); + tagNameField = new javax.swing.JTextField(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + addKeyListener(new java.awt.event.KeyAdapter() { + public void keyReleased(java.awt.event.KeyEvent evt) { + formKeyReleased(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.cancelButton.text")); // NOI18N + cancelButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cancelButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.okButton.text")); // NOI18N + okButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okButtonActionPerformed(evt); + } + }); + + jScrollPane1.setBackground(new java.awt.Color(255, 255, 255)); + + tagsTable.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + + }, + new String [] { + + } + )); + tagsTable.setShowHorizontalLines(false); + tagsTable.setShowVerticalLines(false); + tagsTable.setTableHeader(null); + jScrollPane1.setViewportView(tagsTable); + + org.openide.awt.Mnemonics.setLocalizedText(preexistingLabel, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.preexistingLabel.text")); // NOI18N + + newTagPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.newTagPanel.border.title"))); // NOI18N + + tagCommentField.setText(org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.tagCommentField.text")); // NOI18N + tagCommentField.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyReleased(java.awt.event.KeyEvent evt) { + tagCommentFieldKeyReleased(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(tagNameLabel, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.tagNameLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(tagCommentLabel, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.tagCommentLabel.text")); // NOI18N + + tagNameField.setText(org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.tagNameField.text")); // NOI18N + tagNameField.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyReleased(java.awt.event.KeyEvent evt) { + tagNameFieldKeyReleased(evt); + } + }); + + javax.swing.GroupLayout newTagPanelLayout = new javax.swing.GroupLayout(newTagPanel); + newTagPanel.setLayout(newTagPanelLayout); + newTagPanelLayout.setHorizontalGroup( + newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(newTagPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(tagCommentLabel) + .addComponent(tagNameLabel)) + .addGap(18, 18, 18) + .addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(tagNameField) + .addComponent(tagCommentField)) + .addContainerGap()) + ); + newTagPanelLayout.setVerticalGroup( + newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(newTagPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(tagNameLabel) + .addComponent(tagNameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(tagCommentLabel) + .addComponent(tagCommentField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(138, Short.MAX_VALUE)) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 198, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(preexistingLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(0, 233, Short.MAX_VALUE) + .addComponent(okButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(cancelButton)) + .addComponent(newTagPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(preexistingLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addComponent(newTagPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cancelButton) + .addComponent(okButton)) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed + this.tagMap = null; + this.dispose(); + }//GEN-LAST:event_cancelButtonActionPerformed + + private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed + String tagName = tagNameField.getText(); + String tagComment = tagCommentField.getText(); + if (tagName.isEmpty()) { + JOptionPane.showMessageDialog(null, "Must supply a tag name to continue.", "Tag Name", JOptionPane.ERROR_MESSAGE); + } else if (containsIllegalCharacters(tagName)) { + JOptionPane.showMessageDialog(null, "The tag name contains illegal characters.\nCannot contain any of the following symbols: \\ : * ? \" < > |", + "Illegal Characters", JOptionPane.ERROR_MESSAGE); + } else { + this.tagMap = new HashMap(); + tagMap.put("Name", tagName); + tagMap.put("Comment", tagComment.isEmpty() ? "No Comment" : tagComment); + this.dispose(); + } + }//GEN-LAST:event_okButtonActionPerformed + + private void formKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKeyReleased + if (evt.getKeyCode() == KeyEvent.VK_ENTER) { + okButtonActionPerformed(null); + } + }//GEN-LAST:event_formKeyReleased + + private void tagNameFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_tagNameFieldKeyReleased + if (evt.getKeyCode() == KeyEvent.VK_ENTER) { + okButtonActionPerformed(null); + } + }//GEN-LAST:event_tagNameFieldKeyReleased + + private void tagCommentFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_tagCommentFieldKeyReleased + if (evt.getKeyCode() == KeyEvent.VK_ENTER) { + okButtonActionPerformed(null); + } + }//GEN-LAST:event_tagCommentFieldKeyReleased + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton cancelButton; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JPanel newTagPanel; + private javax.swing.JButton okButton; + private javax.swing.JLabel preexistingLabel; + private javax.swing.JTextField tagCommentField; + private javax.swing.JLabel tagCommentLabel; + private javax.swing.JTextField tagNameField; + private javax.swing.JLabel tagNameLabel; + private javax.swing.JTable tagsTable; + // End of variables declaration//GEN-END:variables + + private class TagsTableModel extends AbstractTableModel { + List tagNames; + + TagsTableModel() { + tagNames = Tags.getTagNames(); + } + + @Override + public int getRowCount() { + return tagNames.size(); + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + @Override + public int getColumnCount() { + return 1; + } + + @Override + public String getValueAt(int rowIndex, int columnIndex) { + return tagNames.get(rowIndex); + } + + } + + private class TagSelectionListener implements ListSelectionListener { + + @Override + public void valueChanged(ListSelectionEvent e) { + Object row = tagsTable.getValueAt(tagsTable.getSelectedRow(), 0); + if (row != null) { + String tagName = row.toString(); + tagNameField.setText(tagName); + } + } + + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index f109926968..58cebeed40 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -174,7 +174,7 @@ public class DataResultFilterNode extends FilterNode { actions.add(null); // creates a menu separator actions.add(new ExtractAction("Extract Directory", dir)); actions.add(null); // creates a menu separator - actions.add(new BookmarkAction("Bookmark Directory", dir)); + actions.add(new TagFileAction(dir)); return actions; } @@ -187,7 +187,7 @@ public class DataResultFilterNode extends FilterNode { actions.add(null); // creates a menu separator actions.add(new ExtractAction("Extract File", lf)); actions.add(null); // creates a menu separator - actions.add(new BookmarkAction("Bookmark File", lf)); + actions.add(new TagFileAction(lf)); return actions; } @@ -195,7 +195,7 @@ public class DataResultFilterNode extends FilterNode { public List visit(VirtualDirectoryNode ld) { List actions = new ArrayList(); - actions.add(new BookmarkAction("Bookmark Directory", ld)); + actions.add(new TagFileAction(ld)); return actions; } @@ -212,7 +212,7 @@ public class DataResultFilterNode extends FilterNode { actions.add(new ExtractAction("Extract File", f)); actions.add(new HashSearchAction("Search for files with the same MD5 hash", f)); actions.add(null); // creates a menu separator - actions.add(new BookmarkAction("Bookmark File", f)); + actions.add(new TagFileAction(f)); return actions; } @@ -246,8 +246,8 @@ public class DataResultFilterNode extends FilterNode { //add file bookmark if itself is not a file bookmark if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()) { actions.add(null); // creates a menu separator - actions.add(new BookmarkAction("Bookmark File", f)); - actions.add(new BookmarkAction("Bookmark Result", ba)); + actions.add(new TagFileAction(f)); + actions.add(new TagResultAction(ba)); } } if (( d = ban.getLookup().lookup(Directory.class)) != null) { @@ -260,8 +260,8 @@ public class DataResultFilterNode extends FilterNode { //add file bookmark if itself is not a file bookmark if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()) { actions.add(null); // creates a menu separator - actions.add(new BookmarkAction("Bookmark Directory", d)); - actions.add(new BookmarkAction("Bookmark Result Directory", ba)); + actions.add(new TagFileAction( d)); + actions.add(new TagResultAction(ba)); } } else if ( ( lf = ban.getLookup().lookup(LayoutFile.class)) != null) { @@ -274,8 +274,8 @@ public class DataResultFilterNode extends FilterNode { //add file bookmark if itself is not a file bookmark if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()) { actions.add(null); // creates a menu separator - actions.add(new BookmarkAction("Bookmark File", lf)); - actions.add(new BookmarkAction("Bookmark Result", ba)); + actions.add(new TagFileAction(lf)); + actions.add(new TagResultAction(ba)); } } //if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagFileAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagFileAction.java new file mode 100644 index 0000000000..652f12a6cf --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagFileAction.java @@ -0,0 +1,179 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.directorytree; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; +import java.util.Map; +import javax.swing.AbstractAction; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import org.openide.nodes.Node; +import org.openide.util.actions.Presenter; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.Bookmarks; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.autopsy.datamodel.Tags; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentVisitor; +import org.sleuthkit.datamodel.Directory; + +/** + * Action on a file or artifact that bookmarks a file and/or artifact + * and reloads the bookmark view. + * Supports bookmarking of a fs file, directory and layout file and layout + * directory (virtual files/dirs for unalloc content) + * + * TODO add use enters description and hierarchy (TSK_TAG_NAME with slashes) + */ +public class TagFileAction extends AbstractAction implements Presenter.Popup { + + private static final Logger logger = Logger.getLogger(TagFileAction.class.getName()); + //content to bookmark + private AbstractFile tagFile; + private final InitializeBookmarkFileV initializer = new InitializeBookmarkFileV(); + + public TagFileAction(Node contentNode) { + Content content = contentNode.getLookup().lookup(Content.class); + tagFile = content.accept(initializer); + } + + public TagFileAction(Content content) { + tagFile = content.accept(initializer); + } + + private String getComment() { + String comment = JOptionPane.showInputDialog(null, + "Please enter a comment for the tag:", + "Tag Comment", + JOptionPane.PLAIN_MESSAGE); + if(comment == null || comment.isEmpty()) { + comment = "No Comment"; + } + return comment; + } + + private void refreshDirectoryTree() { + DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance(); + viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); + viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); + } + + @Override + public JMenuItem getPopupPresenter() { + JMenu result = new JMenu("Tag File"); + + JMenuItem contentItem = new JMenuItem("Bookmark File"); + contentItem.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + Tags.createBookmark(tagFile, getComment()); + refreshDirectoryTree(); + } + + }); + result.add(contentItem); + result.addSeparator(); + + JMenuItem newTagItem = new JMenuItem("Create a new tag"); + newTagItem.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + Map tagMap = new CreateTagDialog(new JFrame(), true).display(); + if (tagMap != null) { + Tags.createTag(tagFile, tagMap.get("Name"), tagMap.get("Comment")); + refreshDirectoryTree(); + } + } + + }); + result.add(newTagItem); + result.addSeparator(); + + List tagNames = Tags.getTagNames(); + if (tagNames.isEmpty()) { + JMenuItem empty = new JMenuItem("No tags"); + empty.setEnabled(false); + result.add(empty); + } else { + for (final String tagName : tagNames) { + if (tagName.equals(Bookmarks.BOOKMARK_TAG_NAME)) { + continue; + } + JMenuItem tagItem = new JMenuItem(tagName); + tagItem.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + Tags.createTag(tagFile, tagName, getComment()); + refreshDirectoryTree(); + } + + }); + result.add(tagItem); + } + } + + return result; + } + + /** + * Returns the FsContent if it is supported, otherwise null + */ + private static class InitializeBookmarkFileV extends ContentVisitor.Default { + + @Override + public AbstractFile visit(org.sleuthkit.datamodel.File f) { + return f; + } + + @Override + public AbstractFile visit(org.sleuthkit.datamodel.LayoutFile lf) { + return lf; + } + + @Override + public AbstractFile visit(org.sleuthkit.datamodel.VirtualDirectory ld) { + return ld; + } + + @Override + public AbstractFile visit(Directory dir) { + return ContentUtils.isDotDirectory(dir) ? null : dir; + } + + @Override + protected AbstractFile defaultVisit(Content cntnt) { + return null; + } + } + + @Override + public void actionPerformed(ActionEvent e) { + // Do nothing - this action should never be performed + // Submenu actions are invoked instead + } +} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagResultAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagResultAction.java new file mode 100644 index 0000000000..06ddd4634b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagResultAction.java @@ -0,0 +1,136 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.directorytree; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; +import java.util.Map; +import javax.swing.AbstractAction; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import org.openide.util.actions.Presenter; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.Bookmarks; +import org.sleuthkit.autopsy.datamodel.Tags; +import org.sleuthkit.datamodel.BlackboardArtifact; + +/** + * Action on a file or artifact that bookmarks a file and/or artifact + * and reloads the bookmark view. + * Supports bookmarking of a fs file, directory and layout file and layout + * directory (virtual files/dirs for unalloc content) + * + * TODO add use enters description and hierarchy (TSK_TAG_NAME with slashes) + */ +public class TagResultAction extends AbstractAction implements Presenter.Popup { + + private static final Logger logger = Logger.getLogger(TagFileAction.class.getName()); + //content to bookmark + private BlackboardArtifact tagArtifact; + + public TagResultAction(BlackboardArtifact artifact) { + tagArtifact = artifact; + } + + private String getComment() { + String comment = JOptionPane.showInputDialog(null, + "Please enter a comment for the tag:", + "Tag Comment", + JOptionPane.PLAIN_MESSAGE); + if(comment == null || comment.isEmpty()) { + comment = "No Comment"; + } + return comment; + } + + private void refreshDirectoryTree() { + DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance(); + viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); + viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); + } + + @Override + public JMenuItem getPopupPresenter() { + JMenu result = new JMenu("Tag Result"); + + JMenuItem contentItem = new JMenuItem("Bookmark Result"); + contentItem.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + Tags.createBookmark(tagArtifact, getComment()); + refreshDirectoryTree(); + } + + }); + result.add(contentItem); + result.addSeparator(); + + JMenuItem newTagItem = new JMenuItem("Create a new tag"); + newTagItem.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + Map tagMap = new CreateTagDialog(new JFrame(), true).display(); + if (tagMap != null) { + Tags.createTag(tagArtifact, tagMap.get("Name"), tagMap.get("Comment")); + refreshDirectoryTree(); + } + } + + }); + result.add(newTagItem); + result.addSeparator(); + + List tagNames = Tags.getTagNames(); + if (tagNames.isEmpty()) { + JMenuItem empty = new JMenuItem("No tags"); + empty.setEnabled(false); + result.add(empty); + } else { + for (final String tagName : Tags.getTagNames()) { + if (tagName.equals(Bookmarks.BOOKMARK_TAG_NAME)) { + continue; + } + JMenuItem tagItem = new JMenuItem(tagName); + tagItem.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + Tags.createTag(tagArtifact, tagName, getComment()); + refreshDirectoryTree(); + } + + }); + result.add(tagItem); + } + } + + return result; + } + + @Override + public void actionPerformed(ActionEvent e) { + // Do nothing - this action should never be performed + // Submenu actions are invoked instead + } +} \ No newline at end of file diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/KeyValueFileNode.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/KeyValueFileNode.java index 25afe142a9..bc7d3e84c1 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/KeyValueFileNode.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/KeyValueFileNode.java @@ -1,6 +1,20 @@ /* - * To change this template, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.hashdatabase; @@ -13,7 +27,7 @@ import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.datamodel.DirectoryNode; import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.datamodel.KeyValueNode; -import org.sleuthkit.autopsy.directorytree.BookmarkAction; +import org.sleuthkit.autopsy.directorytree.TagFileAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -75,7 +89,7 @@ public class KeyValueFileNode extends KeyValueNode { actions.add(new ExtractAction("Extract File", new FileNode(f))); actions.add(new HashSearchAction("Search for files with the same MD5 hash", new FileNode(f))); actions.add(null); // creates a menu separator - actions.add(new BookmarkAction("Bookmark File", new FileNode(f))); + actions.add(new TagFileAction(new FileNode(f))); return actions; } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index 977bab1ed6..deb4f9f706 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -28,7 +28,7 @@ import org.openide.nodes.PropertySupport; import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ProxyLookup; -import org.sleuthkit.autopsy.directorytree.BookmarkAction; +import org.sleuthkit.autopsy.directorytree.TagFileAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -144,7 +144,7 @@ class KeywordSearchFilterNode extends FilterNode { actions.add(new ExtractAction("Extract File", getOriginal())); actions.add(new HashSearchAction("Search for files with the same MD5 hash", getOriginal())); actions.add(null); // creates a menu separator - actions.add(new BookmarkAction("Bookmark File", getOriginal())); + actions.add(new TagFileAction(getOriginal())); return actions; } From af123407d7b0ce88dce203097cf309b04ec0ddd9 Mon Sep 17 00:00:00 2001 From: Devin148 Date: Fri, 28 Dec 2012 16:05:57 -0500 Subject: [PATCH 02/30] Fix label spelling --- Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties index 3caf53f432..3b2ea33bb4 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties @@ -53,5 +53,5 @@ CreateTagDialog.tagNameField.text= CreateTagDialog.tagCommentField.text= CreateTagDialog.tagNameLabel.text=Tag Name: CreateTagDialog.tagCommentLabel.text=Tag Comment: -CreateTagDialog.preexistingLabel.text=Pre-exising Tags: +CreateTagDialog.preexistingLabel.text=Pre-existing Tags: CreateTagDialog.newTagPanel.border.title=New Tag From 0cb089eea33375435f7e1d176a49d55404b94244 Mon Sep 17 00:00:00 2001 From: adam-m Date: Fri, 4 Jan 2013 11:02:53 -0500 Subject: [PATCH 03/30] better progress updates in between keywords, lifted limit on terms query --- .../KeywordSearchIngestModule.java | 18 ++++++++++++------ .../keywordsearch/TermComponentQuery.java | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java index 7482a203c0..0a8ac2c830 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java @@ -888,13 +888,16 @@ public final class KeywordSearchIngestModule implements IngestModuleAbstractFile return null; } + final String queryStr = keywordQuery.getQuery(); + final KeywordSearchList list = keywordToList.get(queryStr); + final String listName = list.getName(); + + //new subProgress will be active after the initial query + //when we know number of hits to start() with if (keywordsSearched > 0) { subProgresses[keywordsSearched - 1].finish(); } - final String queryStr = keywordQuery.getQuery(); - final KeywordSearchList list = keywordToList.get(queryStr); - final String listName = list.getName(); KeywordSearchQuery del = null; @@ -1080,11 +1083,14 @@ public final class KeywordSearchIngestModule implements IngestModuleAbstractFile if (!newArtifacts.isEmpty()) { services.fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT, newArtifacts)); } - } - + } //if has results + + //reset the status text before it goes away + subProgresses[keywordsSearched].progress(""); + ++keywordsSearched; - } + } //for each keyword } //end try block catch (Exception ex) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java index 89ed96d8f8..9a4fdcd7fb 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java @@ -56,7 +56,7 @@ public class TermComponentQuery implements KeywordSearchQuery { private Keyword keywordQuery = null; private KeywordQueryFilter filter = null; private String field = null; - private static int MAX_TERMS_RESULTS = 20000; + private static int MAX_TERMS_RESULTS = 200000; private static final boolean DEBUG = (Version.getBuildType() == Version.Type.DEVELOPMENT); From 4cd1202c731bcf9f712d366bc34735bd0c6a5ca9 Mon Sep 17 00:00:00 2001 From: adam-m Date: Fri, 4 Jan 2013 12:36:58 -0500 Subject: [PATCH 04/30] move cleanup to later --- .../keywordsearch/KeywordSearchIngestModule.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java index 0a8ac2c830..40591e0487 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java @@ -252,9 +252,9 @@ public final class KeywordSearchIngestModule implements IngestModuleAbstractFile logger.log(Level.WARNING, "Error executing Solr query to check number of indexed files/chunks: ", ex); } catch (KeywordSearchModuleException se) { logger.log(Level.WARNING, "Error executing Solr query to check number of indexed files/chunks: ", se); - } finally { - cleanup(); } + + //cleanup done in final searcher //postSummary(); } @@ -290,13 +290,13 @@ public final class KeywordSearchIngestModule implements IngestModuleAbstractFile } /** - * Common cleanup code when module stops or completes + * Common cleanup code when module stops or final searcher completes */ private void cleanup() { ingestStatus.clear(); currentResults.clear(); currentSearcher = null; - finalSearcher = null; + //finalSearcher = null; //do not collect, might be finalizing commitTimer.stop(); searchTimer.stop(); @@ -1148,8 +1148,11 @@ public final class KeywordSearchIngestModule implements IngestModuleAbstractFile //this is the final searcher logger.log(Level.INFO, "The final searcher in this ingest done."); finalSearcherDone = true; - + services.postMessage(IngestMessage.createMessage(++messageID, MessageType.INFO, KeywordSearchIngestModule.instance, "Completed")); + + //run module cleanup + cleanup(); } else { //start counting time for a new searcher to start //unless final searcher is pending From f72dbc4c77e8cfd061eb747ada3972e7e70400f6 Mon Sep 17 00:00:00 2001 From: adam-m Date: Fri, 4 Jan 2013 12:37:19 -0500 Subject: [PATCH 05/30] config change make changes visible after 15k doc commit kicks in --- KeywordSearch/release/solr/solr/conf/solrconfig.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KeywordSearch/release/solr/solr/conf/solrconfig.xml b/KeywordSearch/release/solr/solr/conf/solrconfig.xml index 194c465f3b..052ddce699 100644 --- a/KeywordSearch/release/solr/solr/conf/solrconfig.xml +++ b/KeywordSearch/release/solr/solr/conf/solrconfig.xml @@ -321,7 +321,7 @@ --> 15000 - false + true + + + + diff --git a/KeywordSearch/nbproject/project.xml b/KeywordSearch/nbproject/project.xml index d08f171144..c0a8fd51d7 100644 --- a/KeywordSearch/nbproject/project.xml +++ b/KeywordSearch/nbproject/project.xml @@ -144,21 +144,29 @@ release/modules/ext/vorbis-java-core-0.1-tests.jar - ext/log4j-over-slf4j-1.6.4.jar - release/modules/ext/log4j-over-slf4j-1.6.4.jar + ext/tika-parsers-1.2-javadoc.jar + release/modules/ext/tika-parsers-1.2-javadoc.jar - ext/isoparser-1.0-RC-1.jar - release/modules/ext/isoparser-1.0-RC-1.jar + ext/log4j-over-slf4j-1.6.4.jar + release/modules/ext/log4j-over-slf4j-1.6.4.jar ext/vorbis-java-tika-0.1.jar release/modules/ext/vorbis-java-tika-0.1.jar + + ext/isoparser-1.0-RC-1.jar + release/modules/ext/isoparser-1.0-RC-1.jar + ext/httpcore-4.1.4.jar release/modules/ext/httpcore-4.1.4.jar + + ext/tika-parsers-1.2-sources.jar + release/modules/ext/tika-parsers-1.2-sources.jar + ext/aspectjrt-1.6.11.jar release/modules/ext/aspectjrt-1.6.11.jar @@ -187,6 +195,10 @@ ext/httpclient-4.1.3.jar release/modules/ext/httpclient-4.1.3.jar + + ext/icu4j-3.8.jar + release/modules/ext/icu4j-3.8.jar + ext/juniversalchardet-1.0.3.jar release/modules/ext/juniversalchardet-1.0.3.jar @@ -195,6 +207,10 @@ ext/pdfbox-1.7.0.jar release/modules/ext/pdfbox-1.7.0.jar + + ext/jericho-html-3.3-sources.jar + release/modules/ext/jericho-html-3.3-sources.jar + ext/jdom-1.0.jar release/modules/ext/jdom-1.0.jar @@ -227,10 +243,18 @@ ext/slf4j-api-1.7.2.jar release/modules/ext/slf4j-api-1.7.2.jar + + ext/commons-lang-2.4-javadoc.jar + release/modules/ext/commons-lang-2.4-javadoc.jar + ext/jempbox-1.7.0.jar release/modules/ext/jempbox-1.7.0.jar + + ext/jericho-html-3.3-javadoc.jar + release/modules/ext/jericho-html-3.3-javadoc.jar + ext/wstx-asl-3.2.7.jar release/modules/ext/wstx-asl-3.2.7.jar @@ -239,6 +263,10 @@ ext/netcdf-4.2-min.jar release/modules/ext/netcdf-4.2-min.jar + + ext/solr-solrj-4.0.0-javadoc.jar + release/modules/ext/solr-solrj-4.0.0-javadoc.jar + ext/xmlbeans-2.3.0.jar release/modules/ext/xmlbeans-2.3.0.jar @@ -287,18 +315,26 @@ ext/poi-ooxml-schemas-3.8.jar release/modules/ext/poi-ooxml-schemas-3.8.jar - - ext/jericho-html-3.3.jar - release/modules/ext/jericho-html-3.3.jar - ext/bcprov-jdk15-1.45.jar release/modules/ext/bcprov-jdk15-1.45.jar + + ext/jericho-html-3.3.jar + release/modules/ext/jericho-html-3.3.jar + ext/solr-solrj-4.0.0.jar release/modules/ext/solr-solrj-4.0.0.jar + + ext/commons-lang-2.4-sources.jar + release/modules/ext/commons-lang-2.4-sources.jar + + + ext/solr-solrj-4.0.0-sources.jar + release/modules/ext/solr-solrj-4.0.0-sources.jar + ext/apache-mime4j-dom-0.7.2.jar release/modules/ext/apache-mime4j-dom-0.7.2.jar From fb8d3ea9b66a214d34fed4d1c3f60ec012d97f2b Mon Sep 17 00:00:00 2001 From: adam-m Date: Mon, 7 Jan 2013 16:10:58 -0500 Subject: [PATCH 12/30] update news --- NEWS.txt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/NEWS.txt b/NEWS.txt index 694d57663d..eea827172e 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -4,17 +4,14 @@ As a workaround, you will need to rebuild index by re-running Keyword Search ingest on Cases created with previous versions. Improvements: -- Keyword Search indexing and search speed improvements -- Improved Keyword Search highlighting in Text View: highlighted tokens are no longer delimiter separated -- Better progress updates from Keyword Search ingest -- Upgrade to Solr4.0 / Tika 1.2 +- Upgrade to Solr4.0 / Tika 1.2: Improved performance and highlighting - Remake of reporting UI and functionality - Significant increase in reporting speed - New option to keep the most specific file viewer (default) or the lastly used viewer active. Bugfixes: -- Keyword search now indexes and searches entire extracted content from files and does not miss content. +- Fixed bug that caused the ends of large amounts of text to not be indexed (occurs mostly in unallocated space). - Fix scrolling to first keyword hit when Text View is first loaded - Imported keyword lists are now always enabled for ingest by default From b5714cf4b4a3d8a05145ae6421133bde6712519f Mon Sep 17 00:00:00 2001 From: adam-m Date: Mon, 7 Jan 2013 17:53:53 -0500 Subject: [PATCH 13/30] news placeholder --- NEWS.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/NEWS.txt b/NEWS.txt index eea827172e..09f34ab17a 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,3 +1,15 @@ +---------------- VERSION Current (development) -------------- + +New features: + + +Improvements: + + +Bugfixes: + + + ---------------- VERSION 3.0.3 -------------- *Note: Due to major changes in Keyword search module indexing this release is not fully backward compatible. From f29f48d34b63389bf8a4cd9dfa05a5f0e65f2d7c Mon Sep 17 00:00:00 2001 From: adam-m Date: Mon, 7 Jan 2013 21:36:01 -0500 Subject: [PATCH 14/30] Add support for custom content viewer responding to sel. events from custom result viewer --- .../DataResultViewer.java | 7 ++++ .../AbstractDataResultViewer.java | 22 +++++++++--- .../DataResultTopComponent.java | 35 +++++++++++++++++-- 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java index cf85bcaf25..b8e2ef44b2 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataResultViewer.java @@ -80,4 +80,11 @@ public interface DataResultViewer { * @return True if supported, else false */ public boolean isSupported(Node selectedNode); + + /** + * Set a custom content viewer to respond to selection events from this result viewer. + * If not set, the default content viewer is user + * @param contentViewer content viewer to respond to selection events from this viewer + */ + public void setContentViewer(DataContent contentViewer); } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java index 1d9d3c640b..da3f69e4e3 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AbstractDataResultViewer.java @@ -43,9 +43,19 @@ public abstract class AbstractDataResultViewer extends JPanel implements private static final Logger logger = Logger.getLogger(AbstractDataResultViewer.class.getName()); protected transient ExplorerManager em = new ExplorerManager(); private PropertyChangeListener nodeSelListener; + + /** + * Content viewer to respond to selection events + * Either the main one, or custom one if set + */ + protected DataContent contentViewer; public AbstractDataResultViewer() { + //DataContent is designed to return only the default viewer from lookup + //use the default one unless set otherwise + contentViewer = Lookup.getDefault().lookup(DataContent.class); + //property listener to send nodes to content viewer nodeSelListener = new PropertyChangeListener() { @@ -70,17 +80,16 @@ public abstract class AbstractDataResultViewer extends JPanel implements nodeSelected(selectedNode); - // DataContent is designed to return only the default viewer - DataContent dataContent = Lookup.getDefault().lookup(DataContent.class); + if (selectedNode != null) { // there's a new/changed node to display Node newSelectedNode = selectedNode; // get the selected Node on the table // push the node to default "DataContent" - dataContent.setNode(newSelectedNode); + contentViewer.setNode(newSelectedNode); } else { // clear the node viewer - dataContent.setNode(null); + contentViewer.setNode(null); } } finally { setCursor(null); @@ -155,4 +164,9 @@ public abstract class AbstractDataResultViewer extends JPanel implements logger.log(Level.WARNING, "Couldn't set selected nodes.", ex); } } + + @Override + public void setContentViewer(DataContent contentViewer) { + this.contentViewer = contentViewer; + } } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java index 08d8b38925..32da094913 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.corecomponents; -import java.awt.Component; import java.awt.Cursor; import java.beans.PropertyChangeListener; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResult; @@ -33,6 +32,7 @@ import org.openide.windows.TopComponent; import org.openide.nodes.Node; import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataContent; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; /** @@ -52,7 +52,15 @@ public final class DataResultTopComponent extends TopComponent implements DataRe public static String REMOVE_FILESEARCH = "RemoveFileSearchTopComponent"; // Different DataResultsViewers private List viewers = new ArrayList(); + + //custom content viewer to send selections to, or null if the main one + private DataContent customContentViewer; + /** + * Create a new data result top component + * @param isMain whether it is the main, application default result viewer, there can be only 1 main result viewer + * @param title title of the data result window + */ public DataResultTopComponent(boolean isMain, String title) { initComponents(); setToolTipText(NbBundle.getMessage(DataResultTopComponent.class, "HINT_NodeTableTopComponent")); @@ -65,6 +73,19 @@ public final class DataResultTopComponent extends TopComponent implements DataRe this.dataResultTabbedPanel.addChangeListener(this); } + + /** + * Create a new, custom data result top component, in addition to the application main one + * @param title title of the data result window + * @param customContentViewer custom content viewer to send selection events to + */ + public DataResultTopComponent(String title, DataContentTopComponent customContentViewer) { + this(false, title); + + //custom content viewer tc to setup for every result viewer + this.customContentViewer = customContentViewer; + } + private static class UpdateWrapper { @@ -102,6 +123,10 @@ public final class DataResultTopComponent extends TopComponent implements DataRe boolean isSupported(Node selectedNode) { return this.wrapped.isSupported(selectedNode); } + + void setContentViewer(DataContent contentViewer) { + this.wrapped.setContentViewer(contentViewer); + } } /** @@ -191,8 +216,14 @@ public final class DataResultTopComponent extends TopComponent implements DataRe // find all dataContentViewer and add them to the tabbed pane for (DataResultViewer factory : Lookup.getDefault().lookupAll(DataResultViewer.class)) { DataResultViewer drv = factory.getInstance(); - this.viewers.add(new UpdateWrapper(drv)); + UpdateWrapper resultViewer = new UpdateWrapper(drv); + if (customContentViewer != null) { + //set custom content viewer to respond to events from this result viewer + resultViewer.setContentViewer(customContentViewer); + } + this.viewers.add(resultViewer); this.dataResultTabbedPanel.addTab(drv.getTitle(), drv.getComponent()); + } } From af6a3d7da48c26e55399245b2134d80f0770fe69 Mon Sep 17 00:00:00 2001 From: adam-m Date: Tue, 8 Jan 2013 12:40:08 -0500 Subject: [PATCH 15/30] update news --- NEWS.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS.txt b/NEWS.txt index 09f34ab17a..9c5d458d53 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,7 +1,8 @@ ---------------- VERSION Current (development) -------------- New features: - +- Results and files can be tagged with custom tags and assigned different categories, and +they can be reported on based on those categories. Improvements: From 8bbd3c195bd9361ef0d432ef1829397198803580 Mon Sep 17 00:00:00 2001 From: adam-m Date: Tue, 8 Jan 2013 13:51:03 -0500 Subject: [PATCH 16/30] remove deprecation warning, use proper methods to close queries --- .../autopsy/datamodel/EmailExtracted.java | 1 + .../datamodel/FileSearchFilterChildren.java | 18 +++++-- .../autopsy/datamodel/HashsetHits.java | 20 +++++--- .../autopsy/datamodel/KeywordHits.java | 19 ++++--- .../datamodel/RecentFilesChildren.java | 40 ++++++++------- .../datamodel/RecentFilesFilterChildren.java | 49 ++++++++++--------- .../org/sleuthkit/autopsy/datamodel/Tags.java | 2 + .../directorytree/ResultDeleteAction.java | 19 ++++++- .../autopsy/filesearch/FileSearchPanel.java | 13 ++--- .../filesearch/FileSearchTopComponent.java | 13 ++--- 10 files changed, 119 insertions(+), 75 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 6e4ab779a7..a4c3ca1ff2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -60,6 +60,7 @@ public class EmailExtracted implements AutopsyVisitableItem { accounts = new LinkedHashMap>>(); } + @SuppressWarnings("deprecation") private void initArtifacts() { accounts.clear(); try { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileSearchFilterChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileSearchFilterChildren.java index 7e537dfb2a..487c3f83d1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileSearchFilterChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileSearchFilterChildren.java @@ -28,6 +28,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; import org.openide.nodes.Node; +import org.openide.util.Exceptions; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.datamodel.SearchFilters.FileSearchFilter; import org.sleuthkit.datamodel.Content; @@ -69,22 +70,29 @@ class FileSearchFilterChildren extends ChildFactory { return query; } + @SuppressWarnings("deprecation") private List runQuery(){ + ResultSet rs = null; List list = new ArrayList(); try { - ResultSet rs = skCase.runQuery(createQuery()); + rs = skCase.runQuery(createQuery()); for(FsContent c : skCase.resultSetToFsContents(rs)){ if(c.isFile()){ list.add(c); } } - Statement s = rs.getStatement(); - rs.close(); - if (s != null) - s.close(); } catch (SQLException ex) { logger.log(Level.WARNING, "Couldn't get search results", ex); } + finally { + if (rs != null) { + try { + skCase.closeRunQuery(rs); + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Error closing result set after executing fscontents query for file search results", ex); + } + } + } return list; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index ac2eddf0d4..ca15f6d2e7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -34,6 +34,7 @@ import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; +import org.openide.util.Exceptions; import org.openide.util.lookup.Lookups; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -56,8 +57,10 @@ public class HashsetHits implements AutopsyVisitableItem { hashSetHitsMap = new LinkedHashMap>(); } + @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(); @@ -66,7 +69,7 @@ public class HashsetHits implements AutopsyVisitableItem { + "attribute_type_id=" + setNameId + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" + " AND blackboard_artifacts.artifact_type_id=" + artId; - ResultSet rs = skCase.runQuery(query); + rs = skCase.runQuery(query); while (rs.next()) { String value = rs.getString("value_text"); long artifactId = rs.getLong("artifact_id"); @@ -76,14 +79,19 @@ public class HashsetHits implements AutopsyVisitableItem { hashSetHitsMap.get(value).add(artifactId); } - Statement s = rs.getStatement(); - rs.close(); - if (s != null) { - s.close(); - } + } catch (SQLException ex) { logger.log(Level.WARNING, "SQL Exception occurred: ", ex); } + finally { + if (rs != null) { + try { + skCase.closeRunQuery(rs); + } catch (SQLException ex) { + logger.log(Level.WARNING, "Error closing result set after getting hashset hits", ex); + } + } + } } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 49eba6305c..e11fe6be2c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -106,8 +106,10 @@ public class KeywordHits implements AutopsyVisitableItem { } } + @SuppressWarnings("deprecation") private void initArtifacts() { artifacts.clear(); + ResultSet rs = null; try { int setId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(); int wordId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID(); @@ -120,7 +122,7 @@ public class KeywordHits implements AutopsyVisitableItem { + ") AND (attribute_type_id=" + setId + " OR " + "attribute_type_id=" + wordId + " OR " + "attribute_type_id=" + regexId + ")"; - ResultSet rs = skCase.runQuery(query); + rs = skCase.runQuery(query); while (rs.next()) { String value = rs.getString("value_text"); long artifactId = rs.getLong("artifact_id"); @@ -133,14 +135,19 @@ public class KeywordHits implements AutopsyVisitableItem { } } - Statement s = rs.getStatement(); - rs.close(); - if (s != null) { - s.close(); - } + } catch (SQLException ex) { logger.log(Level.WARNING, "SQL Exception occurred: ", ex); } + finally { + if (rs != null) { + try { + skCase.closeRunQuery(rs); + } catch (SQLException ex) { + logger.log(Level.WARNING, "Error closing result set after getting keyword hits", ex); + } + } + } } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesChildren.java index 1df31ce6f0..141a4cab30 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesChildren.java @@ -34,12 +34,12 @@ import org.sleuthkit.datamodel.SleuthkitCase; * * @author dfickling */ -public class RecentFilesChildren extends ChildFactory{ - +public class RecentFilesChildren extends ChildFactory { + SleuthkitCase skCase; Calendar lastDay; private final static Logger logger = Logger.getLogger(RecentFilesChildren.class.getName()); - + public RecentFilesChildren(SleuthkitCase skCase) { this.skCase = skCase; } @@ -48,7 +48,7 @@ public class RecentFilesChildren extends ChildFactory list) { list.addAll(Arrays.asList(RecentFiles.RecentFilesFilter.values())); lastDay = Calendar.getInstance(); - lastDay.setTimeInMillis(getLastTime()*1000); + lastDay.setTimeInMillis(getLastTime() * 1000); lastDay.set(Calendar.HOUR_OF_DAY, 0); lastDay.set(Calendar.MINUTE, 0); lastDay.set(Calendar.SECOND, 0); @@ -57,10 +57,10 @@ public class RecentFilesChildren extends ChildFactory{ - +public class RecentFilesFilterChildren extends ChildFactory { + SleuthkitCase skCase; RecentFilesFilter filter; Calendar prevDay; @@ -61,13 +61,13 @@ public class RecentFilesFilterChildren extends ChildFactory{ list.addAll(runFsQuery()); return true; } - - private String createQuery(){ + + private String createQuery() { String query = "select * from tsk_files where known <> 1 and ("; - long lowerLimit = prevDay.getTimeInMillis()/1000; + long lowerLimit = prevDay.getTimeInMillis() / 1000; prevDay.add(Calendar.DATE, 1); prevDay.add(Calendar.MILLISECOND, -1); - long upperLimit = prevDay.getTimeInMillis()/1000; + long upperLimit = prevDay.getTimeInMillis() / 1000; query += "(crtime between " + lowerLimit + " and " + upperLimit + ") or "; query += "(ctime between " + lowerLimit + " and " + upperLimit + ") or "; //query += "(atime between " + lowerLimit + " and " + upperLimit + ") or "; @@ -75,33 +75,39 @@ public class RecentFilesFilterChildren extends ChildFactory{ //query += " limit " + MAX_OBJECTS; return query; } - - private List runFsQuery(){ + + @SuppressWarnings("deprecation") + private List runFsQuery() { List list = new ArrayList(); + ResultSet rs = null; try { - ResultSet rs = skCase.runQuery(createQuery()); - for(FsContent c : skCase.resultSetToFsContents(rs)){ - if(c.isFile()){ + rs = skCase.runQuery(createQuery()); + for (FsContent c : skCase.resultSetToFsContents(rs)) { + if (c.isFile()) { list.add(c); } } - Statement s = rs.getStatement(); - rs.close(); - if (s != null) - s.close(); + } catch (SQLException ex) { logger.log(Level.WARNING, "Couldn't get search results", ex); + } finally { + if (rs != null) { + try { + skCase.closeRunQuery(rs); + } catch (SQLException ex) { + logger.log(Level.WARNING, "Error closing result set after getting recent files results", ex); + } + } } return list; - + } - + @Override - protected Node createNodeForKey(Content key){ - return key.accept(new ContentVisitor.Default(){ - + protected Node createNodeForKey(Content key) { + return key.accept(new ContentVisitor.Default() { @Override - public FileNode visit(File f){ + public FileNode visit(File f) { return new FileNode(f, false); } @@ -109,7 +115,6 @@ public class RecentFilesFilterChildren extends ChildFactory{ protected AbstractNode defaultVisit(Content di) { throw new UnsupportedOperationException("Not supported for this type of Displayable Item: " + di.toString()); } - }); } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 78f8ce1a08..1f25544575 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -312,6 +312,7 @@ public class Tags implements AutopsyVisitableItem { * Uses a custom query for speed when dealing with thousands of Tags. * @return a list of all tag names. */ + @SuppressWarnings("deprecation") public static List getTagNames() { Case currentCase = Case.getCurrentCase(); SleuthkitCase skCase = currentCase.getSleuthkitCase(); @@ -333,6 +334,7 @@ public class Tags implements AutopsyVisitableItem { try { skCase.closeRunQuery(rs); } catch (SQLException ex) { + logger.log(Level.SEVERE, "Failed to close the query for blackboard for tag names."); } } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ResultDeleteAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ResultDeleteAction.java index aad956f577..0353fdd7cc 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ResultDeleteAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ResultDeleteAction.java @@ -33,7 +33,9 @@ import org.sleuthkit.datamodel.SleuthkitCase; /** * Action that deletes blackboard artifacts requested and reloads the view + * @deprecated do not use, it is here in case we ever pick up on this work */ +@Deprecated public class ResultDeleteAction extends AbstractAction { private enum ActionType { @@ -100,6 +102,7 @@ public class ResultDeleteAction extends AbstractAction { } //TODO should be moved to SleuthkitCase and BlackboardArtifact API + @SuppressWarnings("deprecation") private static void deleteArtifact(BlackboardArtifact art) { final SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); final long artId = art.getArtifactID(); @@ -117,15 +120,17 @@ public class ResultDeleteAction extends AbstractAction { } + @SuppressWarnings("deprecation") private static void deleteArtifactsByAttributeValue(BlackboardArtifact.ARTIFACT_TYPE artType, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String value) { final SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); + ResultSet rs = null; try { //first to select to get artifact ids to delete //then join delete attrs //then delete arts by id - ResultSet rs = skCase.runQuery("DELETE FROM blackboard_attributes WHERE artifact_id IN " + rs = skCase.runQuery("DELETE FROM blackboard_attributes WHERE artifact_id IN " + "(SELECT blackboard_artifacts.artifact_id FROM blackboard_artifacts " + "INNER JOIN blackboard_attributes ON (blackboard_attributes.artifact_id = blackboard_artifacts.artifact_id) " + "WHERE blackboard_artifacts.artifact_type_id = " @@ -134,7 +139,7 @@ public class ResultDeleteAction extends AbstractAction { + " AND blackboard_attributes.value_type = " + BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING.getType() + " AND blackboard_attributes.value_text = '" + value + "'" + ")"); - skCase.closeRunQuery(rs); + //rs = skCase.runQuery("DELETE from blackboard_artifacts where artifact_type_id = " // + Integer.toString(artType.getTypeID())); @@ -143,10 +148,20 @@ public class ResultDeleteAction extends AbstractAction { } catch (SQLException ex) { logger.log(Level.WARNING, "Could not delete artifacts by type id: " + artType.getTypeID(), ex); } + finally { + if (rs != null) { + try { + skCase.closeRunQuery(rs); + } catch (SQLException ex) { + logger.log(Level.WARNING, "Error closing result set after deleting", ex); + } + } + } } //TODO should be moved to SleuthkitCase + @SuppressWarnings("deprecation") private static void deleteArtifacts(BlackboardArtifact.ARTIFACT_TYPE artType) { // SELECT * from blackboard_attributes INNER JOIN blackboard_artifacts ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_ID AND blackboard_artifacts.artifact_type_id = 9; final SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java index 08414f9f58..68b89014e9 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java @@ -153,6 +153,7 @@ public class FileSearchPanel extends javax.swing.JPanel { * Action when the "Search" button is pressed. * */ + @SuppressWarnings("deprecation") private void search() { // change the cursor to "waiting cursor" for this operation this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); @@ -170,16 +171,12 @@ public class FileSearchPanel extends javax.swing.JPanel { SleuthkitCase tempDb = currentCase.getSleuthkitCase(); ResultSet rs = tempDb.runQuery(this.getQuery("count(*) as TotalMatches")); totalMatches = totalMatches + rs.getInt("TotalMatches"); - Statement s = rs.getStatement(); - rs.close(); - if (s != null) - s.close(); + tempDb.closeRunQuery(rs); + rs = tempDb.runQuery(this.getQuery(null)); currentDbList = tempDb.resultSetToFsContents(rs); - s = rs.getStatement(); - rs.close(); - if (s != null) - s.close(); + tempDb.closeRunQuery(rs); + fsContentList.addAll(currentDbList); } catch (SQLException ex) { Logger logger = Logger.getLogger(this.getClass().getName()); diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchTopComponent.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchTopComponent.java index 2a4d188c76..dfab9f87cb 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchTopComponent.java @@ -150,6 +150,7 @@ public final class FileSearchTopComponent extends TopComponent implements DataEx * Action when the "Search" button is pressed. * */ + @SuppressWarnings("deprecation") private void search() { // change the cursor to "waiting cursor" for this operation this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); @@ -167,16 +168,12 @@ public final class FileSearchTopComponent extends TopComponent implements DataEx SleuthkitCase tempDb = currentCase.getSleuthkitCase(); ResultSet rs = tempDb.runQuery(this.getQuery("count(*) as TotalMatches")); totalMatches = totalMatches + rs.getInt("TotalMatches"); - Statement s = rs.getStatement(); - rs.close(); - if (s != null) - s.close(); + tempDb.closeRunQuery(rs); + rs = tempDb.runQuery(this.getQuery(null)); currentDbList = tempDb.resultSetToFsContents(rs); - s = rs.getStatement(); - rs.close(); - if (s != null) - s.close(); + tempDb.closeRunQuery(rs); + fsContentList.addAll(currentDbList); } catch (SQLException ex) { Logger logger = Logger.getLogger(this.getClass().getName()); From 56a4bb756c670553a2a5d8a642e8dd0b2a3038b8 Mon Sep 17 00:00:00 2001 From: adam-m Date: Tue, 8 Jan 2013 13:57:40 -0500 Subject: [PATCH 17/30] Fix unchecked warning --- Core/src/org/sleuthkit/autopsy/datamodel/ContentChildren.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentChildren.java index cfb275e55d..bfcd35ad5c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentChildren.java @@ -28,7 +28,7 @@ import org.sleuthkit.datamodel.Content; * Class for Children of all ContentNodes. Handles creating child ContentNodes. * TODO consider a ContentChildren child factory */ -class ContentChildren extends AbstractContentChildren { +class ContentChildren extends AbstractContentChildren { private static final Logger logger = Logger.getLogger(ContentChildren.class.getName()); //private static final int MAX_CHILD_COUNT = 1000000; @@ -72,7 +72,7 @@ class ContentChildren extends AbstractContentChildren { @Override protected void removeNotify() { super.removeNotify(); - setKeys(Collections.EMPTY_SET); + setKeys(new ArrayList()); } } From f9373d6e139bbf12916d920b10769de91b4987b0 Mon Sep 17 00:00:00 2001 From: adam-m Date: Tue, 8 Jan 2013 14:04:17 -0500 Subject: [PATCH 18/30] fix ra warning, better close --- .../autopsy/recentactivity/Extract.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java index 6b243362c6..d8e5cac00c 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java @@ -58,6 +58,7 @@ abstract public class Extract implements IngestModuleImage{ * @param query is a sql string query that is to be run * @return FFSqlitedb is a List of FsContent objects */ + @SuppressWarnings("deprecation") public List extractFiles(Image image, String query) { Collection imageFS = tskCase.getFileSystems(image); @@ -78,20 +79,23 @@ abstract public class Extract implements IngestModuleImage{ } } List FFSqlitedb = null; + ResultSet rs = null; try { - ResultSet rs = tskCase.runQuery(query + allFS); + rs = tskCase.runQuery(query + allFS); FFSqlitedb = tskCase.resultSetToFsContents(rs); - Statement s = rs.getStatement(); - rs.close(); - if (s != null) { - s.close(); - } - rs.close(); - rs.getStatement().close(); } catch (SQLException ex) { logger.log(Level.SEVERE, "Error while trying to extract files for:" + this.getClass().getName(), ex); this.addErrorMessage(this.getName() + ": Error while trying to extract files to analyze."); } + finally { + if (rs != null) { + try { + tskCase.closeRunQuery(rs); + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Error while trying to close result set after extract files for:" + this.getClass().getName(), ex); + } + } + } return FFSqlitedb; } From 2c51d6bb29f7ec07154cab61b83c4346963e4e14 Mon Sep 17 00:00:00 2001 From: adam-m Date: Tue, 8 Jan 2013 14:25:32 -0500 Subject: [PATCH 19/30] tags adjustments --- Core/src/org/sleuthkit/autopsy/datamodel/Tags.java | 2 +- Core/src/org/sleuthkit/autopsy/directorytree/TagFileAction.java | 2 +- .../org/sleuthkit/autopsy/directorytree/TagResultAction.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 1f25544575..87f9d85e5a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -46,7 +46,7 @@ public class Tags implements AutopsyVisitableItem { private SleuthkitCase skCase; public static final String NAME = "Tags"; - private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png"; + private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; private Map> tags = new HashMap>(); Tags(SleuthkitCase skCase) { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagFileAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagFileAction.java index 652f12a6cf..c4628d689b 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagFileAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagFileAction.java @@ -65,7 +65,7 @@ public class TagFileAction extends AbstractAction implements Presenter.Popup { private String getComment() { String comment = JOptionPane.showInputDialog(null, - "Please enter a comment for the tag:", + "Please enter a comment for the tag (optional):", "Tag Comment", JOptionPane.PLAIN_MESSAGE); if(comment == null || comment.isEmpty()) { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagResultAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagResultAction.java index 06ddd4634b..cced72519e 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagResultAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagResultAction.java @@ -53,7 +53,7 @@ public class TagResultAction extends AbstractAction implements Presenter.Popup { private String getComment() { String comment = JOptionPane.showInputDialog(null, - "Please enter a comment for the tag:", + "Please enter a comment for the tag (optional):", "Tag Comment", JOptionPane.PLAIN_MESSAGE); if(comment == null || comment.isEmpty()) { From 7454f4ce74351c4992ee75d8a041a6fb33781313 Mon Sep 17 00:00:00 2001 From: adam-m Date: Tue, 8 Jan 2013 15:06:18 -0500 Subject: [PATCH 20/30] fix html report crash when tags have special chars (forward slash) --- .../org/sleuthkit/autopsy/coreutils/FileUtil.java | 12 ++++++++++++ .../src/org/sleuthkit/autopsy/report/ReportHTML.java | 12 ++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/FileUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/FileUtil.java index ce6478a662..d63259d584 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/FileUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/FileUtil.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.coreutils; import java.io.File; import java.io.IOException; import java.util.logging.Level; +import java.util.regex.Matcher; import org.openide.filesystems.FileObject; /** @@ -149,4 +150,15 @@ public class FileUtil { return created.getPath(); } + + /** + * Escape special characters in a file name or a file name component + * @param fileName to escape + * @return escaped string + */ + public static String escapeFileName(String fileName) { + //for now escaping / (not valid in file name, at least on Windows) + //with underscores. Windows/Java seem to ignore \\/ and \\\\/ escapings + return fileName.replaceAll("/", "_"); + } } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 8aca8ece11..4c91427585 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -140,9 +140,12 @@ public class ReportHTML implements TableReportModule { */ @Override public void startDataType(String title) { + String fTitle = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(title); // Make a new out for this page try { - out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + title + getExtension()), "UTF-8")); + //escape out slashes tha that appear in title + + out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + fTitle + getExtension()), "UTF-8")); } catch (FileNotFoundException ex) { logger.log(Level.SEVERE, "File not found: {0}", ex); } catch (UnsupportedEncodingException ex) { @@ -425,7 +428,12 @@ public class ReportHTML implements TableReportModule { nav.append("
  • Case Summary
  • \n"); for (String dataType : dataTypes.keySet()) { - nav.append("
  • ").append(dataType).append(" (").append(dataTypes.get(dataType)).append(")
  • \n"); + String dataTypeEsc = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(dataType); + nav.append("
  • ") + .append(dataType).append(" (").append(dataTypes.get(dataType)) + .append(")
  • \n"); } nav.append("\n"); nav.append("\n\n"); From ad6ae1ba3c64db8015cf7d1a090a4a636c14f377 Mon Sep 17 00:00:00 2001 From: adam-m Date: Tue, 8 Jan 2013 15:26:30 -0500 Subject: [PATCH 21/30] fix hang in excel report generation when special chars present in datatype --- .../org/sleuthkit/autopsy/report/ReportExcel.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java b/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java index f6cde6bafa..82448ebcbe 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java @@ -123,6 +123,7 @@ public class ReportExcel implements TableReportModule { } } } + /** * Start a new sheet for the given data type. @@ -130,6 +131,7 @@ public class ReportExcel implements TableReportModule { */ @Override public void startDataType(String title) { + title = escapeForExcel(title); sheet = wb.createSheet(title); sheet.setAutobreaks(true); currentDataType = title; @@ -154,6 +156,7 @@ public class ReportExcel implements TableReportModule { */ @Override public void startSet(String setName) { + setName = escapeForExcel(setName); Row temp = sheet.createRow(rowCount); temp.setRowStyle(setStyle); temp.createCell(0).setCellValue(setName); @@ -179,6 +182,7 @@ public class ReportExcel implements TableReportModule { */ @Override public void addSetElement(String elementName) { + elementName = escapeForExcel(elementName); Row temp = sheet.createRow(rowCount); temp.setRowStyle(elementStyle); temp.createCell(0).setCellValue(elementName); @@ -248,4 +252,13 @@ public class ReportExcel implements TableReportModule { return "Excel.xlsx"; } + /** + * Escape special chars for Excel that would cause errors/hangs in generating report + * The following are not valid for sheet names: ? / \ * : + * @param text + * @return + */ + private static String escapeForExcel(String text) { + return text.replaceAll("[\\/\\:\\?\\*\\\\]", "_"); + } } From 2e75294c1399cbaeb04290425560f438178ae145 Mon Sep 17 00:00:00 2001 From: adam-m Date: Tue, 8 Jan 2013 15:34:37 -0500 Subject: [PATCH 22/30] update news --- NEWS.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.txt b/NEWS.txt index 9c5d458d53..473571d9f9 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -8,7 +8,7 @@ Improvements: Bugfixes: - +- fixed crash and hang in html and excel report generation, due to special characters present ---------------- VERSION 3.0.3 -------------- From 2a7e0fbeb441d0dae898c7712ca2bd36abe5e93c Mon Sep 17 00:00:00 2001 From: adam-m Date: Tue, 8 Jan 2013 15:54:32 -0500 Subject: [PATCH 23/30] fix dox warnings --- Core/src/org/sleuthkit/autopsy/datamodel/Tags.java | 4 ++++ .../sleuthkit/autopsy/directorytree/ExtractUnallocAction.java | 2 +- Core/src/org/sleuthkit/autopsy/report/ReportHTML.java | 1 - 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 87f9d85e5a..1000da20ff 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -227,6 +227,7 @@ public class Tags implements AutopsyVisitableItem { * Create a tag for a file with TSK_TAG_NAME as tagName. * @param file to create tag for * @param tagName TSK_TAG_NAME + * @param comment the tag comment */ public static void createTag(AbstractFile file, String tagName, String comment) { try { @@ -250,6 +251,7 @@ public class Tags implements AutopsyVisitableItem { * Create a tag for an artifact with TSK_TAG_NAME as tagName. * @param artifact to create tag for * @param tagName TSK_TAG_NAME + * @param comment the tag comment */ public static void createTag(BlackboardArtifact artifact, String tagName, String comment) { try { @@ -279,6 +281,7 @@ public class Tags implements AutopsyVisitableItem { /** * Create a bookmark tag for a file. * @param file to create bookmark tag for + * @param comment the bookmark comment */ public static void createBookmark(AbstractFile file, String comment) { createTag(file, Bookmarks.BOOKMARK_TAG_NAME, comment); @@ -287,6 +290,7 @@ public class Tags implements AutopsyVisitableItem { /** * Create a bookmark tag for an artifact. * @param artifact to create bookmark tag for + * @param comment the bookmark comment */ public static void createBookmark(BlackboardArtifact artifact, String comment) { createTag(artifact, Bookmarks.BOOKMARK_TAG_NAME, comment); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java index 4eb8d84bb5..7e30685540 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java @@ -378,7 +378,7 @@ public final class ExtractUnallocAction extends AbstractAction { /** * LayoutDirectory has all the Layout(Unallocated) files * - * @param ld LayoutDirectory the visitor encountered + * @param vd VirtualDirectory the visitor encountered * @return A list containing all the LayoutFile in ld, * returns null if it fails */ diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 4c91427585..6b40763def 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -98,7 +98,6 @@ public class ReportHTML implements TableReportModule { * Start this report by setting the path, refreshing member variables, * and writing the skeleton for the HTML report. * @param path path to save the report - * @param info map of info to display in the summary */ @Override public void startReport(String path) { From 6d33cd7aafe1fb1db26d226f2f9f50d8847ee5ff Mon Sep 17 00:00:00 2001 From: adam-m Date: Wed, 9 Jan 2013 09:42:40 -0500 Subject: [PATCH 24/30] new static method to create a custom data result viewer linked to a custom content viewer --- .../DataResultTopComponent.java | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java index 32da094913..e25a539160 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java @@ -129,6 +129,17 @@ public final class DataResultTopComponent extends TopComponent implements DataRe } } + + private static void createInstanceCommon(String pathText, Node givenNode, int totalMatches, DataResultTopComponent newDataResult) { + newDataResult.numberMatchLabel.setText(Integer.toString(totalMatches)); + + newDataResult.open(); // open it first so the component can be initialized + + // set the tree table view + newDataResult.setNode(givenNode); + newDataResult.setPath(pathText); + } + /** * Creates a new non-default DataResult component * @@ -141,13 +152,25 @@ public final class DataResultTopComponent extends TopComponent implements DataRe public static DataResultTopComponent createInstance(String title, String pathText, Node givenNode, int totalMatches) { DataResultTopComponent newDataResult = new DataResultTopComponent(false, title); - newDataResult.numberMatchLabel.setText(Integer.toString(totalMatches)); + createInstanceCommon(pathText, givenNode, totalMatches, newDataResult); - newDataResult.open(); // open it first so the component can be initialized + return newDataResult; + } + + /** + * Creates a new non-default DataResult component + * + * @param title Title of the component window + * @param pathText Descriptive text about the source of the nodes displayed + * @param givenNode The new root node + * @param totalMatches Cardinality of root node's children + * @param dataContentWindow a handle to data content top component window to send events to from the new result viewer + * @return + */ + public static DataResultTopComponent createInstance(String title, String pathText, Node givenNode, int totalMatches, DataContentTopComponent dataContentWindow) { + DataResultTopComponent newDataResult = new DataResultTopComponent(title, dataContentWindow); - // set the tree table view - newDataResult.setNode(givenNode); - newDataResult.setPath(pathText); + createInstanceCommon(pathText, givenNode, totalMatches, newDataResult); return newDataResult; } From 2f529c1cc0176f0e8a5e6c1acb1eb8ba8f9ebe9d Mon Sep 17 00:00:00 2001 From: adam-m Date: Wed, 9 Jan 2013 13:51:38 -0500 Subject: [PATCH 25/30] add source file path to result content view for consistency --- .../autopsy/datamodel/ArtifactStringContent.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java index 1a6f272d28..ef75b1de5d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactStringContent.java @@ -104,6 +104,22 @@ public class ArtifactStringContent implements StringContent { buffer.append(""); buffer.append(""); } + + //add file path + buffer.append("
    "); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append("
    Source File"); + final Content content = getAssociatedContent(wrapped); + buffer.append(content.getName()); + buffer.append("
    Source File Path"); + buffer.append(DataConversion.getformattedPath(ContentUtils.getDisplayPath(content), 0, 1)); + buffer.append("
    "); buffer.append(""); return buffer.toString(); From 9b5a84e951b2fb6aa8849c7bf24ca2b09873889f Mon Sep 17 00:00:00 2001 From: adam-m Date: Wed, 9 Jan 2013 16:40:45 -0500 Subject: [PATCH 26/30] - added utils to show message / notification in status area - ingest errors/warnings now show as clickable notifications --- .../autopsy/coreutils/MessageNotifyUtil.java | 203 ++++++++++++++++++ .../autopsy/images/error-icon-16.png | Bin 0 -> 775 bytes .../sleuthkit/autopsy/images/info-icon-16.png | Bin 0 -> 791 bytes .../autopsy/images/warning-icon-16.png | Bin 0 -> 867 bytes .../ingest/IngestMessageTopComponent.java | 74 ++++--- .../autopsy/ingest/IngestMessagesToolbar.java | 5 +- 6 files changed, 257 insertions(+), 25 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java create mode 100644 Core/src/org/sleuthkit/autopsy/images/error-icon-16.png create mode 100644 Core/src/org/sleuthkit/autopsy/images/info-icon-16.png create mode 100644 Core/src/org/sleuthkit/autopsy/images/warning-icon-16.png diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java new file mode 100644 index 0000000000..0b5c96993d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java @@ -0,0 +1,203 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.coreutils; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.net.URL; +import java.util.logging.Level; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import org.openide.DialogDisplayer; +import org.openide.NotifyDescriptor; +import org.openide.awt.NotificationDisplayer; +import org.openide.util.ImageUtilities; + +/** + * Utility for displaying messages and notifications in status area. Wraps + * around NB RCP NotificationDisplayer. + * + * Messages can optionally contain click-able Actions. + * + * Based on: + * http://qbeukes.blogspot.com/2009/11/netbeans-platform-notifications.html + * + * @license Apache License 2.0 + */ +public class MessageNotifyUtil { + + private MessageNotifyUtil() { + } + + public enum MessageType { + + INFO(NotifyDescriptor.INFORMATION_MESSAGE, "info-icon-16.png"), + ERROR(NotifyDescriptor.ERROR_MESSAGE, "error-icon-16.png"), + WARNING(NotifyDescriptor.WARNING_MESSAGE, "warning-icon-16.png"); + private int notifyDescriptorType; + private Icon icon; + + private MessageType(int notifyDescriptorType, String resourceName) { + this.notifyDescriptorType = notifyDescriptorType; + if (resourceName == null) { + icon = new ImageIcon(); + } else { + icon = loadIcon(resourceName); + } + } + + private static Icon loadIcon(String resourceName) { + Icon icon = ImageUtilities.loadImageIcon("org/sleuthkit/autopsy/images/" + resourceName, false); + if (icon == null) { + Logger logger = Logger.getLogger(org.sleuthkit.autopsy.coreutils.MessageNotifyUtil.MessageType.class.getName()); + logger.log(Level.SEVERE, "Failed to load icon resource: " + resourceName + ". Using blank image."); + icon = new ImageIcon(); + } + return icon; + } + + int getNotifyDescriptorType() { + return notifyDescriptorType; + } + + Icon getIcon() { + return icon; + } + } + + /** + * Utility to display messages + */ + public static class Message { + + private Message() { + } + + /** + * @return The dialog displayer used to show message boxes + */ + public static DialogDisplayer getDialogDisplayer() { + return DialogDisplayer.getDefault(); + } + + /** + * Show a message of the specified type + * + * @param message message to show + * @param messageType message type to show + */ + public static void show(String message, MessageType messageType) { + getDialogDisplayer().notify(new NotifyDescriptor.Message(message, + messageType.getNotifyDescriptorType())); + } + + /** + * Show an information dialog + * + * @param message message to show + */ + public static void info(String message) { + show(message, MessageType.INFO); + } + + /** + * Show an error dialog + * + * @param message message to shpw + */ + public static void error(String message) { + show(message, MessageType.ERROR); + } + + /** + * Show an warning dialog + * + * @param message message to show + */ + public static void warn(String message) { + show(message, MessageType.WARNING); + } + } + + /** + * Utility to display notifications with baloons + */ + public static class Notify { + + private Notify() { + } + + /** + * Show message with the specified type and action listener + */ + public static void show(String title, String message, MessageType type, ActionListener actionListener) { + NotificationDisplayer.getDefault().notify(title, type.getIcon(), message, actionListener); + } + + /** + * Show message with the specified type and a default action which + * displays the message using MessageNotifyUtil.Message with the same + * message type + * + * @param title message title + * @param message message text + * @param type type of the message + */ + public static void show(String title, final String message, final MessageType type) { + ActionListener actionListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + MessageNotifyUtil.Message.show(message, type); + } + }; + + show(title, message, type, actionListener); + } + + /** + * Show an information notification + * + * @param title message title + * @param message message text + */ + public static void info(String title, String message) { + show(title, message, MessageType.INFO); + } + + /** + * Show an error notification + * + * @param title message title + * @param message message text + */ + public static void error(String title, String message) { + show(title, message, MessageType.ERROR); + } + + /** + * Show an warning notification + * + * @param title message title + * @param message message text + */ + public static void warn(String title, String message) { + show(title, message, MessageType.WARNING); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/images/error-icon-16.png b/Core/src/org/sleuthkit/autopsy/images/error-icon-16.png new file mode 100644 index 0000000000000000000000000000000000000000..54ef8cefacf8ad076129c58c3d94c5dad2c9eb76 GIT binary patch literal 775 zcmV+i1Ni)jP)oU|iOS6an-!uu1g7ANA8rOQ&dV_dyCwcpGJ#_; z^tNSEx^f<*ra?Fck=UPSFbE^#aCC~HeyLD!K9j%+?koAMt1OX>QDK!Ji}0s}Al^dQ z24C$GEj}egZ$Cm~fZL<6K2ET?H4|6;5{L=F`U12N|Fw{`G?)XEg1RFlCnIc8h0xJ1gX@pyj6Fq!{;dB^Eg>!zH!GV1AL$gszrlR6K&vi26 zZZEbuB_@gdB*1S539MU-<{js|COgf5&S`XY(23qyAOw9RCMFh}S47Su4^~Hkd5`$U z__Vy76amLgHp{IUa3hSNcH}aCq6mi?kgw4MfxW(-%=UI+O>8+{iNCoS|EW{veOmmE zv~VrLgj$eF&#n1v(!DaQNyyl?jl9lI6Fm9+DavYPW@(v8GO>L-fvzsbq=i25mMAyP zHC~&8t3t}xgv4G~M{!37pZlKR-B2Y{wJ_Ixo2;@$j8s=M-QA5R1w7KnSwq$sS7V7y zgjB>@n^d5GR)m)=MH?6(J(v(gC_SBsvyhD85#CAW5lME&z%7!l`X%N36>0Py%VuGk z=-whkTJ%p5O-bYj@lgR^HhB38*8G<8Ps??taA}X7jTIJ@Awr3J{4s?D^j*%r7>3Kh zB`V+h_hU-7HQ9=tWfoS8;EHtt`(k*940^vMp7Vp`;2&@^6h|grps@e|002ovPDHLk FV1k#xZCU^T literal 0 HcmV?d00001 diff --git a/Core/src/org/sleuthkit/autopsy/images/info-icon-16.png b/Core/src/org/sleuthkit/autopsy/images/info-icon-16.png new file mode 100644 index 0000000000000000000000000000000000000000..a9e499782c6e78fc6b23d743f4b29baa398699ce GIT binary patch literal 791 zcmV+y1L*vTP)vORuoxkyWZB_J$pHqndVHnyVeiGe9ZsPH}lW;4TAq;4;V8WxxDQq zV9Cw_gaABKQ~2xfAOsff()_E$Vw8Y0k;&Yl-F>8H&5kmpGZ}&7wE%>G5{ZK34?^_A zAd!b2^pL>Z30l99NMPY?1p~&~^9827T+s3wAc{f<1|lmA108Zi1Yu?tLVY(UuxFx# z?(;GNlwxzI*SD3M3N`^?1&~GqNXtXz#tg>Z_hlZGpa8NjKnZ0C|C|ATZ_5i3@a$6w zYD|u1XGUce-HZY8JRpvPt!4wb>WUaaP4_5#oD%?xB1ES>fN4v@$Quw|-l|2&WOJ=+ zzE`bD*3+wSv8GaZ4({yFXZX~!N$^XUVIs*8`92Mb5Qe3$i!P)uuJBqLFPmAPWVIXz z3oUGZH0E8kE-m^%nqLCHyTgl8%Ik63fkuQyiM{wr7 z7GpU~{U9&-!T?Fn?#BLK6)RS@>Nac}NOPRA z6NLk{9iSG@%}8R&Z;RnS{-AG!BOwS5b&kv4$4QYPf4E10TNzTzw_(F;@>~P VS_#VW`A`4=002ovPDHLkV1ju1bi)7u literal 0 HcmV?d00001 diff --git a/Core/src/org/sleuthkit/autopsy/images/warning-icon-16.png b/Core/src/org/sleuthkit/autopsy/images/warning-icon-16.png new file mode 100644 index 0000000000000000000000000000000000000000..42a1625a37d853b12a1bc5e88af7a0f5bbb0ac54 GIT binary patch literal 867 zcmV-p1DyPcP)NfJ$d~M{HdzUYdPMx(Yj{5?1jX{tUm@WI30bXSqm3$gr;R%L+ z%n$$cr*&otU`~$d^O_;aYPbtZLkfz~NeWh@lAC~_s4!RVB!C6aeuipc5~b`TSh><- zZ~ttJ^`xXNzn|mdqM<{N#Gy8IB4ox1kc2&V9g?EKY$Xd$7Eb9Y*?NGoHG`mB#@EM+ zz3lT1Y;brFyCj(k8e3unX@}O-Ms-M_{OT@5RYSPrGq{ymIEyo+U>bHl2XC>8Ll^Dc z?9(0$p8gh>L|ud#Gtd}ohTa^38g4~?`WY#Z5lyWp|9Mi7MXi{FU9jOSI5;}u?qKWQQhHbKg$m8!58JP3Y(?L$uQQW3*rr`W6* za18=ONS6pCK_ghH7(kK*#M))}UI4e|qh{ApcQ~wqU)XWpZC`%I9ewP|{x5O3TIKZa z46-UhCD84wHOLCE`5O~;Hy{XyUk7C7//GEN-BEGIN:initComponents private void initComponents() { @@ -124,11 +134,11 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing super.componentClosed(); /* - Mode mode = WindowManager.getDefault().findMode("dockedBottom"); - if (mode != null) { - mode.dockInto(this); - this.open(); - } + Mode mode = WindowManager.getDefault().findMode("dockedBottom"); + if (mode != null) { + mode.dockInto(this); + this.open(); + } * */ //this.close(); @@ -204,7 +214,6 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing private void registerListeners() { //handle case change Case.addPropertyChangeListener(new PropertyChangeListener() { - @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(Case.CASE_CURRENT_CASE)) { @@ -219,8 +228,7 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing } try { manager.stopAll(); - } - finally { + } finally { //clear inbox clearMessages(); } @@ -257,7 +265,7 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing final String reportActionName = "org.sleuthkit.autopsy.report.ReportAction"; Action reportAction = null; - + //find action by name from action lookup, without introducing cyclic dependency if (choice == JOptionPane.NO_OPTION) { List actions = Utilities.actionsForPath("Toolbars/File"); @@ -270,11 +278,13 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing } } } - - if (reportAction == null) + + if (reportAction == null) { logger.log(Level.SEVERE, "Could not locate Action: " + reportActionName); - else reportAction.actionPerformed(null); - + } else { + reportAction.actionPerformed(null); + } + } } @@ -285,6 +295,24 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing @Override public void displayMessage(IngestMessage ingestMessage) { messagePanel.addMessage(ingestMessage); + + + //post special messages to notification area + MessageType ingestMessageType = ingestMessage.getMessageType(); + if (ingestMessageType.equals(MessageType.ERROR) + || ingestMessageType.equals(MessageType.WARNING)) { + MessageNotifyUtil.MessageType notifyMessageType = + ingestMessageType.equals(MessageType.ERROR) + ? MessageNotifyUtil.MessageType.ERROR + : MessageNotifyUtil.MessageType.WARNING; + + String details = ingestMessage.getDetails(); + if (details == null) { + details = ""; + } + MessageNotifyUtil.Notify.show(ingestMessage.getSubject(), details, + notifyMessageType, showIngestInboxAction); + } } @Override @@ -292,8 +320,6 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing return messagePanel.getMessagesCount(); } - - @Override public void clearMessages() { messagePanel.clearMessages(); @@ -302,9 +328,9 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing @Override public void displayIngestDialog(final Image image) { /* - final IngestDialog ingestDialog = new IngestDialog(); - ingestDialog.setImage(image); - ingestDialog.display(); + final IngestDialog ingestDialog = new IngestDialog(); + ingestDialog.setImage(image); + ingestDialog.display(); */ } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessagesToolbar.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessagesToolbar.java index ef4a89777d..51167f8ef9 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessagesToolbar.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessagesToolbar.java @@ -130,7 +130,10 @@ public class IngestMessagesToolbar extends javax.swing.JPanel { }); } - private void showIngestMessages() { + /** + * Pop up and show ingest messages window + */ + void showIngestMessages() { IngestMessageTopComponent tc = IngestMessageTopComponent.findInstance(); Mode mode = WindowManager.getDefault().findMode("floatingLeftBottom"); From 3f226b3ff2d59af0cf44bc342694aa20609f9527 Mon Sep 17 00:00:00 2001 From: adam-m Date: Wed, 9 Jan 2013 16:45:40 -0500 Subject: [PATCH 27/30] Better error message due to low disk space --- Core/src/org/sleuthkit/autopsy/ingest/IngestMessage.java | 4 ++++ Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessage.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessage.java index 87b24efe3b..1dff6e2167 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessage.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessage.java @@ -241,4 +241,8 @@ public class IngestMessage { static IngestMessage createManagerMessage(String subject, String detailsHtml) { return new IngestMessage(++managerMessageId, MessageType.INFO, null, subject, detailsHtml, null); } + + static IngestMessage createManagerErrorMessage(String subject, String detailsHtml) { + return new IngestMessage(++managerMessageId, MessageType.ERROR, null, subject, detailsHtml, null); + } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java index 95ab451534..ace482edbc 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java @@ -66,7 +66,7 @@ public class IngestMonitor { //TODO add support to monitor multiple drives, e.g. user dir drive in addition to Case drive private class MonitorAction implements ActionListener { - private final static long MIN_FREE_DISK_SPACE = 100L * 1024 * 1024; //100MB + private final static long MIN_FREE_DISK_SPACE = 100L * 1024 * 1024 * 999999; //100MB private File root = new File(File.separator); //default, roto dir where autopsy runs MonitorAction() { @@ -118,7 +118,7 @@ public class IngestMonitor { final String diskPath = root.getAbsolutePath(); logger.log(Level.SEVERE, "Stopping ingest due to low disk space on disk " + diskPath); manager.stopAll(); - manager.postMessage(IngestMessage.createManagerMessage("Stopping ingest due to low disk space on disk " + diskPath, "Stopping ingest due to low disk space on disk " + diskPath + ". Please ensure the drive where Case is located has at least 1GB free space (more for large images) and restart ingest.")); + manager.postMessage(IngestMessage.createManagerErrorMessage("Ingest stopped - low disk space." + diskPath, "Stopping ingest due to low disk space on disk " + diskPath + ". Please ensure the drive where Case is located has at least 1GB free space (more for large images) and restart ingest.")); } } From f87ebd7fb7619567d2925eb382207bebe391c20f Mon Sep 17 00:00:00 2001 From: adam-m Date: Wed, 9 Jan 2013 17:02:59 -0500 Subject: [PATCH 28/30] better notify messages + strip html from ingest messages if present --- .../autopsy/ingest/IngestManager.java | 11 ++++++++++- .../ingest/IngestMessageTopComponent.java | 18 +++++++++++++++++- .../autopsy/ingest/IngestMonitor.java | 7 +++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index 2ce44b0003..eed525a3bb 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -690,7 +690,16 @@ public class IngestManager { sb.append("Errors per module:"); for (IngestModuleAbstract module : errors.keySet()) { final int errorsModule = errors.get(module); - sb.append("\t").append(module.getName()).append(": ").append(errorsModule).append(EOL); + String moduleName; + if (module != null) { + moduleName = module.getName(); + } + else { + //manager message + moduleName = "System"; + } + + sb.append("\t").append(moduleName).append(": ").append(errorsModule).append(EOL); } } return sb.toString(); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageTopComponent.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageTopComponent.java index 6fb37791e4..0cbdad6d77 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageTopComponent.java @@ -24,6 +24,8 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.Action; import javax.swing.BoxLayout; @@ -50,6 +52,7 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing private IngestManager manager; private static String PREFERRED_ID = "IngestMessageTopComponent"; private ActionListener showIngestInboxAction; + private static final Pattern tagRemove = Pattern.compile("<.+?>"); public IngestMessageTopComponent() { initComponents(); @@ -306,11 +309,15 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing ? MessageNotifyUtil.MessageType.ERROR : MessageNotifyUtil.MessageType.WARNING; + String subject = ingestMessage.getSubject(); String details = ingestMessage.getDetails(); if (details == null) { details = ""; } - MessageNotifyUtil.Notify.show(ingestMessage.getSubject(), details, + //strip html tags in case they are present in ingest message + details = stripHtmlTags(details); + + MessageNotifyUtil.Notify.show(subject, details, notifyMessageType, showIngestInboxAction); } } @@ -344,4 +351,13 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing //disable TC toolbar actions return new Action[0]; } + + private static String stripHtmlTags(String string) { + if (string == null || string.length() == 0) { + return string; + } + + Matcher m = tagRemove.matcher(string); + return m.replaceAll(""); + } } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java index ace482edbc..028cf31d14 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java @@ -66,7 +66,7 @@ public class IngestMonitor { //TODO add support to monitor multiple drives, e.g. user dir drive in addition to Case drive private class MonitorAction implements ActionListener { - private final static long MIN_FREE_DISK_SPACE = 100L * 1024 * 1024 * 999999; //100MB + private final static long MIN_FREE_DISK_SPACE = 100L * 1024 * 1024; //100MB private File root = new File(File.separator); //default, roto dir where autopsy runs MonitorAction() { @@ -118,7 +118,10 @@ public class IngestMonitor { final String diskPath = root.getAbsolutePath(); logger.log(Level.SEVERE, "Stopping ingest due to low disk space on disk " + diskPath); manager.stopAll(); - manager.postMessage(IngestMessage.createManagerErrorMessage("Ingest stopped - low disk space." + diskPath, "Stopping ingest due to low disk space on disk " + diskPath + ". Please ensure the drive where Case is located has at least 1GB free space (more for large images) and restart ingest.")); + manager.postMessage(IngestMessage.createManagerErrorMessage + ("Ingest stopped - low disk space on " + diskPath, + "Stopping ingest due to low disk space on disk " + diskPath + + ". \nEnsure the Case drive has at least 1GB free space and restart ingest.")); } } From 7e4a2343e0ffe7b3a0b72fe1c0ad9aa4c7484dec Mon Sep 17 00:00:00 2001 From: adam-m Date: Wed, 9 Jan 2013 17:09:24 -0500 Subject: [PATCH 29/30] better error icon --- .../sleuthkit/autopsy/images/error-icon-16.png | Bin 775 -> 619 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/images/error-icon-16.png b/Core/src/org/sleuthkit/autopsy/images/error-icon-16.png index 54ef8cefacf8ad076129c58c3d94c5dad2c9eb76..e8f8f55fc105d35466e0bf8d6f04134425b24c92 100644 GIT binary patch delta 594 zcmV-Y0ZL7G|y^W@sQ0Q)-B5QfOiuKCJO; z+q6k{uDfUgOSM14k0o@|u30wy0cvBV6=5Nf1mmKlu$b6EW+(##ow?qjQv#Oi!kfG~ zlQX%`IrlvW!G9h!F1aTNh@N>uNSH=I3{#}vg@=s>`6u9`+kd^nO-#JtYA?J#bJ%tFo+~>iXn@ zs&)q^7BEgtyWI&F%l>uq+J*r~ijuz9Y$ivhP~dqlbuS-qI&WRSVhT-aVx`lm(XCvV zZ?&XLi*(3wVY;ik970nfg}5%NQpxmki;xPvuoBm_;@C~RL+3ZgFgGGB`y#}$&qRcR zR$eCL$4fWE$b2!)H#90`+QOfJ2`Y}tWy@&^pXU%YR-;k3CTTaM*|9U+!Ntz7c4USM gSQX778FmhS14#tq678F*$N&HU07*qoM6N<$f|f2H-T(jq delta 751 zcmVoU|iOS6a zn-!uu1g7ANA8rOQ&dV_dyCwcpGJ#_;^tNSEx^f<*ra?Fck=UPSFbE^#aCC~HeyLD! zK9j%+?koAMt1OX>QDK!Ji}0s}Al^dQ24C$GEj}egZ$Cm~fZL<6K2ET?H4|6;5{L=F z`U12N|Fw{`G=G=_lY+VzV-RM`Znn10l2CcT1 zSW^?h7yUfW7Lo|;|4NVAV#jxVF?srXDOucdun}9^X$-?4($HWwZoO~;rD=p)juSn6 zgyD1;N`-TNnZbd4^h2{zN~WUXJ75jG=bqGJc{6hZ>Nt z(FB3LzMjnXc419yIbMmsxf%bdQ|5hI{EoD6Ey9FakV?<3`E1g?GOS6+*tU(l&Q23N z`TQx$YJX*BX_-kfv3)y%t}e!;g+B3?C^yYDUYmofLdw^K#9miNaYqNA`<~$4P$g5f zFxP#Xtg=OnR97?I-Hj&&JkrNmL)I8qV~I_KRK!}FRG@!WgqJNv8yFxxm=HuLJ)MZN zkc{CG-bv;WNp{A-Et0PKCFT4TY4je;W?`D>-e@93TJ%p5O-bYj@lgR^HhB38*8G<8 zPs??taA}X7jTIJ@Awr3J{4s?D^j*%r7>3KhB`V+h_hU-7HQ9=tWfoS8;EHtt`(k*9 h40^vMp7Vp`;2&@^6h|grps@e|002ovPDHLkV1iQMZ0-O6 From 2b0deb68c9de02106ac241fcf7c73b6d273ba8ef Mon Sep 17 00:00:00 2001 From: adam-m Date: Wed, 9 Jan 2013 17:10:43 -0500 Subject: [PATCH 30/30] news --- NEWS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.txt b/NEWS.txt index 473571d9f9..136acb9e1e 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -5,6 +5,7 @@ New features: they can be reported on based on those categories. Improvements: +- Better error reporting in the UI using the notification area. Bugfixes: