diff --git a/Core/manifest.mf b/Core/manifest.mf index 45cb2dbed0..eb49d09c52 100644 --- a/Core/manifest.mf +++ b/Core/manifest.mf @@ -1,8 +1,8 @@ Manifest-Version: 1.0 -OpenIDE-Module: org.sleuthkit.autopsy.core/5 +OpenIDE-Module: org.sleuthkit.autopsy.core/6 OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml -OpenIDE-Module-Implementation-Version: 3 +OpenIDE-Module-Implementation-Version: 4 OpenIDE-Module-Requires: org.openide.windows.WindowManager, org.netbeans.api.javahelp.Help AutoUpdate-Show-In-Client: true AutoUpdate-Essential-Module: true diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index 977c65838c..7b65d77075 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -5,5 +5,5 @@ license.file=../LICENSE-2.0.txt nbm.homepage=http://www.sleuthkit.org/ nbm.module.author=Brian Carrier nbm.needs.restart=true -spec.version.base=3.0 +spec.version.base=4.0 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..e25a539160 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,8 +123,23 @@ 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); + } } + + 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 * @@ -116,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; } @@ -191,8 +239,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()); + } } 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/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/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/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("Source File"); + buffer.append(""); + final Content content = getAssociatedContent(wrapped); + buffer.append(content.getName()); + buffer.append(""); + buffer.append(""); + buffer.append(""); + buffer.append("Source File Path"); + buffer.append(""); + buffer.append(DataConversion.getformattedPath(ContentUtils.getDisplayPath(content), 0, 1)); + buffer.append(""); + buffer.append(""); + buffer.append(""); buffer.append(""); return buffer.toString(); 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/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()); } } 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/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/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..1000da20ff 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,195 @@ 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/tag-folder-blue-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 + * @param comment the tag comment */ - 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(); @@ -62,8 +251,9 @@ public class Tags { * 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 */ - 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(); @@ -91,6 +281,7 @@ public class Tags { /** * 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); @@ -99,6 +290,7 @@ public class Tags { /** * 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); @@ -124,6 +316,7 @@ public class Tags { * 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(); @@ -145,6 +338,7 @@ public class Tags { 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/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..3b2ea33bb4 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-existing 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/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/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/directorytree/TagFileAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagFileAction.java new file mode 100644 index 0000000000..c4628d689b --- /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 (optional):", + "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..cced72519e --- /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 (optional):", + "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/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()); 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 0000000000..e8f8f55fc1 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/error-icon-16.png differ 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 0000000000..a9e499782c Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/info-icon-16.png differ 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 0000000000..42a1625a37 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/warning-icon-16.png differ 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/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/IngestMessageTopComponent.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageTopComponent.java index 1a17dfe19a..0cbdad6d77 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageTopComponent.java @@ -18,10 +18,14 @@ */ package org.sleuthkit.autopsy.ingest; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; 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; @@ -33,6 +37,8 @@ import org.openide.windows.Mode; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType; import org.sleuthkit.datamodel.Image; /** @@ -45,6 +51,8 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing private IngestMessageMainPanel messagePanel; private IngestManager manager; private static String PREFERRED_ID = "IngestMessageTopComponent"; + private ActionListener showIngestInboxAction; + private static final Pattern tagRemove = Pattern.compile("<.+?>"); public IngestMessageTopComponent() { initComponents(); @@ -54,6 +62,13 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing setToolTipText(NbBundle.getMessage(IngestMessageTopComponent.class, "HINT_IngestMessageTopComponent")); //putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE); + showIngestInboxAction = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + IngestMessagesToolbar.getDefault().showIngestMessages(); + } + }; + } private static synchronized IngestMessageTopComponent getDefault() { @@ -79,13 +94,11 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing protected String preferredID() { return PREFERRED_ID; } - - - /** 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. + /** + * 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. */ // //GEN-BEGIN:initComponents private void initComponents() { @@ -124,11 +137,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 +217,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 +231,7 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing } try { manager.stopAll(); - } - finally { + } finally { //clear inbox clearMessages(); } @@ -257,7 +268,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 +281,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 +298,28 @@ 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 subject = ingestMessage.getSubject(); + String details = ingestMessage.getDetails(); + if (details == null) { + details = ""; + } + //strip html tags in case they are present in ingest message + details = stripHtmlTags(details); + + MessageNotifyUtil.Notify.show(subject, details, + notifyMessageType, showIngestInboxAction); + } } @Override @@ -292,8 +327,6 @@ public final class IngestMessageTopComponent extends TopComponent implements Ing return messagePanel.getMessagesCount(); } - - @Override public void clearMessages() { messagePanel.clearMessages(); @@ -302,9 +335,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(); */ } @@ -318,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/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"); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java index 95ab451534..028cf31d14 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java @@ -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.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 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.")); } } 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("[\\/\\:\\?\\*\\\\]", "_"); + } } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 8aca8ece11..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) { @@ -140,9 +139,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 +427,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"); diff --git a/ExifParser/manifest.mf b/ExifParser/manifest.mf index e613aa76c2..be1a6f49a5 100644 --- a/ExifParser/manifest.mf +++ b/ExifParser/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 AutoUpdate-Show-In-Client: true OpenIDE-Module: org.sleuthkit.autopsy.exifparser/3 -OpenIDE-Module-Implementation-Version: 3 +OpenIDE-Module-Implementation-Version: 4 OpenIDE-Module-Layer: org/sleuthkit/autopsy/exifparser/layer.xml OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/exifparser/Bundle.properties diff --git a/ExifParser/nbproject/project.xml b/ExifParser/nbproject/project.xml index 9542df9bcf..7ec5936e8d 100644 --- a/ExifParser/nbproject/project.xml +++ b/ExifParser/nbproject/project.xml @@ -11,8 +11,8 @@ - 5 - 3.0 + 6 + 4.0 diff --git a/HashDatabase/manifest.mf b/HashDatabase/manifest.mf index 0b3c75a34a..3eb4693293 100644 --- a/HashDatabase/manifest.mf +++ b/HashDatabase/manifest.mf @@ -1,7 +1,7 @@ Manifest-Version: 1.0 AutoUpdate-Show-In-Client: true OpenIDE-Module: org.sleuthkit.autopsy.hashdatabase/3 -OpenIDE-Module-Implementation-Version: 3 +OpenIDE-Module-Implementation-Version: 4 OpenIDE-Module-Layer: org/sleuthkit/autopsy/hashdatabase/layer.xml OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/hashdatabase/Bundle.properties diff --git a/HashDatabase/nbproject/project.xml b/HashDatabase/nbproject/project.xml index 1a3d2b30a5..fc2022a50e 100644 --- a/HashDatabase/nbproject/project.xml +++ b/HashDatabase/nbproject/project.xml @@ -77,8 +77,8 @@ - 5 - 3.0 + 6 + 4.0 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/ivy.xml b/KeywordSearch/ivy.xml index 3dac76b7db..b4dbcb7ed9 100644 --- a/KeywordSearch/ivy.xml +++ b/KeywordSearch/ivy.xml @@ -17,9 +17,14 @@ + + + + + diff --git a/KeywordSearch/manifest.mf b/KeywordSearch/manifest.mf index 91df9c8471..c3eb62fc6b 100644 --- a/KeywordSearch/manifest.mf +++ b/KeywordSearch/manifest.mf @@ -1,7 +1,7 @@ Manifest-Version: 1.0 AutoUpdate-Show-In-Client: true OpenIDE-Module: org.sleuthkit.autopsy.keywordsearch/4 -OpenIDE-Module-Implementation-Version: 3 +OpenIDE-Module-Implementation-Version: 4 OpenIDE-Module-Install: org/sleuthkit/autopsy/keywordsearch/Installer.class OpenIDE-Module-Layer: org/sleuthkit/autopsy/keywordsearch/layer.xml OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/keywordsearch/Bundle.properties diff --git a/KeywordSearch/nbproject/project.properties b/KeywordSearch/nbproject/project.properties index 71755d2104..c2673613cd 100644 --- a/KeywordSearch/nbproject/project.properties +++ b/KeywordSearch/nbproject/project.properties @@ -3,4 +3,4 @@ javac.compilerargs=-Xlint -Xlint:-serial license.file=../LICENSE-2.0.txt nbm.homepage=http://www.sleuthkit.org/autopsy/ nbm.needs.restart=true -spec.version.base=2.0 +spec.version.base=2.1 diff --git a/KeywordSearch/nbproject/project.xml b/KeywordSearch/nbproject/project.xml index 36b2e796e9..c0a8fd51d7 100644 --- a/KeywordSearch/nbproject/project.xml +++ b/KeywordSearch/nbproject/project.xml @@ -95,8 +95,8 @@ - 5 - 3.0 + 6 + 4.0 @@ -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 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