diff --git a/Core/src/org/sleuthkit/autopsy/apputils/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/apputils/Bundle.properties-MERGED index d9811e349af4858c24b21530b1b1c3866badee5d..de7c28c9484b69eb6df5a9c4470c6321e5a45814 100644 --- a/Core/src/org/sleuthkit/autopsy/apputils/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/apputils/Bundle.properties-MERGED @@ -1,3 +1,4 @@ CTL_ResetWindowsAction=Reset Windows -ResetWindowAction.confirm.text=The program will close and restart to perform the resetting of window locations.\n\nAre you sure you want to reset all window locations? -ResetWindowAction.confirm.title=Reset Windows +ResetWindowAction.caseCloseFailure.text=Unable to close the current case, the software will restart and the windows locations will reset the next time the software is closed. +ResetWindowAction.caseSaveMetadata.text=Unable to save current case path, the software will restart and the windows locations will reset but the current case will not be opened upon restart. +ResetWindowAction.confirm.text=In order to perform the resetting of window locations the software will close and restart. If a case is currently open, it will be closed. If ingest or a search is currently running, it will be terminated. Are you sure you want to restart the software to reset all window locations? diff --git a/Core/src/org/sleuthkit/autopsy/apputils/ResetWindowsAction.java b/Core/src/org/sleuthkit/autopsy/apputils/ResetWindowsAction.java index 36a9b915df2c36281d8a727414ce08edb4c87505..c5298bc64e848d082a5b4d5dc45c684871dc92b1 100644 --- a/Core/src/org/sleuthkit/autopsy/apputils/ResetWindowsAction.java +++ b/Core/src/org/sleuthkit/autopsy/apputils/ResetWindowsAction.java @@ -20,8 +20,8 @@ import java.io.File; import java.io.IOException; +import java.nio.charset.Charset; import java.util.logging.Level; -import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.apache.commons.io.FileUtils; import org.openide.LifecycleManager; @@ -32,9 +32,10 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; -import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.CaseActionException; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; /** @@ -51,39 +52,66 @@ public final class ResetWindowsAction extends CallableSystemAction { private static final String DISPLAY_NAME = Bundle.CTL_ResetWindowsAction(); private static final long serialVersionUID = 1L; private final static Logger logger = Logger.getLogger(ResetWindowsAction.class.getName()); + private final static String WINDOWS2LOCAL = "Windows2Local"; + private final static String CASE_TO_REOPEN_FILE = "caseToOpen.txt"; @Override public boolean isEnabled() { - return !Case.isCaseOpen(); + return true; } - @NbBundle.Messages({"ResetWindowAction.confirm.title=Reset Windows", - "ResetWindowAction.confirm.text=The program will close and restart to perform the resetting of window locations.\n\nAre you sure you want to reset all window locations?"}) + @NbBundle.Messages({"ResetWindowAction.confirm.text=In order to perform the resetting of window locations the software will close and restart. " + + "If a case is currently open, it will be closed. If ingest or a search is currently running, it will be terminated. " + + "Are you sure you want to restart the software to reset all window locations?", + "ResetWindowAction.caseCloseFailure.text=Unable to close the current case, " + + "the software will restart and the windows locations will reset the next time the software is closed.", + "ResetWindowAction.caseSaveMetadata.text=Unable to save current case path, " + + "the software will restart and the windows locations will reset but the current case will not be opened upon restart."}) @Override public void performAction() { SwingUtilities.invokeLater(() -> { - int response = JOptionPane.showConfirmDialog( - WindowManager.getDefault().getMainWindow(), - Bundle.ResetWindowAction_confirm_text(), - Bundle.ResetWindowAction_confirm_title(), - JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE); - if (response == JOptionPane.YES_OPTION) { + boolean response = MessageNotifyUtil.Message.confirm(Bundle.ResetWindowAction_confirm_text()); + if (response) { + //adding the shutdown hook, closing the current case, and marking for restart can be re-ordered if slightly different behavior is desired Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { try { - FileUtils.deleteDirectory(new File(PlatformUtil.getUserConfigDirectory() + File.separator + "Windows2Local")); + FileUtils.deleteDirectory(new File(PlatformUtil.getUserConfigDirectory() + File.separator + WINDOWS2LOCAL)); } catch (IOException ex) { - logger.log(Level.WARNING, "Unable to delete config directory, window locations will not be reset.", ex); + //While we would like the user to be aware of this in the unlikely event that the directory can not be deleted + //Because our deletion is being attempted in a shutdown hook I don't know that we can pop up UI elements during the shutdown proces + logger.log(Level.SEVERE, "Unable to delete config directory, window locations will not be reset. To manually reset the windows please delete the following directory while the software is closed. " + PlatformUtil.getUserConfigDirectory() + File.separator + "Windows2Local", ex); } } }); - LifecycleManager.getDefault().markForRestart(); - LifecycleManager.getDefault().exit(); + try { + if (Case.isCaseOpen()) { + String caseMetadataFilePath = Case.getCurrentCase().getMetadata().getFilePath().toString(); + File caseToOpenFile = new File(ResetWindowsAction.getCaseToReopenFilePath()); + Charset encoding = null; //prevents writeStringToFile from having ambiguous arguments + FileUtils.writeStringToFile(caseToOpenFile, caseMetadataFilePath, encoding); + Case.closeCurrentCase(); + } + // The method markForRestart can not be undone once it is called. + LifecycleManager.getDefault().markForRestart(); + //we need to call exit last + LifecycleManager.getDefault().exit(); + } catch (CaseActionException ex) { + logger.log(Level.WARNING, Bundle.ResetWindowAction_caseCloseFailure_text(), ex); + MessageNotifyUtil.Message.show(Bundle.ResetWindowAction_caseCloseFailure_text(), MessageNotifyUtil.MessageType.ERROR); + } catch (IOException ex) { + logger.log(Level.WARNING, Bundle.ResetWindowAction_caseSaveMetadata_text(), ex); + MessageNotifyUtil.Message.show(Bundle.ResetWindowAction_caseSaveMetadata_text(), MessageNotifyUtil.MessageType.ERROR); + } } }); } + + public static String getCaseToReopenFilePath(){ + return PlatformUtil.getUserConfigDirectory() + File.separator + CASE_TO_REOPEN_FILE; + } /** * Set this action to be enabled/disabled @@ -91,6 +119,7 @@ public void run() { * @param value whether to enable this action or not */ @Override + public void setEnabled(boolean value) { super.setEnabled(value); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 634e92fbd9cfa12987f1740962430161d438a8b5..528d3a50883e09c4b05254b8d14b9e691356d6de 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -345,6 +345,12 @@ RecentCases.getName.text=Clear Recent Cases RecentItems.openRecentCase.msgDlg.text=Case {0} no longer exists. SelectDataSourceProcessorPanel.name.text=Select Data Source Type StartupWindow.title.text=Welcome +# {0} - autFilePath +StartupWindowProvider.openCase.cantOpen=Unable to open previously open case with metadata file: {0} +# {0} - reOpenFilePath +StartupWindowProvider.openCase.deleteOpenFailure=Unable to open or delete file containing path {0} to previously open case. The previous case will not be opened. +# {0} - autFilePath +StartupWindowProvider.openCase.noFile=Unable to open previously open case because metadata file not found at: {0} UnpackagePortableCaseDialog.title.text=Unpackage Portable Case UnpackagePortableCaseDialog.UnpackagePortableCaseDialog.extensions=Portable case package (.zip, .zip.001) UnpackagePortableCaseDialog.validatePaths.badExtension=File extension must be .zip or .zip.001 diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 3ffae2bd0f528a14e01a076fe30f66327812fe6f..422f76509cea0a0a4d724033cf6a597bc50c452f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -1923,7 +1923,7 @@ public void deleteReports(Collection<? extends Report> reports) throws TskCoreEx * * @return A CaseMetaData object. */ - CaseMetadata getMetadata() { + public CaseMetadata getMetadata() { return metadata; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 5f7ffe9ea7837d82ad9b3f33a2a619604d74dcfb..96f9899dae4273f0e79fe7c96028c7d0cd4ca09f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -218,7 +218,7 @@ public static Path getCaseMetadataFilePath(Path directoryPath) { * * @return The path to the metadata file */ - Path getFilePath() { + public Path getFilePath() { return metadataFilePath; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java b/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java index 9b62bdb0e0dc12cd75387f27ca0a848bac704b97..821beea6b3f975c3c4a064e4f99164115cbd0f5b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java @@ -18,12 +18,18 @@ */ package org.sleuthkit.autopsy.casemodule; +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; import java.util.Collection; import java.util.Iterator; import java.util.logging.Level; -import org.netbeans.spi.sendopts.OptionProcessor; +import javax.swing.SwingUtilities; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; import org.openide.util.Lookup; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.apputils.ResetWindowsAction; import org.sleuthkit.autopsy.commandlineingest.CommandLineIngestManager; import org.sleuthkit.autopsy.commandlineingest.CommandLineOpenCaseManager; import org.sleuthkit.autopsy.commandlineingest.CommandLineOptionProcessor; @@ -61,15 +67,22 @@ public static StartupWindowProvider getInstance() { return instance; } + @NbBundle.Messages({ + "# {0} - autFilePath", + "StartupWindowProvider.openCase.noFile=Unable to open previously open case because metadata file not found at: {0}", + "# {0} - reOpenFilePath", + "StartupWindowProvider.openCase.deleteOpenFailure=Unable to open or delete file containing path {0} to previously open case. The previous case will not be opened.", + "# {0} - autFilePath", + "StartupWindowProvider.openCase.cantOpen=Unable to open previously open case with metadata file: {0}"}) private void init() { if (startupWindowToUse == null) { // first check whether we are running from command line if (isRunningFromCommandLine()) { - + String defaultArg = getDefaultArgument(); - if(defaultArg != null) { - new CommandLineOpenCaseManager(defaultArg).start(); - return; + if (defaultArg != null) { + new CommandLineOpenCaseManager(defaultArg).start(); + return; } else { // Autopsy is running from command line logger.log(Level.INFO, "Running from command line"); //NON-NLS @@ -83,36 +96,41 @@ private void init() { if (RuntimeProperties.runningWithGUI()) { checkSolr(); } - //discover the registered windows Collection<? extends StartupWindowInterface> startupWindows = Lookup.getDefault().lookupAll(StartupWindowInterface.class); int windowsCount = startupWindows.size(); - if (windowsCount == 1) { - startupWindowToUse = startupWindows.iterator().next(); - logger.log(Level.INFO, "Will use the default startup window: " + startupWindowToUse.toString()); //NON-NLS - } else if (windowsCount == 2) { - //pick the non default one - Iterator<? extends StartupWindowInterface> it = startupWindows.iterator(); - while (it.hasNext()) { - StartupWindowInterface window = it.next(); - if (!org.sleuthkit.autopsy.casemodule.StartupWindow.class.isInstance(window)) { - startupWindowToUse = window; - logger.log(Level.INFO, "Will use the custom startup window: " + startupWindowToUse.toString()); //NON-NLS - break; + switch (windowsCount) { + case 1: + startupWindowToUse = startupWindows.iterator().next(); + logger.log(Level.INFO, "Will use the default startup window: {0}", startupWindowToUse.toString()); //NON-NLS + break; + case 2: { + //pick the non default one + Iterator<? extends StartupWindowInterface> it = startupWindows.iterator(); + while (it.hasNext()) { + StartupWindowInterface window = it.next(); + if (!org.sleuthkit.autopsy.casemodule.StartupWindow.class.isInstance(window)) { + startupWindowToUse = window; + logger.log(Level.INFO, "Will use the custom startup window: {0}", startupWindowToUse.toString()); //NON-NLS + break; + } } + break; } - } else { - // select first non-Autopsy start up window - Iterator<? extends StartupWindowInterface> it = startupWindows.iterator(); - while (it.hasNext()) { - StartupWindowInterface window = it.next(); - if (!window.getClass().getCanonicalName().startsWith("org.sleuthkit.autopsy")) { - startupWindowToUse = window; - logger.log(Level.INFO, "Will use the custom startup window: " + startupWindowToUse.toString()); //NON-NLS - break; + default: { + // select first non-Autopsy start up window + Iterator<? extends StartupWindowInterface> it = startupWindows.iterator(); + while (it.hasNext()) { + StartupWindowInterface window = it.next(); + if (!window.getClass().getCanonicalName().startsWith("org.sleuthkit.autopsy")) { + startupWindowToUse = window; + logger.log(Level.INFO, "Will use the custom startup window: {0}", startupWindowToUse.toString()); //NON-NLS + break; + } } + break; } } @@ -121,6 +139,45 @@ private void init() { startupWindowToUse = new org.sleuthkit.autopsy.casemodule.StartupWindow(); } } + File openPreviousCaseFile = new File(ResetWindowsAction.getCaseToReopenFilePath()); + + if (openPreviousCaseFile.exists()) { + //do actual opening on another thread + new Thread(() -> { + String caseFilePath = ""; + String unableToOpenMessage = null; + try { + //avoid readFileToString having ambiguous arguments + Charset encoding = null; + caseFilePath = FileUtils.readFileToString(openPreviousCaseFile, encoding); + if (new File(caseFilePath).exists()) { + FileUtils.forceDelete(openPreviousCaseFile); + //close the startup window as we attempt to open the case + close(); + Case.openAsCurrentCase(caseFilePath); + + } else { + unableToOpenMessage = Bundle.StartupWindowProvider_openCase_noFile(caseFilePath); + logger.log(Level.WARNING, unableToOpenMessage); + } + } catch (IOException ex) { + unableToOpenMessage = Bundle.StartupWindowProvider_openCase_deleteOpenFailure(ResetWindowsAction.getCaseToReopenFilePath()); + logger.log(Level.WARNING, unableToOpenMessage, ex); + } catch (CaseActionException ex) { + unableToOpenMessage = Bundle.StartupWindowProvider_openCase_cantOpen(caseFilePath); + logger.log(Level.WARNING, unableToOpenMessage, ex); + } + + if (RuntimeProperties.runningWithGUI() && !StringUtils.isBlank(unableToOpenMessage)) { + final String message = unableToOpenMessage; + SwingUtilities.invokeLater(() -> { + MessageNotifyUtil.Message.warn(message); + //the case was not opened restore the startup window + open(); + }); + } + }).start(); + } } private void checkSolr() { @@ -147,9 +204,9 @@ private void checkSolr() { * @return True if running from command line, false otherwise */ private boolean isRunningFromCommandLine() { - + CommandLineOptionProcessor processor = Lookup.getDefault().lookup(CommandLineOptionProcessor.class); - if(processor != null) { + if (processor != null) { return processor.isRunFromCommandLine(); } return false; @@ -157,12 +214,12 @@ private boolean isRunningFromCommandLine() { /** * Get the default argument from the CommandLineOptionProcessor. - * - * @return If set, the default argument otherwise null. + * + * @return If set, the default argument otherwise null. */ - private String getDefaultArgument() { + private String getDefaultArgument() { CommandLineOptionProcessor processor = Lookup.getDefault().lookup(CommandLineOptionProcessor.class); - if(processor != null) { + if (processor != null) { return processor.getDefaultArgument(); } return null; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED index 6d7a1dc7ff7303319778c456d2b448420c3fe195..d2a7f32bf7499060696f11cadc1264822c87c390 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED @@ -376,6 +376,10 @@ TagNode.propertySheet.origNameDisplayName=Original Name TagsNode.displayName.text=Tags TagsNode.createSheet.name.name=Name TagsNode.createSheet.name.displayName=Name +UnsupportedContentNode.createSheet.name.desc=no description +UnsupportedContentNode.createSheet.name.displayName=Name +UnsupportedContentNode.createSheet.name.name=Name +UnsupportedContentNode.displayName=Unsupported Content ViewsNode.name.text=Views ViewsNode.createSheet.name.name=Name ViewsNode.createSheet.name.displayName=Name diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java index 4d9f3e08707550d01bcffef6a18caf6ba1761578..3f6706952a39127c16053c80a90b5e91bb31d885 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java @@ -52,8 +52,9 @@ interface ContentNodeVisitor<T> { T visit(BlackboardArtifactNode bban); + T visit(UnsupportedContentNode ucn); + T visit(OsAccountNode bban); - /** * Visitor with an implementable default behavior for all types. Override @@ -126,6 +127,11 @@ public T visit(SlackFileNode sfn) { public T visit(BlackboardArtifactNode bban) { return defaultVisit(bban); } + + @Override + public T visit(UnsupportedContentNode ucn) { + return defaultVisit(ucn); + } @Override public T visit(OsAccountNode bban) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/CreateSleuthkitNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/CreateSleuthkitNodeVisitor.java index b5d808153d52b6f5eec5d1d503faac8f1b781d99..7601f4a88c0d364abcfa2648a669ca65172e207a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/CreateSleuthkitNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/CreateSleuthkitNodeVisitor.java @@ -32,6 +32,7 @@ import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.SleuthkitItemVisitor; import org.sleuthkit.datamodel.SleuthkitVisitableItem; +import org.sleuthkit.datamodel.UnsupportedContent; import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.datamodel.Volume; @@ -99,6 +100,11 @@ public AbstractContentNode<? extends Content> visit(SlackFile sf) { public AbstractContentNode<? extends Content> visit(BlackboardArtifact art) { return new BlackboardArtifactNode(art); } + + @Override + public AbstractContentNode<? extends Content> visit(UnsupportedContent uc) { + return new UnsupportedContentNode(uc); + } @Override protected AbstractContentNode<? extends Content> defaultVisit(SleuthkitVisitableItem di) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index fa87c8df2e075329ac0fe684429cddd3e7c5c050..61bc401ee50eeca54344c35bc6f0c15c9c875599 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -202,6 +202,11 @@ public interface DisplayableItemNodeVisitor<T> { T visit(HostNode node); T visit(DataSourcesByTypeNode node); + + /* + * Unsupported node + */ + T visit(UnsupportedContentNode ucn); /** * Visitor with an implementable default behavior for all types. Override @@ -574,5 +579,10 @@ public T visit(DataSourcesByTypeNode node) { public T visit(PersonGroupingNode node) { return defaultVisit(node); } + + @Override + public T visit(UnsupportedContentNode node) { + return defaultVisit(node); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/UnsupportedContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/UnsupportedContentNode.java new file mode 100644 index 0000000000000000000000000000000000000000..4d8a3473e67b0772fd883ce29a9ca737304116d5 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/UnsupportedContentNode.java @@ -0,0 +1,186 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021 Basis Technology Corp. + * Contact: carrier <at> sleuthkit <dot> 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.datamodel; + +import java.util.ArrayList; +import java.util.List; +import javax.swing.Action; +import org.apache.commons.lang3.tuple.Pair; +import org.openide.nodes.Sheet; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; +import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; +import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.NO_DESCR; +import org.sleuthkit.datamodel.UnsupportedContent; +import org.sleuthkit.datamodel.Tag; + +/** + * This class is used to represent the "Node" for an unsupported content object. + */ +public class UnsupportedContentNode extends AbstractContentNode<UnsupportedContent> { + + /** + * + * @param unsupportedContent underlying Content instance + */ + @NbBundle.Messages({ + "UnsupportedContentNode.displayName=Unsupported Content", + }) + public UnsupportedContentNode(UnsupportedContent unsupportedContent) { + super(unsupportedContent); + + // set name, display name, and icon + this.setDisplayName(Bundle.UnsupportedContentNode_displayName()); + + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon.png"); //NON-NLS + } + + /** + * Right click action for UnsupportedContentNode node + * + * @param popup + * + * @return + */ + @Override + public Action[] getActions(boolean popup) { + List<Action> actionsList = new ArrayList<>(); + + for (Action a : super.getActions(true)) { + actionsList.add(a); + } + + return actionsList.toArray(new Action[actionsList.size()]); + + } + + @NbBundle.Messages({ + "UnsupportedContentNode.createSheet.name.name=Name", + "UnsupportedContentNode.createSheet.name.displayName=Name", + "UnsupportedContentNode.createSheet.name.desc=no description", + }) + @Override + protected Sheet createSheet() { + Sheet sheet = super.createSheet(); + Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES); + if (sheetSet == null) { + sheetSet = Sheet.createPropertiesSet(); + sheet.put(sheetSet); + } + + sheetSet.put(new NodeProperty<>(Bundle.UnsupportedContentNode_createSheet_name_name(), + Bundle.UnsupportedContentNode_createSheet_name_displayName(), + Bundle.UnsupportedContentNode_createSheet_name_desc(), + this.getDisplayName())); + + return sheet; + } + + @Override + public <T> T accept(ContentNodeVisitor<T> visitor) { + return visitor.visit(this); + } + + @Override + public boolean isLeafTypeNode() { + return false; + } + + @Override + public <T> T accept(DisplayableItemNodeVisitor<T> visitor) { + return visitor.visit(this); + } + + @Override + public String getItemType() { + return getClass().getName(); + } + + /** + * Reads and returns a list of all tags associated with this content node. + * + * Null implementation of an abstract method. + * + * @return list of tags associated with the node. + */ + @Override + protected List<Tag> getAllTagsFromDatabase() { + return new ArrayList<>(); + } + + /** + * Returns correlation attribute instance for the underlying content of the + * node. + * + * Null implementation of an abstract method. + * + * @return correlation attribute instance for the underlying content of the + * node. + */ + @Override + protected CorrelationAttributeInstance getCorrelationAttributeInstance() { + return null; + } + + /** + * Returns Score property for the node. + * + * Null implementation of an abstract method. + * + * @param tags list of tags. + * + * @return Score property for the underlying content of the node. + */ + @Override + protected Pair<DataResultViewerTable.Score, String> getScorePropertyAndDescription(List<Tag> tags) { + return Pair.of(DataResultViewerTable.Score.NO_SCORE, NO_DESCR); + } + + /** + * Returns comment property for the node. + * + * Null implementation of an abstract method. + * + * @param tags list of tags + * @param attribute correlation attribute instance + * + * @return Comment property for the underlying content of the node. + */ + @Override + protected DataResultViewerTable.HasCommentStatus getCommentProperty(List<Tag> tags, CorrelationAttributeInstance attribute) { + return DataResultViewerTable.HasCommentStatus.NO_COMMENT; + } + + /** + * Returns occurrences/count property for the node. + * + * Null implementation of an abstract method. + * + * @param attributeType the type of the attribute to count + * @param attributeValue the value of the attribute to coun + * @param defaultDescription a description to use when none is determined by + * the getCountPropertyAndDescription method + * + * @return count property for the underlying content of the node. + */ + @Override + protected Pair<Long, String> getCountPropertyAndDescription(CorrelationAttributeInstance.Type attributeType, String attributeValue, String defaultDescription) { + return Pair.of(-1L, NO_DESCR); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED index c648387016cfbb40fc33eecd6b4b104724538801..0ab883cbd47a0a01c5f4593705f6b1e4339f8748 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED @@ -59,6 +59,7 @@ SelectionContext.views=Views ViewContextAction.errorMessage.cannotFindDirectory=Failed to locate directory. ViewContextAction.errorMessage.cannotFindNode=Failed to locate data source node in tree. ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree. +ViewContextAction.errorMessage.unsupportedParent=Unable to navigate to content not supported in this release. VolumeDetailsPanel.volumeIDLabel.text=Volume ID: VolumeDetailsPanel.volumeIDValue.text=... VolumeDetailsPanel.startValue.text=... diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index a412bb5970b377789d6cc691d1d5a4559ad1aa96..bf99de6183d1c5ceca54056acd41a320af9a5b99 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -304,7 +304,6 @@ public List<Action> visit(BlackboardArtifactNode ban) { NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewFileInDir.text"), c)); } // action to go to the source file of the artifact - // action to go to the source file of the artifact Content fileContent = ban.getLookup().lookup(AbstractFile.class); if (fileContent == null) { Content content = ban.getLookup().lookup(Content.class); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index ca9aa4319876239d1d1e3d3f1e4ed55ea4658963..6fb134ceec9034c1f564942b2dd1778eac3da59a 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -63,6 +63,7 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskDataException; +import org.sleuthkit.datamodel.UnsupportedContent; import org.sleuthkit.datamodel.VolumeSystem; /** @@ -161,7 +162,8 @@ public ViewContextAction(String displayName, Content content) { @Messages({ "ViewContextAction.errorMessage.cannotFindDirectory=Failed to locate directory.", "ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree.", - "ViewContextAction.errorMessage.cannotFindNode=Failed to locate data source node in tree." + "ViewContextAction.errorMessage.cannotFindNode=Failed to locate data source node in tree.", + "ViewContextAction.errorMessage.unsupportedParent=Unable to navigate to content not supported in this release." }) public void actionPerformed(ActionEvent event) { EventQueue.invokeLater(() -> { @@ -181,6 +183,13 @@ public void actionPerformed(ActionEvent event) { logger.log(Level.SEVERE, String.format("Could not get parent of Content object: %s", content), ex); //NON-NLS return; } + + if ((parentContent != null) + && (parentContent instanceof UnsupportedContent)) { + MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_unsupportedParent()); + logger.log(Level.WARNING, String.format("Could not navigate to unsupported content with id: %d", parentContent.getId())); //NON-NLS + return; + } /* * Get the "Data Sources" node from the tree view. diff --git a/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java b/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java index cf02c8e11bf5e7c88fde3adf7ccebdc5a381e702..a50f266c57c44184adfa4d9585353aaf3a3bf7c7 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java @@ -31,6 +31,7 @@ import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.SlackFile; +import org.sleuthkit.datamodel.UnsupportedContent; import org.sleuthkit.datamodel.VirtualDirectory; /** @@ -113,4 +114,9 @@ public Collection<AbstractFile> visit(BlackboardArtifact art) { public Collection<AbstractFile> visit(OsAccount art) { return getAllFromChildren(art); } + + @Override + public Collection<AbstractFile> visit(UnsupportedContent uc) { + return getAllFromChildren(uc); + } }