diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java index ee30eb8283..ae57423b5b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java @@ -20,8 +20,10 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.Component; import java.awt.Dialog; +import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.text.MessageFormat; import java.util.logging.Level; import javax.swing.Action; import javax.swing.ImageIcon; @@ -74,6 +76,7 @@ public final class AddImageAction extends CallableSystemAction implements Presen static final String NOFATORPHANS_PROP = "nofatorphans"; //NON-NLS static final Logger logger = Logger.getLogger(AddImageAction.class.getName()); + static final Dimension SIZE = new Dimension(875, 550); private WizardDescriptor wizardDescriptor; private WizardDescriptor.Iterator iterator; @@ -119,11 +122,14 @@ public final class AddImageAction extends CallableSystemAction implements Presen wizardDescriptor = new WizardDescriptor(iterator); wizardDescriptor.setTitle(NbBundle.getMessage(this.getClass(), "AddImageAction.wizard.title")); wizardDescriptor.putProperty(NAME, e); + wizardDescriptor.setTitleFormat(new MessageFormat("{0}")); if (dialog != null) { dialog.setVisible(false); // hide the old one } dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor); + Dimension d = dialog.getSize(); + dialog.setSize(SIZE); dialog.setVisible(true); dialog.toFront(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.form b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.form index f010a38b65..928cb45a95 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.form @@ -34,13 +34,7 @@ - - - - - - - + @@ -48,35 +42,15 @@ - + - - - + - - - - - - - - - - - - - - - - - - @@ -88,9 +62,9 @@ - + - + @@ -105,8 +79,8 @@ - - + + @@ -132,12 +106,12 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java index 489c713af8..ad02d666a9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java @@ -205,7 +205,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { buttonGroup1 = new javax.swing.ButtonGroup(); jLabel2 = new javax.swing.JLabel(); - nextLabel = new javax.swing.JLabel(); inputPanel = new javax.swing.JPanel(); typeTabel = new javax.swing.JLabel(); typePanel = new javax.swing.JPanel(); @@ -215,12 +214,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { setPreferredSize(new java.awt.Dimension(588, 328)); - org.openide.awt.Mnemonics.setLocalizedText(nextLabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.nextLabel.text")); // NOI18N - nextLabel.setPreferredSize(new java.awt.Dimension(514, 35)); - nextLabel.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - - inputPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - org.openide.awt.Mnemonics.setLocalizedText(typeTabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.typeTabel.text")); // NOI18N typePanel.setMinimumSize(new java.awt.Dimension(0, 65)); @@ -230,11 +223,11 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { typePanel.setLayout(typePanelLayout); typePanelLayout.setHorizontalGroup( typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 544, Short.MAX_VALUE) + .addGap(0, 548, Short.MAX_VALUE) ); typePanelLayout.setVerticalGroup( typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 173, Short.MAX_VALUE) + .addGap(0, 225, Short.MAX_VALUE) ); javax.swing.GroupLayout inputPanelLayout = new javax.swing.GroupLayout(inputPanel); @@ -248,8 +241,8 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { .addComponent(typeTabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(typeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 115, Short.MAX_VALUE)) - .addComponent(typePanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 544, Short.MAX_VALUE)) + .addGap(0, 119, Short.MAX_VALUE)) + .addComponent(typePanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 548, Short.MAX_VALUE)) .addContainerGap()) ); inputPanelLayout.setVerticalGroup( @@ -260,8 +253,8 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { .addComponent(typeTabel) .addComponent(typeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 173, Short.MAX_VALUE) - .addContainerGap()) + .addComponent(typePanel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); @@ -270,28 +263,21 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(inputPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addComponent(nextLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 54, Short.MAX_VALUE))) + .addComponent(inputPanel, 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() - .addGap(39, 39, 39) + .addGap(6, 6, 6) .addComponent(inputPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 24, Short.MAX_VALUE) - .addComponent(nextLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0)) + .addContainerGap(44, Short.MAX_VALUE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; private javax.swing.JPanel inputPanel; private javax.swing.JLabel jLabel2; - private javax.swing.JLabel nextLabel; private javax.swing.JComboBox typeComboBox; private javax.swing.JPanel typePanel; private javax.swing.JLabel typeTabel; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form index d6f2eb1302..2af6e2e533 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form @@ -21,34 +21,19 @@ - - - - + + + - - - - - - - - + - - - - - - - @@ -59,12 +44,12 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java index 1de19dd5d0..f1a0211425 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java @@ -42,7 +42,6 @@ class AddImageWizardIngestConfigVisual extends JPanel { } private void customizeComponents() { - configPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); configPanel.setLayout(new BorderLayout()); configPanel.add(ingestPanel, BorderLayout.CENTER); } @@ -66,24 +65,21 @@ class AddImageWizardIngestConfigVisual extends JPanel { // //GEN-BEGIN:initComponents private void initComponents() { - subtitleLabel = new javax.swing.JLabel(); configPanel = new javax.swing.JPanel(); setPreferredSize(new java.awt.Dimension(569, 300)); - subtitleLabel.setText(org.openide.util.NbBundle.getMessage(AddImageWizardIngestConfigVisual.class, "AddImageWizardIngestConfigVisual.subtitleLabel.text")); // NOI18N - configPanel.setPreferredSize(new java.awt.Dimension(569, 400)); javax.swing.GroupLayout configPanelLayout = new javax.swing.GroupLayout(configPanel); configPanel.setLayout(configPanelLayout); configPanelLayout.setHorizontalGroup( configPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 569, Short.MAX_VALUE) + .addGap(0, 609, Short.MAX_VALUE) ); configPanelLayout.setVerticalGroup( configPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 258, Short.MAX_VALUE) + .addGap(0, 349, Short.MAX_VALUE) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); @@ -91,23 +87,15 @@ class AddImageWizardIngestConfigVisual extends JPanel { layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(subtitleLabel) - .addContainerGap(218, Short.MAX_VALUE)) - .addComponent(configPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(configPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 609, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(subtitleLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(configPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 258, Short.MAX_VALUE) - .addContainerGap()) + .addComponent(configPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel configPanel; - private javax.swing.JLabel subtitleLabel; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index d05018d379..474b7f6ace 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -69,11 +69,9 @@ LocalFilesPanel.selectedPaths.toolTipText= LocalFilesPanel.localFileChooser.approveButtonText=Select LocalFilesPanel.localFileChooser.approveButtonToolTipText= LocalFilesPanel.selectButton.actionCommand=Add -AddImageWizardIngestConfigVisual.subtitleLabel.text=Configure the ingest modules you would like to run on this data source. AddImageWizardAddingProgressVisual.statusLabel.text=Data source has been added to the local database. Files are being analyzed. -AddImageWizardChooseDataSourceVisual.typeTabel.text=Select source type to add: +AddImageWizardChooseDataSourceVisual.typeTabel.text=Select data source type: AddImageWizardChooseDataSourceVisual.jLabel2.text=jLabel2 -AddImageWizardChooseDataSourceVisual.nextLabel.text= Press 'Next' to analyze the input data, extract volume and file system data, and populate a local database. AddImageWizardAddingProgressVisual.progressLabel.text= AddImageWizardAddingProgressVisual.viewLogButton.text=View Log AddImageWizardAddingProgressVisual.subTitle1Label.text=Processing data source and adding it to a local database. File analysis will start when this finishes. @@ -100,7 +98,7 @@ AddImageWizardAddingProgressVisual.getName.text=Add Data Source AddImageWizardAddingProgressVisual.showErrors.critText=*Failed to add data source (critical errors encountered). Click below to view the log. AddImageWizardAddingProgressVisual.showErrors.nonCritText=*Data Source added (non-critical errors encountered). Click below to view the log. AddImageWizardChooseDataSourcePanel.moveFocusNext=Next > -AddImageWizardChooseDataSourceVisual.getName.text=Enter Data Source Information +AddImageWizardChooseDataSourceVisual.getName.text=Select Data Source AddImageWizardIngestConfigPanel.dsProcDone.noErrs.text=*Data Source added. AddImageWizardIngestConfigPanel.dsProcDone.errs.text=*Errors encountered in adding Data Source. AddImageWizardIngestConfigVisual.getName.text=Configure Ingest Modules @@ -219,14 +217,6 @@ RecentItems.openRecentCase.msgDlg.text=Case {0} no longer exists. StartupWindow.title.text=Welcome UpdateRecentCases.menuItem.clearRecentCases.text=Clear Recent Cases UpdateRecentCases.menuItem.empty=-Empty- -XMLCaseManagement.create.exception.msg=Error setting up Case XML file, -XMLCaseManagement.writeFile.exception.noCase.msg=No set case to write management file for. -XMLCaseManagement.writeFile.exception.errWriteToFile.msg=Error writing to case file -XMLCaseManagement.open.exception.errReadXMLFile.msg=Error reading case XML file\: {0} -XMLCaseManagement.open.msgDlg.notAutCase.msg=Error\: This is not an Autopsy config file ("{0}").\n\n\ -Detail\: \n\ -Cannot open a non-Autopsy config file (at {1}). -XMLCaseManagement.open.msgDlg.notAutCase.title=Error AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel ImageFilePanel.errorLabel.text=Error Label DataSourceOnCDriveError.text=Warning\: Path to multi-user data source is on "C\:" drive diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties index 071aafab4c..4a60a9a404 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties @@ -53,11 +53,9 @@ LocalFilesPanel.clearButton.text=\u30af\u30ea\u30a2 LocalFilesPanel.clearButton.toolTipText=\u73fe\u5728\u9078\u629e\u3055\u308c\u3066\u3044\u308b\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9\u304c\u30af\u30ea\u30a2\u3055\u308c\u307e\u3059 LocalFilesPanel.localFileChooser.approveButtonText=\u9078\u629e LocalFilesPanel.selectButton.actionCommand=\u8ffd\u52a0 -AddImageWizardIngestConfigVisual.subtitleLabel.text=\u3053\u306e\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u306b\u5bfe\u3057\u3066\u5b9f\u884c\u3057\u305f\u3044\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u8a2d\u5b9a\u3057\u307e\u3059\u3002 AddImageWizardAddingProgressVisual.statusLabel.text=\u30ed\u30fc\u30ab\u30eb\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u304c\u8ffd\u52a0\u3055\u308c\u307e\u3057\u305f\u3002\u30d5\u30a1\u30a4\u30eb\u3092\u89e3\u6790\u4e2d\u3067\u3059\u3002 AddImageWizardChooseDataSourceVisual.typeTabel.text=\u8ffd\u52a0\u3059\u308b\u30bd\u30fc\u30b9\u30bf\u30a4\u30d7\u3092\u9078\u629e\uff1a AddImageWizardChooseDataSourceVisual.jLabel2.text=jLabel2 -AddImageWizardChooseDataSourceVisual.nextLabel.text= \u300c\u6b21\u3078\u300d\u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u3001\u30a4\u30f3\u30d7\u30c3\u30c8\u30c7\u30fc\u30bf\u3092\u89e3\u6790\u3001\u30dc\u30ea\u30e5\u30fc\u30e0\u304a\u3088\u3073\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u30c7\u30fc\u30bf\u3092\u62bd\u51fa\u3001\u30ed\u30fc\u30ab\u30eb\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u30c7\u30fc\u30bf\u3092\u6295\u5165\u3002 AddImageWizardAddingProgressVisual.progressLabel.text=\uff1c\u30d7\u30ed\u30b0\u30ec\u30b9\uff1e AddImageWizardAddingProgressVisual.viewLogButton.text=\u30ed\u30b0\u3092\u8868\u793a AddImageWizardAddingProgressVisual.subTitle1Label.text=\u30ed\u30fc\u30ab\u30eb\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u60c5\u5831\u3092\u8ffd\u52a0\u4e2d\u3067\u3059\u3002\u3053\u3061\u3089\u304c\u5b8c\u4e86\u6b21\u7b2c\u3001\u30d5\u30a1\u30a4\u30eb\u89e3\u6790\u304c\u59cb\u307e\u308a\u307e\u3059\u3002 @@ -178,14 +176,6 @@ RecentItems.openRecentCase.msgDlg.text=\u30a8\u30e9\u30fc\uff1a\u30b1\u30fc\u30b StartupWindow.title.text=\u3088\u3046\u3053\u305d UpdateRecentCases.menuItem.clearRecentCases.text=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u30af\u30ea\u30a2 UpdateRecentCases.menuItem.empty=-\u7a7a\u767d- -XMLCaseManagement.create.exception.msg=\u30b1\u30fc\u30b9XML\u30d5\u30a1\u30a4\u30eb\u306e\u8a2d\u5b9a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3001 -XMLCaseManagement.writeFile.exception.noCase.msg=\u30de\u30cd\u30b8\u30e1\u30f3\u30c8\u30d5\u30a1\u30a4\u30eb\u3092\u66f8\u304f\u5fc5\u8981\u304c\u3042\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002 -XMLCaseManagement.writeFile.exception.errWriteToFile.msg=\u30b1\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u3078\u306e\u66f8\u304d\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f -XMLCaseManagement.open.exception.errReadXMLFile.msg=\u30b1\u30fc\u30b9XML\u30d5\u30a1\u30a4\u30eb\u306e\u8aad\u307f\u53d6\u308a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a{0} -XMLCaseManagement.open.msgDlg.notAutCase.msg=\u30a8\u30e9\u30fc\uff1aAutopsy\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb("{0}")\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002\n\n\ -\u8a73\u7d30\uff1a\n\ -Autopsy\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u4ee5\u5916\u306f(at {1})\u3067\u958b\u3051\u307e\u305b\u3093\u3002 -XMLCaseManagement.open.msgDlg.notAutCase.title=\u30a8\u30e9\u30fc ImageFilePanel.noFatOrphansCheckbox.text=FAT\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u306e\u30aa\u30fc\u30d5\u30a1\u30f3\u30d5\u30a1\u30a4\u30eb\u306f\u7121\u8996 LocalDiskPanel.noFatOrphansCheckbox.text=FAT\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u306e\u30aa\u30fc\u30d5\u30a1\u30f3\u30d5\u30a1\u30a4\u30eb\u306f\u7121\u8996 AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=\u30ad\u30e3\u30f3\u30bb\u30eb diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 29567cbf5f..2d1d0c0a03 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -48,6 +48,7 @@ import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.apache.commons.io.FileUtils; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException; @@ -260,19 +261,12 @@ public class Case implements SleuthkitCase.ErrorObserver { } }; - private String name; - private String number; - private String examiner; - private String configFilePath; - private final XMLCaseManagement xmlcm; + private final CaseMetadata caseMetadata; private final SleuthkitCase db; // Track the current case (only set with changeCase() method) private static Case currentCase = null; - private final CaseType caseType; private final Services services; private static final Logger logger = Logger.getLogger(Case.class.getName()); - static final String CASE_EXTENSION = "aut"; //NON-NLS - static final String CASE_DOT_EXTENSION = "." + CASE_EXTENSION; private final static String CACHE_FOLDER = "Cache"; //NON-NLS private final static String EXPORT_FOLDER = "Export"; //NON-NLS private final static String LOG_FOLDER = "Log"; //NON-NLS @@ -288,13 +282,8 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Constructor for the Case class */ - private Case(String name, String number, String examiner, String configFilePath, XMLCaseManagement xmlcm, SleuthkitCase db, CaseType type) { - this.name = name; - this.number = number; - this.examiner = examiner; - this.configFilePath = configFilePath; - this.xmlcm = xmlcm; - this.caseType = type; + private Case(CaseMetadata caseMetadata, SleuthkitCase db) { + this.caseMetadata = caseMetadata; this.db = db; this.services = new Services(db); } @@ -365,7 +354,7 @@ public class Case implements SleuthkitCase.ErrorObserver { NbBundle.getMessage(Case.class, "IntervalErrorReport.ErrorText")); doCaseChange(currentCase); SwingUtilities.invokeLater(() -> { - RecentCases.getInstance().addRecentCase(currentCase.name, currentCase.configFilePath); // update the recent cases + RecentCases.getInstance().addRecentCase(currentCase.getName(), currentCase.getCaseMetadata().getFilePath().toString()); // update the recent cases }); if (CaseType.MULTI_USER_CASE == newCase.getCaseType()) { try { @@ -448,8 +437,9 @@ public class Case implements SleuthkitCase.ErrorObserver { * CaseActionException.getCause will return a Throwable * (null otherwise). * - * @throws CaseActionException if there is a problem creating the case. + * @throws CaseActionException if there is a problem creating the case. */ + @Messages({"Case.creationException=Could not create case: failed to make metadata file."}) public static void create(String caseDir, String caseName, String caseNumber, String examiner, CaseType caseType) throws CaseActionException { logger.log(Level.INFO, "Creating case with case directory {0}, caseName {1}", new Object[]{caseDir, caseName}); //NON-NLS @@ -478,14 +468,13 @@ public class Case implements SleuthkitCase.ErrorObserver { /* * Create the case metadata (.aut) file. - * - * TODO (AUT-1885): Replace use of obsolete and unsafe XMLCaseManagement - * class with use of CaseMetadata class. */ - String configFilePath = caseDir + File.separator + caseName + CASE_DOT_EXTENSION; - XMLCaseManagement xmlcm = new XMLCaseManagement(); - xmlcm.create(caseDir, caseName, examiner, caseNumber, caseType, dbName, indexName); - xmlcm.writeFile(); + CaseMetadata metadata; + try { + metadata = new CaseMetadata(caseDir, caseType, caseName, caseNumber, examiner, dbName, indexName); + } catch (CaseMetadataException ex) { + throw new CaseActionException(Bundle.Case_creationException(), ex); + } /* * Create the case database. @@ -515,7 +504,7 @@ public class Case implements SleuthkitCase.ErrorObserver { throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex); } - Case newCase = new Case(caseName, caseNumber, examiner, configFilePath, xmlcm, db, caseType); + Case newCase = new Case(metadata, db); changeCase(newCase); } @@ -598,8 +587,8 @@ public class Case implements SleuthkitCase.ErrorObserver { /* * Verify the extension of the case metadata file. */ - if (!caseMetadataFilePath.endsWith(CASE_DOT_EXTENSION)) { - throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.open.exception.checkFile.msg", CASE_DOT_EXTENSION)); + if (!caseMetadataFilePath.endsWith(CaseMetadata.getFileExtension())) { + throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.open.exception.checkFile.msg", CaseMetadata.getFileExtension())); } try { @@ -607,25 +596,23 @@ public class Case implements SleuthkitCase.ErrorObserver { * Get the case metadata required to open the case database. */ CaseMetadata metadata = new CaseMetadata(Paths.get(caseMetadataFilePath)); - String caseName = metadata.getCaseName(); - String caseNumber = metadata.getCaseNumber(); - String examiner = metadata.getExaminer(); CaseType caseType = metadata.getCaseType(); - String caseDir = metadata.getCaseDirectory(); /* * Open the case database. */ SleuthkitCase db; + String caseDir; if (caseType == CaseType.SINGLE_USER_CASE) { - String dbPath = Paths.get(caseDir, "autopsy.db").toString(); //NON-NLS + String dbPath = metadata.getCaseDatabasePath(); //NON-NLS db = SleuthkitCase.openCase(dbPath); + caseDir = new File(dbPath).getParent(); } else { if (!UserPreferences.getIsMultiUserModeEnabled()) { throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.open.exception.multiUserCaseNotEnabled")); } try { - db = SleuthkitCase.openCase(metadata.getCaseDatabaseName(), UserPreferences.getDatabaseConnectionInfo(), caseDir); + db = SleuthkitCase.openCase(metadata.getCaseDatabaseName(), UserPreferences.getDatabaseConnectionInfo(), metadata.getCaseDirectory()); } catch (UserPreferencesException ex) { throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex); } @@ -674,14 +661,7 @@ public class Case implements SleuthkitCase.ErrorObserver { } } } - - /* - * TODO (AUT-1885): Replace use of obsolete and unsafe - * XMLCaseManagement class with use of CaseMetadata class. - */ - XMLCaseManagement xmlcm = new XMLCaseManagement(); - xmlcm.open(caseMetadataFilePath); - Case openedCase = new Case(caseName, caseNumber, examiner, caseMetadataFilePath, xmlcm, db, caseType); + Case openedCase = new Case(metadata, db); changeCase(openedCase); } catch (CaseMetadataException ex) { @@ -859,7 +839,6 @@ public class Case implements SleuthkitCase.ErrorObserver { changeCase(null); try { services.close(); - this.xmlcm.close(); // close the xmlcm this.db.close(); } catch (Exception e) { throw new CaseActionException(NbBundle.getMessage(this.getClass(), "Case.closeCase.exception.msg"), e); @@ -877,11 +856,9 @@ public class Case implements SleuthkitCase.ErrorObserver { logger.log(Level.INFO, "Deleting case.\ncaseDir: {0}", caseDir); //NON-NLS try { - - xmlcm.close(); // close the xmlcm boolean result = deleteCaseDirectory(caseDir); // delete the directory - RecentCases.getInstance().removeRecentCase(this.name, this.configFilePath); // remove it from the recent case + RecentCases.getInstance().removeRecentCase(this.caseMetadata.getCaseName(), this.caseMetadata.getFilePath().toString()); // remove it from the recent case Case.changeCase(null); if (result == false) { throw new CaseActionException( @@ -906,8 +883,8 @@ public class Case implements SleuthkitCase.ErrorObserver { */ void updateCaseName(String oldCaseName, String oldPath, String newCaseName, String newPath) throws CaseActionException { try { - xmlcm.setCaseName(newCaseName); // set the case - name = newCaseName; // change the local value + getCaseMetadata().setCaseName(newCaseName); // set the case + caseMetadata.setCaseName(newCaseName); // change the local value eventPublisher.publish(new AutopsyEvent(Events.NAME.toString(), oldCaseName, newCaseName)); SwingUtilities.invokeLater(() -> { try { @@ -922,42 +899,6 @@ public class Case implements SleuthkitCase.ErrorObserver { } } - /** - * Updates the case examiner - * - * This should not be called from the EDT. - * - * @param oldExaminer the old examiner - * @param newExaminer the new examiner - */ - void updateExaminer(String oldExaminer, String newExaminer) throws CaseActionException { - try { - xmlcm.setCaseExaminer(newExaminer); // set the examiner - examiner = newExaminer; - eventPublisher.publish(new AutopsyEvent(Events.EXAMINER.toString(), oldExaminer, newExaminer)); - } catch (Exception e) { - throw new CaseActionException(NbBundle.getMessage(this.getClass(), "Case.updateExaminer.exception.msg"), e); - } - } - - /** - * Updates the case number - * - * This should not be called from the EDT. - * - * @param oldCaseNumber the old case number - * @param newCaseNumber the new case number - */ - void updateCaseNumber(String oldCaseNumber, String newCaseNumber) throws CaseActionException { - try { - xmlcm.setCaseNumber(newCaseNumber); // set the case number - number = newCaseNumber; - eventPublisher.publish(new AutopsyEvent(Events.NUMBER.toString(), oldCaseNumber, newCaseNumber)); - } catch (Exception e) { - throw new CaseActionException(NbBundle.getMessage(this.getClass(), "Case.updateCaseNum.exception.msg"), e); - } - } - /** * Checks whether there is a current case open. * @@ -967,24 +908,6 @@ public class Case implements SleuthkitCase.ErrorObserver { return currentCase != null; } - /** - * Uses the given path to store it as the configuration file path - * - * @param givenPath the given config file path - */ - private void setConfigFilePath(String givenPath) { - configFilePath = givenPath; - } - - /** - * Get the config file path in the given path - * - * @return configFilePath the path of the configuration file - */ - String getConfigFilePath() { - return configFilePath; - } - /** * Returns the current version of Autopsy * @@ -994,6 +917,13 @@ public class Case implements SleuthkitCase.ErrorObserver { return autopsyVer; } + /** + * @return the caseMetadata + */ + CaseMetadata getCaseMetadata() { + return caseMetadata; + } + /** * Gets the application name * @@ -1012,7 +942,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return name */ public String getName() { - return name; + return caseMetadata.getCaseName(); } /** @@ -1021,7 +951,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return number */ public String getNumber() { - return number; + return caseMetadata.getCaseNumber(); } /** @@ -1030,7 +960,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return examiner */ public String getExaminer() { - return examiner; + return caseMetadata.getExaminer(); } /** @@ -1039,11 +969,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return caseDirectoryPath */ public String getCaseDirectory() { - if (xmlcm == null) { - return ""; - } else { - return xmlcm.getCaseDirectory(); - } + return caseMetadata.getCaseDirectory(); } /** @@ -1052,7 +978,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return */ public CaseType getCaseType() { - return this.caseType; + return this.getCaseMetadata().getCaseType(); } /** @@ -1170,7 +1096,7 @@ public class Case implements SleuthkitCase.ErrorObserver { private String getHostDirectory() { String caseDirectory = getCaseDirectory(); Path hostPath; - if (caseType == CaseType.MULTI_USER_CASE) { + if (getCaseMetadata().getCaseType() == CaseType.MULTI_USER_CASE) { hostPath = Paths.get(caseDirectory, NetworkUtils.getLocalHostName()); } else { hostPath = Paths.get(caseDirectory); @@ -1241,11 +1167,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return case creation date */ public String getCreatedDate() { - if (xmlcm == null) { - return ""; - } else { - return xmlcm.getCreatedDate(); - } + return getCaseMetadata().getCreatedDate(); } /** @@ -1254,11 +1176,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return Index name. */ public String getTextIndexName() { - if (xmlcm == null) { - return ""; - } else { - return xmlcm.getTextIndexName(); - } + return getCaseMetadata().getTextIndexName(); } /** @@ -1621,7 +1539,7 @@ public class Case implements SleuthkitCase.ErrorObserver { if (RuntimeProperties.coreComponentsAreActive()) { SwingUtilities.invokeLater(() -> { - updateMainWindowTitle(currentCase.name); + updateMainWindowTitle(currentCase.getName()); }); } else { SwingUtilities.invokeLater(() -> { @@ -1754,4 +1672,15 @@ public class Case implements SleuthkitCase.ErrorObserver { return hasData; } + /** + * Gets the full path to the case metadata file for this case. + * + * @return configFilePath The case metadata file path. + * @deprecated Use getCaseMetadata and CaseMetadata.getFilePath instead. + */ + @Deprecated + String getConfigFilePath() { + return getCaseMetadata().getFilePath().toString(); + } + } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseConfigFileInterface.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseConfigFileInterface.java deleted file mode 100644 index 8b7964a76e..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseConfigFileInterface.java +++ /dev/null @@ -1,52 +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.casemodule; - -/** - * NOTE: NOTHING ACTUALLY USES THIS - * - * The interface for the classes that edit the case configuration file - */ -//TODO: check that this can just be deleted. -interface CaseConfigFileInterface { - - public void open(String conFilePath) throws Exception; // opens the confiuation store (XML, DB...) - - public void writeFile() throws Exception; // writes out the configuration to store - - public void close() throws Exception; // close and clear the document handler -// public int[] getImageIDs() throws Exception; // returns a list of image IDs and names -// public int getNextImageID() throws Exception; // returns the next free ID to be assigned to new image, and increments the internal counter - - // all the get and set methods - public String getCaseName() throws Exception; // get the case name - - public void setCaseName(String caseName) throws Exception; // set the case name - - public String getCaseNumber() throws Exception; // get the case number - - public void setCaseNumber(String caseNumber) throws Exception; // set the case number - - public String getCaseExaminer() throws Exception; // get the examiner - - public void setCaseExaminer(String examiner) throws Exception; // set the examiner - - // public void getXXX(); // methods to get the case attributes - // public void setXXX(); // methods to set the case attributes -} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java index 54920ec79e..6ec7c79222 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java @@ -81,8 +81,7 @@ final class CaseDeleteAction extends CallableSystemAction { @Override public void actionPerformed(ActionEvent e) { Case currentCase = Case.getCurrentCase(); - File configFile = new File(currentCase.getConfigFilePath()); - File caseFolder = new File(configFile.getParent()); + File caseFolder = new File(currentCase.getCaseDirectory()); String caseName = currentCase.getName(); if (!caseFolder.exists()) { // throw an error diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 81e53a1fc9..bd07a3deaf 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,98 +18,138 @@ */ package org.sleuthkit.autopsy.casemodule; +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.StringWriter; import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import org.sleuthkit.autopsy.coreutils.Version; +import org.sleuthkit.autopsy.coreutils.XMLUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; /** - * Provides access to case metadata. + * Provides access to the case metadata stored in the case metadata file. */ public final class CaseMetadata { + private static final String FILE_EXTENSION = ".aut"; + private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)"); + private static final String SCHEMA_VERSION_ONE = "1.0"; + private final static String AUTOPSY_CREATED_VERSION_ELEMENT_NAME = "AutopsyCreatedVersion"; //NON-NLS + private final static String CASE_DATABASE_NAME_ELEMENT_NAME = "DatabaseName"; //NON-NLS + private final static String TEXT_INDEX_NAME_ELEMENT = "TextIndexName"; //NON-NLS + private static final String CURRENT_SCHEMA_VERSION = "2.0"; + private final static String ROOT_ELEMENT_NAME = "AutopsyCase"; //NON-NLS + private final static String SCHEMA_VERSION_ELEMENT_NAME = "SchemaVersion"; //NON-NLS + private final static String CREATED_DATE_ELEMENT_NAME = "CreatedDate"; //NON-NLS + private final static String MODIFIED_DATE_ELEMENT_NAME = "ModifiedDate"; //NON-NLS + private final static String AUTOPSY_CREATED_BY_ELEMENT_NAME = "CreatedByAutopsyVersion"; //NON-NLS + private final static String AUTOPSY_SAVED_BY_ELEMENT_NAME = "SavedByAutopsyVersion"; //NON-NLS + private final static String CASE_ELEMENT_NAME = "Case"; //NON-NLS + private final static String CASE_NAME_ELEMENT_NAME = "Name"; //NON-NLS + private final static String CASE_NUMBER_ELEMENT_NAME = "Number"; //NON-NLS + private final static String EXAMINER_ELEMENT_NAME = "Examiner"; //NON-NLS + private final static String CASE_TYPE_ELEMENT_NAME = "CaseType"; //NON-NLS + private final static String CASE_DATABASE_ELEMENT_NAME = "Database"; //NON-NLS + private final static String TEXT_INDEX_ELEMENT = "TextIndex"; //NON-NLS + private final Path metadataFilePath; + private Case.CaseType caseType; + private String caseName; + private String caseNumber; + private String examiner; + private String caseDatabase; + private String textIndexName; + private String createdDate; + private String createdByVersion; + /** - * Exception thrown by the CaseMetadata class when there is a problem - * accessing the metadata for a case. + * Gets the file extension used for case metadata files. + * + * @return The file extension. */ - public final static class CaseMetadataException extends Exception { - - private static final long serialVersionUID = 1L; - - private CaseMetadataException(String message) { - super(message); - } - - private CaseMetadataException(String message, Throwable cause) { - super(message, cause); - } + public static String getFileExtension() { + return FILE_EXTENSION; } - private final Case.CaseType caseType; - private final String caseName; - private final String caseNumber; - private final String examiner; - private final String caseDirectory; - private final String caseDatabaseName; - private final String caseTextIndexName; + /** + * Constructs an object that provides access to the case metadata stored in + * a new case metadata file that is created using the supplied metadata. + * + * @param caseDirectory The case directory. + * @param caseType The type of case. + * @param caseName The name of the case. + * @param caseNumber The case number. + * @param examiner The name of the case examiner. + * @param caseDatabase For a single-user case, the full path to the + * case database file. For a multi-user case, the + * case database name. + * @param caseTextIndexName The text index name. + * + * @throws CaseMetadataException If the new case metadata file cannot be + * created. + */ + CaseMetadata(String caseDirectory, Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDatabase, String caseTextIndexName) throws CaseMetadataException { + metadataFilePath = Paths.get(caseDirectory, caseName + FILE_EXTENSION); + this.caseType = caseType; + this.caseName = caseName; + this.caseNumber = caseNumber; + this.examiner = examiner; + this.caseDatabase = caseDatabase; + this.textIndexName = caseTextIndexName; + createdByVersion = Version.getVersion(); + createdDate = CaseMetadata.DATE_FORMAT.format(new Date()); + writeToFile(); + } /** - * Constructs an object that provides access to case metadata. + * Constructs an object that provides access to the case metadata stored in + * an existing case metadata file. * - * @param metadataFilePath Path to the metadata (.aut) file for a case. + * @param metadataFilePath The full path to the case metadata file. + * + * @throws CaseMetadataException If the new case metadata file cannot be + * read. */ public CaseMetadata(Path metadataFilePath) throws CaseMetadataException { - try { - /* - * TODO (RC): This class should eventually replace the non-public - * and unsafe XMLCaseManagement class altogether. - */ - XMLCaseManagement metadata = new XMLCaseManagement(); - metadata.open(metadataFilePath.toString()); - try { - caseType = metadata.getCaseType(); - } catch (NullPointerException unused) { - throw new CaseMetadataException("Case type element missing"); - } - try { - caseName = metadata.getCaseName(); - if (caseName.isEmpty()) { - throw new CaseMetadataException("Case name missing"); - } - } catch (NullPointerException unused) { - throw new CaseMetadataException("Case name element missing"); - } - try { - caseNumber = metadata.getCaseNumber(); - } catch (NullPointerException unused) { - throw new CaseMetadataException("Case number element missing"); - } - try { - examiner = metadata.getCaseExaminer(); - } catch (NullPointerException unused) { - throw new CaseMetadataException("Examiner element missing"); - } - try { - caseDirectory = metadata.getCaseDirectory(); - if (caseDirectory.isEmpty()) { - throw new CaseMetadataException("Case directory missing"); - } - } catch (NullPointerException unused) { - throw new CaseMetadataException("Case directory element missing"); - } - try { - caseDatabaseName = metadata.getDatabaseName(); - } catch (NullPointerException unused) { - throw new CaseMetadataException("Case database element missing"); - } - try { - caseTextIndexName = metadata.getTextIndexName(); - if (Case.CaseType.MULTI_USER_CASE == caseType && caseDatabaseName.isEmpty()) { - throw new CaseMetadataException("Case keyword search index name missing"); - } - } catch (NullPointerException unused) { - throw new CaseMetadataException("Case keyword search index name missing"); - } - } catch (CaseActionException ex) { - throw new CaseMetadataException(ex.getLocalizedMessage(), ex); - } + this.metadataFilePath = metadataFilePath; + readFromFile(); + } + + /** + * Gets the full path to the case metadata file. + * + * @return The path to the metadata file + */ + Path getFilePath() { + return metadataFilePath; + } + + /** + * Gets the case directory. + * + * @return The case directory. + */ + public String getCaseDirectory() { + return metadataFilePath.getParent().toString(); } /** @@ -118,18 +158,35 @@ public final class CaseMetadata { * @return The case type. */ public Case.CaseType getCaseType() { - return this.caseType; + return caseType; } /** - * Gets the case name. + * Gets the case display name. * - * @return The case name. + * @return The case display name. */ public String getCaseName() { return caseName; } + /** + * Sets the case display name. This does not change the name of the case + * directory, the case database, or the text index name. + * + * @param caseName A case display name. + */ + void setCaseName(String caseName) throws CaseMetadataException { + String oldCaseName = caseName; + this.caseName = caseName; + try { + writeToFile(); + } catch (CaseMetadataException ex) { + this.caseName = oldCaseName; + throw ex; + } + } + /** * Gets the case number. * @@ -149,30 +206,281 @@ public final class CaseMetadata { } /** - * Gets the case directory. + * Gets the name of the case case database. * - * @return The case directory. + * @return The case database name. */ - public String getCaseDirectory() { - return caseDirectory; + public String getCaseDatabaseName() { + if (caseType == Case.CaseType.MULTI_USER_CASE) { + return caseDatabase; + } else { + return Paths.get(caseDatabase).getFileName().toString(); + } } /** - * Gets the case database name. + * Gets the full path to the case database file if the case is a single-user + * case. * - * @return The case database name, will be empty for a single-user case. + * @return The full path to the case database file for a single-user case. + * + * @throws UnsupportedOperationException If called for a multi-user case. */ - public String getCaseDatabaseName() { - return caseDatabaseName; + public String getCaseDatabasePath() throws UnsupportedOperationException { + if (caseType == Case.CaseType.SINGLE_USER_CASE) { + return caseDatabase; + } else { + throw new UnsupportedOperationException(); + } } /** * Gets the text index name. * - * @return The case text index name, will be empty for a single-user case. + * @return The name of the text index for the case. */ public String getTextIndexName() { - return caseTextIndexName; + return textIndexName; + } + + /** + * Gets the date the case was created. + * + * @return The date this case was created as a string + */ + String getCreatedDate() { + return createdDate; + } + + /** + * Sets the date the case was created. Used for preserving the case creation + * date during single-user to multi-user case conversion. + * + * @param createdDate The date the case was created as a string. + */ + void setCreatedDate(String createdDate) throws CaseMetadataException { + String oldCreatedDate = createdDate; + this.createdDate = createdDate; + try { + writeToFile(); + } catch (CaseMetadataException ex) { + this.createdDate = oldCreatedDate; + throw ex; + } + } + + /** + * Gets the Autopsy version that created the case. + * + * @return A build identifier. + */ + String getCreatedByVersion() { + return createdByVersion; + } + + /** + * Sets the Autopsy version that created the case. Used for preserving this + * metadata during single-user to multi-user case conversion. + * + * @param buildVersion An build version identifier. + */ + void setCreatedByVersion(String buildVersion) throws CaseMetadataException { + String oldCreatedByVersion = this.createdByVersion; + this.createdByVersion = buildVersion; + try { + this.writeToFile(); + } catch (CaseMetadataException ex) { + this.createdByVersion = oldCreatedByVersion; + throw ex; + } + } + + /** + * Writes the case metadata to the metadata file. + * + * @throws CaseMetadataException If there is an error writing to the case + * metadata file. + */ + private void writeToFile() throws CaseMetadataException { + try { + /* + * Create the XML DOM. + */ + Document doc = XMLUtil.createDocument(); + createXMLDOM(doc); + doc.normalize(); + + /* + * Prepare the DOM for pretty printing to the metadata file. + */ + Source source = new DOMSource(doc); + StringWriter stringWriter = new StringWriter(); + Result streamResult = new StreamResult(stringWriter); + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //NON-NLS + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); //NON-NLS + transformer.transform(source, streamResult); + + /* + * Write the DOM to the metadata file. + */ + try (BufferedWriter fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(metadataFilePath.toFile())))) { + fileWriter.write(stringWriter.toString()); + fileWriter.flush(); + } + + } catch (ParserConfigurationException | TransformerException | IOException ex) { + throw new CaseMetadataException(String.format("Error writing to case metadata file %s", metadataFilePath), ex); + } + } + + /* + * Creates an XML DOM from the case metadata. + */ + private void createXMLDOM(Document doc) { + /* + * Create the root element and its children. + */ + Element rootElement = doc.createElement(ROOT_ELEMENT_NAME); + doc.appendChild(rootElement); + createChildElement(doc, rootElement, SCHEMA_VERSION_ELEMENT_NAME, CURRENT_SCHEMA_VERSION); + createChildElement(doc, rootElement, CREATED_DATE_ELEMENT_NAME, createdDate); + createChildElement(doc, rootElement, MODIFIED_DATE_ELEMENT_NAME, DATE_FORMAT.format(new Date())); + createChildElement(doc, rootElement, AUTOPSY_CREATED_BY_ELEMENT_NAME, createdByVersion); + createChildElement(doc, rootElement, AUTOPSY_SAVED_BY_ELEMENT_NAME, Version.getVersion()); + Element caseElement = doc.createElement(CASE_ELEMENT_NAME); + rootElement.appendChild(caseElement); + + /* + * Create the children of the case element. + */ + createChildElement(doc, caseElement, CASE_NAME_ELEMENT_NAME, caseName); + createChildElement(doc, caseElement, CASE_NUMBER_ELEMENT_NAME, caseNumber); + createChildElement(doc, caseElement, EXAMINER_ELEMENT_NAME, examiner); + createChildElement(doc, caseElement, CASE_TYPE_ELEMENT_NAME, caseType.toString()); + createChildElement(doc, caseElement, CASE_DATABASE_ELEMENT_NAME, caseDatabase); + createChildElement(doc, caseElement, TEXT_INDEX_ELEMENT, textIndexName); + } + + /** + * Creates an XML element for the case metadata XML DOM. + * + * @param doc The document. + * @param parentElement The parent element of the element to be created. + * @param elementName The name of the element to be created. + * @param elementContent The text content of the element to be created, may + * be empty. + */ + private void createChildElement(Document doc, Element parentElement, String elementName, String elementContent) { + Element element = doc.createElement(elementName); + element.appendChild(doc.createTextNode(elementContent)); + parentElement.appendChild(element); + } + + /** + * Reads the case metadata from the metadata file. + * + * @throws CaseMetadataException If there is an error reading from the case + * metadata file. + */ + private void readFromFile() throws CaseMetadataException { + try { + /* + * Parse the file into an XML DOM and get the root element. + */ + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = builder.parse(this.getFilePath().toFile()); + doc.getDocumentElement().normalize(); + Element rootElement = doc.getDocumentElement(); + if (!rootElement.getNodeName().equals(ROOT_ELEMENT_NAME)) { + throw new CaseMetadataException("Case metadata file corrupted"); + } + + /* + * Get the content of the relevant children of the root element. + */ + String schemaVersion = getElementTextContent(rootElement, SCHEMA_VERSION_ELEMENT_NAME, true); + this.createdDate = getElementTextContent(rootElement, CREATED_DATE_ELEMENT_NAME, true); + if (schemaVersion.equals(SCHEMA_VERSION_ONE)) { + this.createdByVersion = getElementTextContent(rootElement, AUTOPSY_CREATED_VERSION_ELEMENT_NAME, true); + } else { + this.createdByVersion = getElementTextContent(rootElement, AUTOPSY_CREATED_BY_ELEMENT_NAME, true); + } + + /* + * Get the content of the children of the case element. + */ + NodeList caseElements = doc.getElementsByTagName(CASE_ELEMENT_NAME); + if (caseElements.getLength() == 0) { + throw new CaseMetadataException("Case metadata file corrupted"); + } + Element caseElement = (Element) caseElements.item(0); + this.caseName = getElementTextContent(caseElement, CASE_NAME_ELEMENT_NAME, true); + this.caseNumber = getElementTextContent(caseElement, CASE_NUMBER_ELEMENT_NAME, false); + this.examiner = getElementTextContent(caseElement, EXAMINER_ELEMENT_NAME, false); + this.caseType = Case.CaseType.fromString(getElementTextContent(caseElement, CASE_TYPE_ELEMENT_NAME, true)); + if (null == this.caseType) { + throw new CaseMetadataException("Case metadata file corrupted"); + } + if (schemaVersion.equals(SCHEMA_VERSION_ONE)) { + this.caseDatabase = getElementTextContent(caseElement, CASE_DATABASE_NAME_ELEMENT_NAME, true); + this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_NAME_ELEMENT, true); + } else { + this.caseDatabase = getElementTextContent(caseElement, CASE_DATABASE_ELEMENT_NAME, true); + this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_ELEMENT, true); + } + + /* + * Update the file to the current schema, if necessary. + */ + if (!schemaVersion.equals(CURRENT_SCHEMA_VERSION)) { + writeToFile(); + } + + } catch (ParserConfigurationException | SAXException | IOException ex) { + throw new CaseMetadataException(String.format("Error reading from case metadata file %s", metadataFilePath), ex); + } + } + + /** + * Gets the text content of an XML element. + * + * @param parentElement The parent element. + * @param elementName The element name. + * @param contentIsRequired Whether or not the content is required. + * + * @return The text content, may be empty if not required. + * + * @throws CaseMetadataException If the element is missing or content is + * required and it is empty. + */ + private String getElementTextContent(Element parentElement, String elementName, boolean contentIsRequired) throws CaseMetadataException { + NodeList elementsList = parentElement.getElementsByTagName(elementName); + if (elementsList.getLength() == 0) { + throw new CaseMetadataException(String.format("Missing %s element from case metadata file %s", elementName, metadataFilePath)); + } + String textContent = elementsList.item(0).getTextContent(); + if (textContent.isEmpty() && contentIsRequired) { + throw new CaseMetadataException(String.format("Empty %s element in case metadata file %s", elementName, metadataFilePath)); + } + return textContent; + } + + /** + * Exception thrown by the CaseMetadata class when there is a problem + * accessing the metadata for a case. + */ + public final static class CaseMetadataException extends Exception { + + private static final long serialVersionUID = 1L; + + private CaseMetadataException(String message) { + super(message); + } + + private CaseMetadataException(String message, Throwable cause) { + super(message, cause); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java index f879393558..80f89c0fab 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java @@ -54,7 +54,7 @@ public final class CaseOpenAction implements ActionListener { * Constructs an action that opens an existing case. */ public CaseOpenAction() { - caseMetadataFileFilter = new FileNameExtensionFilter(NbBundle.getMessage(CaseOpenAction.class, "CaseOpenAction.autFilter.title", Version.getName(), Case.CASE_DOT_EXTENSION), Case.CASE_EXTENSION); + caseMetadataFileFilter = new FileNameExtensionFilter(NbBundle.getMessage(CaseOpenAction.class, "CaseOpenAction.autFilter.title", Version.getName(), CaseMetadata.getFileExtension()), CaseMetadata.getFileExtension().substring(1)); fileChooser.setDragEnabled(false); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); fileChooser.setMultiSelectionEnabled(false); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java index eae7cf228d..537cd0f3d2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,6 @@ */ package org.sleuthkit.autopsy.casemodule; -import java.awt.*; import java.nio.file.Paths; import java.awt.event.ActionListener; import java.io.File; @@ -41,9 +40,8 @@ import org.openide.NotifyDescriptor; import org.openide.util.actions.CallableSystemAction; /** - * The form where user can change / update the properties of the current case. - * - * @author jantonius + * The form where user can change / update the properties of the current case + * metadata. */ class CasePropertiesForm extends javax.swing.JPanel { @@ -89,8 +87,12 @@ class CasePropertiesForm extends javax.swing.JPanel { caseDirTextArea.setText(caseDir); current = currentCase; - CaseMetadata caseMetadata = new CaseMetadata(Paths.get(currentCase.getConfigFilePath())); - tbDbName.setText(caseMetadata.getCaseDatabaseName()); + CaseMetadata caseMetadata = currentCase.getCaseMetadata(); + if (caseMetadata.getCaseType() == Case.CaseType.SINGLE_USER_CASE) { + tbDbName.setText(caseMetadata.getCaseDatabasePath()); + } else { + tbDbName.setText(caseMetadata.getCaseDatabaseName()); + } Case.CaseType caseType = caseMetadata.getCaseType(); tbDbType.setText(caseType.getLocalizedDisplayName()); if (caseType == Case.CaseType.SINGLE_USER_CASE) { @@ -103,15 +105,16 @@ class CasePropertiesForm extends javax.swing.JPanel { // create the headers and add all the rows // Header names are internationalized via the generated code, do not overwrite. - String[] headers = {imagesTable.getColumnName(0), - imagesTable.getColumnName(1)}; + String[] headers = {imagesTable.getColumnName(0), + imagesTable.getColumnName(1)}; String[][] rows = new String[totalImages][]; int i = 0; for (long key : imgPaths.keySet()) { String path = imgPaths.get(key); String shortenPath = shrinkPath(path, 70); - rows[i++] = new String[]{shortenPath}; + rows[i] = new String[]{shortenPath}; + i++; } // create the table inside with the imgPaths information @@ -124,61 +127,17 @@ class CasePropertiesForm extends javax.swing.JPanel { } }; imagesTable.setModel(model); - -// // set the size of the remove column -// TableColumn removeCol = imagesTable.getColumnModel().getColumn(lastColumn); -// removeCol.setPreferredWidth(75); -// removeCol.setMaxWidth(75); -// removeCol.setMinWidth(75); -// removeCol.setResizable(false); -// // create the delete action to remove the image from the current case -// Action delete = new AbstractAction() -// { -// @Override -// public void actionPerformed(ActionEvent e) -// { -// // get the image path -// JTable table = (JTable)e.getSource(); -// int modelRow = Integer.valueOf(e.getActionCommand()); -// String removeColumn = table.getValueAt(modelRow, lastColumn).toString(); -// // get the image ID -// int selectedID = Integer.parseInt(removeColumn.substring(0, removeColumn.indexOf('|'))); -// String imagePath = removeColumn.substring(removeColumn.indexOf('|') + 1); -// -// // throw the confirmation first -// String confMsg = "Are you sure want to remove image \"" + imagePath + "\" from this case?"; -// NotifyDescriptor d = new NotifyDescriptor.Confirmation(confMsg, "Create directory", NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.WARNING_MESSAGE); -// d.setValue(NotifyDescriptor.NO_OPTION); -// -// Object res = DialogDisplayer.getDefault().notify(d); -// // if user select "Yes" -// if(res != null && res == DialogDescriptor.YES_OPTION){ -// // remove the image in the case class and in the xml config file -// try { -// current.removeImage(selectedID, imagePath); -// } catch (Exception ex) { -// Logger.getLogger(CasePropertiesForm.class.getName()).log(Level.WARNING, "Error: couldn't remove image.", ex); -// } -// // remove the row of the image path -// ((DefaultTableModel)table.getModel()).removeRow(modelRow); -// } -// } -// }; -// -// ButtonColumn buttonColumn = new ButtonColumn(imagesTable, delete, 1, "Remove"); -// buttonColumn.setMnemonic(KeyEvent.VK_D); } - /** - * In this generated code below, there are 2 strings "Path" and "Remove" that are - * table column headers in the DefaultTableModel. When this model is generated, - * it puts the hard coded English strings into the generated code. And then about 15 - * lines later, it separately internationalizes them using: - * imagesTable.getColumnModel().getColumn(0).setHeaderValue(). - * There is no way to prevent the GUI designer from putting the hard coded - * English strings into the generated code. So, they remain, and are not used. + /** + * In this generated code below, there are 2 strings "Path" and "Remove" + * that are table column headers in the DefaultTableModel. When this model + * is generated, it puts the hard coded English strings into the generated + * code. And then about 15 lines later, it separately internationalizes them + * using: imagesTable.getColumnModel().getColumn(0).setHeaderValue(). There + * is no way to prevent the GUI designer from putting the hard coded English + * strings into the generated code. So, they remain, and are not used. */ - /** * 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 @@ -429,9 +388,6 @@ class CasePropertiesForm extends javax.swing.JPanel { private void updateCaseNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_updateCaseNameButtonActionPerformed String oldCaseName = Case.getCurrentCase().getName(); String newCaseName = caseNameTextField.getText(); - //String oldPath = caseDirTextArea.getText() + File.separator + oldCaseName + ".aut"; - //String newPath = caseDirTextArea.getText() + File.separator + newCaseName + ".aut"; - // check if the old and new case name is not equal if (!oldCaseName.equals(newCaseName)) { @@ -469,7 +425,7 @@ class CasePropertiesForm extends javax.swing.JPanel { Object res = DialogDisplayer.getDefault().notify(d); if (res != null && res == DialogDescriptor.YES_OPTION) { // if user select "Yes" - String oldPath = current.getConfigFilePath(); + String oldPath = current.getCaseMetadata().getFilePath().toString(); try { current.updateCaseName(oldCaseName, oldPath, newCaseName, oldPath); } catch (Exception ex) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseSchema.xsd b/Core/src/org/sleuthkit/autopsy/casemodule/CaseSchema.xsd deleted file mode 100644 index 63c9aa49df..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseSchema.xsd +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/RecentCases.java b/Core/src/org/sleuthkit/autopsy/casemodule/RecentCases.java index 2baaf28590..2204da444a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/RecentCases.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/RecentCases.java @@ -408,7 +408,7 @@ final class RecentCases extends CallableSystemAction implements Presenter.Menu { String[] casePaths = new String[LENGTH]; String currentCasePath = null; try { - currentCasePath = Case.getCurrentCase().getConfigFilePath(); + currentCasePath = Case.getCurrentCase().getCaseMetadata().getFilePath().toString(); } catch (IllegalStateException ex) { // in case there is no current case. } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java index 2654a11c27..95d94d1f23 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java @@ -46,7 +46,7 @@ import org.sleuthkit.autopsy.coreutils.NetworkUtils; public class SingleUserCaseConverter { private static final String AUTOPSY_DB_FILE = "autopsy.db"; //NON-NLS - private static final String DOTAUT = ".aut"; //NON-NLS + private static final String DOTAUT = CaseMetadata.getFileExtension(); //NON-NLS private static final String TIMELINE_FOLDER = "Timeline"; //NON-NLS private static final String TIMELINE_FILE = "events.db"; //NON-NLS private static final String POSTGRES_DEFAULT_DB_NAME = "postgres"; //NON-NLS @@ -165,9 +165,8 @@ public class SingleUserCaseConverter { } // Read old xml config - XMLCaseManagement oldXmlCaseManagement = new XMLCaseManagement(); - oldXmlCaseManagement.open(icd.getCaseInputFolder().resolve(icd.getAutFileName()).toString()); - if (oldXmlCaseManagement.getCaseType() == CaseType.MULTI_USER_CASE) { + CaseMetadata oldCaseMetadata = new CaseMetadata(icd.getCaseInputFolder().resolve(icd.getAutFileName())); + if (oldCaseMetadata.getCaseType() == CaseType.MULTI_USER_CASE) { throw new Exception(NbBundle.getMessage(SingleUserCaseConverter.class, "SingleUserCaseConverter.AlreadyMultiUser")); //NON-NLS } @@ -191,15 +190,15 @@ public class SingleUserCaseConverter { copyImages(icd); // Create new .aut file - XMLCaseManagement newXmlCaseManagement = new XMLCaseManagement(); - newXmlCaseManagement.create(icd.getCaseOutputFolder().toString(), + CaseMetadata newCaseMetadata = new CaseMetadata(icd.getCaseOutputFolder().toString(), + CaseType.MULTI_USER_CASE, icd.getNewCaseName(), - oldXmlCaseManagement.getCaseExaminer(), - oldXmlCaseManagement.getCaseNumber(), - CaseType.MULTI_USER_CASE, dbName, solrName); - + oldCaseMetadata.getCaseNumber(), + oldCaseMetadata.getExaminer(), + dbName, solrName); // Set created date. This calls writefile, no need to call it again - newXmlCaseManagement.setCreatedDate(oldXmlCaseManagement.getCreatedDate()); + newCaseMetadata.setCreatedDate(oldCaseMetadata.getCreatedDate()); + newCaseMetadata.setCreatedByVersion(oldCaseMetadata.getCreatedByVersion()); // At this point the import has been finished successfully so we can delete the original case // (if requested). This *should* be fairly safe - at this point we know there was an autopsy file diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java b/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java deleted file mode 100644 index d1e6b87a3a..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java +++ /dev/null @@ -1,814 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2012-2015 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.casemodule; - -import java.io.*; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.logging.Level; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.xml.parsers.*; -import javax.xml.transform.*; -import javax.xml.transform.dom.*; -import javax.xml.transform.stream.*; -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.casemodule.Case.CaseType; -import org.sleuthkit.autopsy.core.RuntimeProperties; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.w3c.dom.*; -import org.xml.sax.SAXException; - -/** - * - * This class is used to create, access, and modify the XML configuration file, - * where we store the information about the case and image(s). This class uses - * the document handler to store the information about the case. The document - * handler will be created / opened when the case configuration file is created/ - * opened. - * - * @author jantonius - */ -class XMLCaseManagement implements CaseConfigFileInterface { - - final static String XSDFILE = "CaseSchema.xsd"; //NON-NLS - final static String TOP_ROOT_NAME = "AutopsyCase"; //NON-NLS - final static String CASE_ROOT_NAME = "Case"; //NON-NLS - // general metadata about the case file - final static String NAME = "Name"; //NON-NLS - final static String NUMBER = "Number"; //NON-NLS - final static String EXAMINER = "Examiner"; //NON-NLS - final static String CREATED_DATE_NAME = "CreatedDate"; //NON-NLS - final static String MODIFIED_DATE_NAME = "ModifiedDate"; //NON-NLS - final static String SCHEMA_VERSION_NAME = "SchemaVersion"; //NON-NLS - final static String AUTOPSY_CRVERSION_NAME = "AutopsyCreatedVersion"; //NON-NLS - final static String AUTOPSY_MVERSION_NAME = "AutopsySavedVersion"; //NON-NLS - final static String CASE_TEXT_INDEX_NAME = "TextIndexName"; //NON-NLS - // folders inside case directory - final static String LOG_FOLDER_NAME = "LogFolder"; //NON-NLS - final static String LOG_FOLDER_RELPATH = "Log"; //NON-NLS - final static String TEMP_FOLDER_NAME = "TempFolder"; //NON-NLS - final static String TEMP_FOLDER_RELPATH = "Temp"; //NON-NLS - final static String EXPORT_FOLDER_NAME = "ExportFolder"; //NON-NLS - final static String EXPORT_FOLDER_RELPATH = "Export"; //NON-NLS - final static String CACHE_FOLDER_NAME = "CacheFolder"; //NON-NLS - final static String CACHE_FOLDER_RELPATH = "Cache"; //NON-NLS - final static String CASE_TYPE = "CaseType"; //NON-NLS - final static String DATABASE_NAME = "DatabaseName"; //NON-NLS - // folders attribute - final static String RELATIVE_NAME = "Relative"; // relevant path info NON-NLS - // folder attr values - final static String RELATIVE_TRUE = "true"; // if it's a relative path NON-NLS - final static String RELATIVE_FALSE = "false"; // if it's not a relative path NON-NLS - // the document - private Document doc; - // general info - private final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)"); - private String caseDirPath; // case directory path - private String caseName; // case name - private String caseNumber; // case number - private String examiner; // examiner name - private final String schemaVersion = "1.0"; - private final String autopsySavedVersion; - private CaseType caseType; // The type of case: local or shared - private String dbName; // The name of the database - private String textIndexName; // The name of the index where extracted text is stored. - - // for error handling - private JPanel caller; - private final String className = this.getClass().toString(); - private static final Logger logger = Logger.getLogger(XMLCaseManagement.class.getName()); - - /** - * The constructor - */ - public XMLCaseManagement() { - autopsySavedVersion = System.getProperty("netbeans.buildnumber"); - } - - /** - * Sets the case directory path of the case directory on the local variable - * - * @param givenPath the new path to be stored as case directory path - */ - private void setCaseDirPath(String givenPath) { - caseDirPath = givenPath; // change this to change the xml file if needed - } - - /** - * Sets the case Name on the XML configuration file - * - * @param givenCaseName the new case name to be set - */ - @Override - public void setCaseName(String givenCaseName) throws CaseActionException { - // change this to change the xml file if needed - Element nameElement = (Element) getCaseElement().getElementsByTagName(NAME).item(0); - nameElement.setTextContent(givenCaseName); - doc.normalize(); - - // edit the modified data - String newDate = dateFormat.format(new Date()); - Element rootEl = getRootElement(); - rootEl.getElementsByTagName(MODIFIED_DATE_NAME).item(0).setTextContent(newDate); - - writeFile(); - - } - - /** - * Sets the case number on the XML configuration file - * - * @param givenCaseNumber the new case number to be set - */ - @Override - public void setCaseNumber(String givenCaseNumber) throws CaseActionException { - // change this to change the xml file if needed - Element nameElement = (Element) getCaseElement().getElementsByTagName(NUMBER).item(0); - nameElement.setTextContent(String.valueOf(givenCaseNumber)); - doc.normalize(); - - // edit the modified data - String newDate = dateFormat.format(new Date()); - Element rootEl = getRootElement(); - rootEl.getElementsByTagName(MODIFIED_DATE_NAME).item(0).setTextContent(newDate); - - writeFile(); - - } - - /** - * Sets the created date on the XML configuration file. This method is for - * preserving the created date when converting a case from single-user to - * multi-user. - * - * @param createdDate the date the case was originally created - * - * @throws org.sleuthkit.autopsy.casemodule.CaseActionException - */ - public void setCreatedDate(String createdDate) throws CaseActionException { - String newDate = dateFormat.format(new Date()); - Element rootEl = getRootElement(); - rootEl.getElementsByTagName(CREATED_DATE_NAME).item(0).setTextContent(createdDate); - rootEl.getElementsByTagName(MODIFIED_DATE_NAME).item(0).setTextContent(newDate); - writeFile(); - } - - /** - * Sets the examiner on the XML configuration file - * - * @param givenExaminer the new examiner to be set - */ - @Override - public void setCaseExaminer(String givenExaminer) throws CaseActionException { - // change this to change the xml file if needed - Element nameElement = (Element) getCaseElement().getElementsByTagName(EXAMINER).item(0); - nameElement.setTextContent(givenExaminer); - doc.normalize(); - - // edit the modified data - String newDate = dateFormat.format(new Date()); - Element rootEl = getRootElement(); - rootEl.getElementsByTagName(MODIFIED_DATE_NAME).item(0).setTextContent(newDate); - - writeFile(); - - } - - /** - * Sets the case name internally (on local variable in this class) - * - * @param givenCaseName the new case name - */ - private void setName(String givenCaseName) { - caseName = givenCaseName; // change this to change the xml file if needed - } - - /** - * Sets the case number internally (on local variable in this class) - * - * @param givenCaseNumber the new case number - */ - private void setNumber(String givenCaseNumber) { - caseNumber = givenCaseNumber; // change this to change the xml file if needed - } - - /** - * Sets the case type internally (on local variable in this class) - * - * @param givenCaseType the new case type - */ - private void setCaseType(CaseType givenCaseType) { - caseType = givenCaseType; // change this to change the xml file if needed - } - - /** - * Gets the case Type from the document handler. Defaults to local if it - * can't figure it out. - * - * @return caseType from the document handler - */ - public CaseType getCaseType() { - if (doc == null) { - return CaseType.SINGLE_USER_CASE; - } else { - if (getCaseElement().getElementsByTagName(CASE_TYPE).getLength() > 0) { - Element nameElement = (Element) getCaseElement().getElementsByTagName(CASE_TYPE).item(0); - return CaseType.fromString(nameElement.getTextContent()); - } else { - return CaseType.SINGLE_USER_CASE; - } - } - } - - /** - * Sets the database name internally (on local variable in this class) - * - * @param givenDbName the new db name - */ - private void setDatabaseName(String givenDbName) { - dbName = givenDbName; // change this to change the xml file if needed - } - - /** - * Gets the database name from the document handler - * - * @return the database name - */ - public String getDatabaseName() { - if (doc == null) { - return ""; - } else { - if (getCaseElement().getElementsByTagName(DATABASE_NAME).getLength() > 0) { - Element nameElement = (Element) getCaseElement().getElementsByTagName(DATABASE_NAME).item(0); - return nameElement.getTextContent(); - } else { - return ""; /// couldn't find one, so return a blank name - } - } - } - - /** - * Sets the text index name internally (on local variable in this class) - * - * @param textIndexName the new name for the index where extracted text is - * stored for the case. - */ - private void setTextIndexName(String textIndexName) { - this.textIndexName = textIndexName; // change this to change the xml file if needed - } - - /** - * Gets the name of the index where extracted text is stored. - * - * @return the index name - */ - public String getTextIndexName() { - if (doc == null) { - return ""; - } else { - if (getCaseElement().getElementsByTagName(CASE_TEXT_INDEX_NAME).getLength() > 0) { - Element nameElement = (Element) getCaseElement().getElementsByTagName(CASE_TEXT_INDEX_NAME).item(0); - return nameElement.getTextContent(); - } else { - return ""; /// couldn't find one, so return a blank index name - } - } - } - - /** - * Sets the examiner name internally (on local variable in this class) - * - * @param givenExaminer the new examiner - */ - private void setExaminer(String givenExaminer) { - examiner = givenExaminer; // change this to change the xml file if needed - } - - /** - * Gets the case Name from the document handler - * - * @return caseName the case name from the document handler - */ - @Override - public String getCaseName() { - if (doc == null) { - return ""; - } else { - Element nameElement = (Element) getCaseElement().getElementsByTagName(NAME).item(0); - String result = nameElement.getTextContent(); - return result; - } - } - - /** - * Gets the case Number from the document handler - * - * @return caseNumber the case number from the document handler - */ - @Override - public String getCaseNumber() { - if (doc == null) { - return ""; - } else { - Element numberElement = (Element) getCaseElement().getElementsByTagName(NUMBER).item(0); - String result = "-1"; - if (numberElement != null) { - result = numberElement.getTextContent(); - } - return result; - } - } - - /** - * Gets the examiner from the document handler - * - * @return examiner the examiner from the document handler - */ - @Override - public String getCaseExaminer() { - if (doc == null) { - return ""; - } else { - Element examinerElement = (Element) getCaseElement().getElementsByTagName(EXAMINER).item(0); - String result = ""; - if (examinerElement != null) { - result = examinerElement.getTextContent(); - } - return result; - } - } - - /** - * Gets the case directory path that's stored in this class - * - * @return caseDirPath the case directory path - */ - public String getCaseDirectory() { - if (doc == null) { - return ""; - } else { - return caseDirPath; - } - // Note: change this to get the case name from the xml file if needed - } - - /** - * Gets the Root Element from the document handler - * - * @return rootElement the root element on the document handler - */ - private Element getRootElement() { - if (doc != null) { - return doc.getDocumentElement(); - } else { - return null; // should throw error or exception - } - } - - /** - * Gets the created Date from the document handler - * - * @return createdDate the creation date of this case - */ - public String getCreatedDate() { - if (doc != null) { - Element crDateElement = (Element) getRootElement().getElementsByTagName(CREATED_DATE_NAME).item(0); - return crDateElement.getTextContent(); - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the Modified Date from the document handler - * - * @return modifiedDate the modification date of this case - */ - protected String getModifiedDate() { - if (doc != null) { - Element mDateElement = (Element) getRootElement().getElementsByTagName(MODIFIED_DATE_NAME).item(0); - return mDateElement.getTextContent(); - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the Autopsy Created Version from the document handler - * - * @return createdVersion the version of autopsy when this case was created - */ - protected String getCreatedVersion() { - if (doc != null) { - Element crVerElement = (Element) getRootElement().getElementsByTagName(AUTOPSY_CRVERSION_NAME).item(0); - return crVerElement.getTextContent(); - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the Autopsy Saved Version from the document handler - * - * @return savedVersion the latest version of autopsy when this case is - * saved - */ - protected String getSavedVersion() { - if (doc != null) { - Element mVerElement = (Element) getRootElement().getElementsByTagName(AUTOPSY_MVERSION_NAME).item(0); - return mVerElement.getTextContent(); - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the Schema Version from the document handler - * - * @return schemaVersion the schema version of this XML configuration file - */ - protected String getSchemaVersion() { - if (doc != null) { - Element schemaVerElement = (Element) getRootElement().getElementsByTagName(SCHEMA_VERSION_NAME).item(0); - return schemaVerElement.getTextContent(); - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the Case Element from the document handler - * - * @return caseElement the "Case" element - */ - private Element getCaseElement() { - if (doc != null) { - return (Element) doc.getElementsByTagName(CASE_ROOT_NAME).item(0); - } else { - return null; // should throw error or exception - } - } - - /** - * Gets the full path to the log directory - * - * @return logDir the full path of the "Log" directory - */ - protected String getLogDir() { - if (doc != null) { - Element logElement = (Element) getCaseElement().getElementsByTagName(LOG_FOLDER_NAME).item(0); - if (logElement.getAttribute(RELATIVE_NAME).equals(RELATIVE_TRUE)) { - return caseDirPath + File.separator + logElement.getTextContent(); - } else { - return logElement.getTextContent(); - } - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the full path to the temp directory - * - * @return tempDir the full path of the "Temp" directory - */ - protected String getTempDir() { - if (doc != null) { - Element tempElement = (Element) getCaseElement().getElementsByTagName(TEMP_FOLDER_NAME).item(0); - if (tempElement.getAttribute(RELATIVE_NAME).equals(RELATIVE_TRUE)) { - return caseDirPath + File.separator + tempElement.getTextContent(); - } else { - return tempElement.getTextContent(); - } - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the full path to the Export directory - * - * @return exportDir the full path of the "Export" directory - */ - protected String getExportDir() { - if (doc != null) { - Element exportElement = (Element) getCaseElement().getElementsByTagName(EXPORT_FOLDER_NAME).item(0); - if (exportElement.getAttribute(RELATIVE_NAME).equals(RELATIVE_TRUE)) { - return caseDirPath + File.separator + exportElement.getTextContent(); - } else { - return exportElement.getTextContent(); - } - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the full path to the Cache directory - * - * @return cacheDir the full path of the "Cache" directory - */ - protected String getCacheDir() { - if (doc != null) { - Element cacheElement = (Element) getCaseElement().getElementsByTagName(CACHE_FOLDER_NAME).item(0); - if (cacheElement.getAttribute(RELATIVE_NAME).equals(RELATIVE_TRUE)) { - return caseDirPath + File.separator + cacheElement.getTextContent(); - } else { - return cacheElement.getTextContent(); - } - } else { - return ""; // should throw error or exception - } - } - - /** - * Initialize the basic values for a new case management file. Note: this is - * the schema version 1.0 - * - * @param dirPath case directory path - * @param caseName the name of the config file to be located in the - * case directory - * @param examiner examiner for the case (optional, can be empty string - * @param caseNumber case number (optional), can be empty - * @param dbName the name of the database. Could be a local path, - * could be a Postgre db name. - * @param textIndexName The name of the index where extracted text is - * stored. - */ - public void create(String dirPath, String caseName, String examiner, String caseNumber, CaseType caseType, String dbName, String textIndexName) throws CaseActionException { - clear(); // clear the previous data - - // set the case Name and Directory and the parent directory - setCaseDirPath(dirPath); - setName(caseName); - setExaminer(examiner); - setNumber(caseNumber); - setCaseType(caseType); - setDatabaseName(dbName); - setTextIndexName(textIndexName); - DocumentBuilder docBuilder; - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); - - // throw an error here - try { - docBuilder = docFactory.newDocumentBuilder(); - } catch (ParserConfigurationException ex) { - clear(); - throw new CaseActionException( - NbBundle.getMessage(this.getClass(), "XMLCaseManagement.create.exception.msg"), ex); - } - - doc = docBuilder.newDocument(); - Element rootElement = doc.createElement(TOP_ROOT_NAME); // ... - doc.appendChild(rootElement); - - Element crDateElement = doc.createElement(CREATED_DATE_NAME); // ... - crDateElement.appendChild(doc.createTextNode(dateFormat.format(new Date()))); - rootElement.appendChild(crDateElement); - - Element mDateElement = doc.createElement(MODIFIED_DATE_NAME); // ... - mDateElement.appendChild(doc.createTextNode(dateFormat.format(new Date()))); - rootElement.appendChild(mDateElement); - - Element autVerElement = doc.createElement(AUTOPSY_CRVERSION_NAME); // ... - autVerElement.appendChild(doc.createTextNode(autopsySavedVersion)); - rootElement.appendChild(autVerElement); - - Element autSavedVerElement = doc.createElement(AUTOPSY_MVERSION_NAME); // ... - autSavedVerElement.appendChild(doc.createTextNode(autopsySavedVersion)); - rootElement.appendChild(autSavedVerElement); - - Element schVerElement = doc.createElement(SCHEMA_VERSION_NAME); // ... - schVerElement.appendChild(doc.createTextNode(schemaVersion)); - rootElement.appendChild(schVerElement); - - Element caseElement = doc.createElement(CASE_ROOT_NAME); // ... - rootElement.appendChild(caseElement); - - Element nameElement = doc.createElement(NAME); // ... - nameElement.appendChild(doc.createTextNode(caseName)); - caseElement.appendChild(nameElement); - - Element numberElement = doc.createElement(NUMBER); // ... - numberElement.appendChild(doc.createTextNode(String.valueOf(caseNumber))); - caseElement.appendChild(numberElement); - - Element examinerElement = doc.createElement(EXAMINER); // ... - examinerElement.appendChild(doc.createTextNode(examiner)); - caseElement.appendChild(examinerElement); - - Element exportElement = doc.createElement(EXPORT_FOLDER_NAME); // ... - exportElement.appendChild(doc.createTextNode(EXPORT_FOLDER_RELPATH)); - exportElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS - caseElement.appendChild(exportElement); - - Element logElement = doc.createElement(LOG_FOLDER_NAME); // ... - logElement.appendChild(doc.createTextNode(LOG_FOLDER_RELPATH)); - logElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS - caseElement.appendChild(logElement); - - Element tempElement = doc.createElement(TEMP_FOLDER_NAME); // ... - tempElement.appendChild(doc.createTextNode(TEMP_FOLDER_RELPATH)); - tempElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS - caseElement.appendChild(tempElement); - - Element cacheElement = doc.createElement(CACHE_FOLDER_NAME); // ... - cacheElement.appendChild(doc.createTextNode(CACHE_FOLDER_RELPATH)); - cacheElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS - caseElement.appendChild(cacheElement); - - Element typeElement = doc.createElement(CASE_TYPE); // ... - typeElement.appendChild(doc.createTextNode(caseType.toString())); - caseElement.appendChild(typeElement); - - Element dbNameElement = doc.createElement(DATABASE_NAME); // ... - dbNameElement.appendChild(doc.createTextNode(dbName)); - caseElement.appendChild(dbNameElement); - - Element indexNameElement = doc.createElement(CASE_TEXT_INDEX_NAME); // ... - indexNameElement.appendChild(doc.createTextNode(textIndexName)); - caseElement.appendChild(indexNameElement); - - // write more code if needed ... - } - - /** - * Writes the case management file to disk (from document handler to .aut - * file) - * - */ - @Override - public void writeFile() throws CaseActionException { - if (doc == null || caseName.equals("")) { - throw new CaseActionException( - NbBundle.getMessage(this.getClass(), "XMLCaseManagement.writeFile.exception.noCase.msg")); - } - - // Prepare the DOM document for writing - Source source = new DOMSource(doc); - - // Prepare the data for the output file - StringWriter sw = new StringWriter(); - Result result = new StreamResult(sw); - - // Write the DOM document to the file - Transformer xformer;// = TransformerFactory.newInstance().newTransformer(); - TransformerFactory tfactory = TransformerFactory.newInstance(); - - try { - xformer = tfactory.newTransformer(); - } catch (TransformerConfigurationException ex) { - logger.log(Level.SEVERE, "Could not setup tranformer and write case file"); //NON-NLS - throw new CaseActionException( - NbBundle.getMessage(this.getClass(), "XMLCaseManagement.writeFile.exception.errWriteToFile.msg"), ex); - } - - //Setup indenting to "pretty print" - xformer.setOutputProperty(OutputKeys.INDENT, "yes"); //NON-NLS - xformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); //NON-NLS - - try { - xformer.transform(source, result); - } catch (TransformerException ex) { - logger.log(Level.SEVERE, "Could not run tranformer and write case file"); //NON-NLS - throw new CaseActionException( - NbBundle.getMessage(this.getClass(), "XMLCaseManagement.writeFile.exception.errWriteToFile.msg"), ex); - } - - // preparing the output file - String xmlString = sw.toString(); - File file = new File(caseDirPath + File.separator + caseName + ".aut"); - - // write the file - try { - BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))); - bw.write(xmlString); - bw.flush(); - bw.close(); - } catch (IOException ex) { - logger.log(Level.SEVERE, "Error writing to case file"); //NON-NLS - throw new CaseActionException( - NbBundle.getMessage(this.getClass(), "XMLCaseManagement.writeFile.exception.errWriteToFile.msg"), ex); - } - } - - /** - * Opens the configuration file and load the document handler Note: this is - * for the schema version 1.0 - * - * @param conFilePath the path of the XML case configuration file path - */ - @Override - public void open(String conFilePath) throws CaseActionException { - clear(); - File file = new File(conFilePath); - - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db; - try { - db = dbf.newDocumentBuilder(); - doc = db.parse(file); - } catch (ParserConfigurationException | SAXException | IOException ex) { - throw new CaseActionException( - NbBundle.getMessage(this.getClass(), "XMLCaseManagement.open.exception.errReadXMLFile.msg", - conFilePath), ex); - } - - doc.getDocumentElement().normalize(); - doc.getDocumentElement().normalize(); - - // TODO: Restore later -// if (!XMLUtil.xmlIsValid(doc, XMLCaseManagement.class, XSDFILE)) { -// logger.log(Level.WARNING, "Could not validate against [" + XSDFILE + "], results may not accurate"); //NON-NLS -// } - Element rootEl = doc.getDocumentElement(); - String rootName = rootEl.getNodeName(); - - // check if it's the autopsy case, if not, throws an error - if (!rootName.equals(TOP_ROOT_NAME)) { - // throw an error ... - clear(); - if (RuntimeProperties.coreComponentsAreActive()) { - - JOptionPane.showMessageDialog(caller, - NbBundle.getMessage(this.getClass(), - "XMLCaseManagement.open.msgDlg.notAutCase.msg", - file.getName(), className), - NbBundle.getMessage(this.getClass(), - "XMLCaseManagement.open.msgDlg.notAutCase.title"), - JOptionPane.ERROR_MESSAGE); - } - } else { - /* - * Autopsy Created Version - */ - String createdVersion = getCreatedVersion(); // get the created version - - // check if it has the same autopsy version as the current one - if (!createdVersion.equals(autopsySavedVersion)) { - // if not the same version, update the saved version in the xml to the current version - getRootElement().getElementsByTagName(AUTOPSY_MVERSION_NAME).item(0).setTextContent(autopsySavedVersion); - } - - /* - * Schema Version - */ - String schemaVer = getSchemaVersion(); - // check if it has the same schema version as the current one - if (!schemaVer.equals(schemaVersion)) { - // do something here if not the same version - // ... @Override - } - - // set the case Directory and Name - setCaseDirPath(file.getParent()); - String fullFileName = file.getName(); - String fileName = fullFileName.substring(0, fullFileName.lastIndexOf(".")); // remove the extension - setName(fileName); - } - } - - /** - * When user wants to close the case. This method writes any changes to the - * XML case configuration file, closes it and the document handler, and - * clears all the local variables / fields. - * - */ - @Override - public void close() throws CaseActionException { - writeFile(); // write any changes to xml - clear(); - } - - /** - * Clear the internal structures / variables - */ - private void clear() { - doc = null; - caseDirPath = ""; - caseName = ""; - caseNumber = ""; - examiner = ""; - caseType = CaseType.SINGLE_USER_CASE; - dbName = ""; - textIndexName = ""; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java index 72378e7c88..d5064e3b4e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java @@ -1,7 +1,7 @@ /* * Sleuth Kit Data Model * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; import org.openide.util.Lookup; -import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -30,87 +29,102 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskDataException; /** - * Provides utility methods for blackboard artifact indexing. + * Represents the blackboard, a place where artifacts and their attributes are + * posted. + * + * NOTE: This API of this class is under development. */ public final class Blackboard implements Closeable { /** - * Index the text associated with the given artifact. + * Indexes the text associated with the an artifact. * * @param artifact The artifact to be indexed. * - * @throws - * org.sleuthkit.autopsy.casemodule.services.Blackboard.BlackboardException + * @throws BlackboardException If there is a problem indexing the artifact. */ public void indexArtifact(BlackboardArtifact artifact) throws BlackboardException { KeywordSearchService searchService = Lookup.getDefault().lookup(KeywordSearchService.class); if (null == searchService) { - throw new BlackboardException(NbBundle.getMessage(this.getClass(), "Blackboard.keywordSearchNotFound.exception.msg")); + throw new BlackboardException("Keyword search service not found"); } - try { searchService.indexArtifact(artifact); } catch (TskCoreException ex) { - throw new BlackboardException(NbBundle.getMessage(this.getClass(), "Blackboard.unableToIndexArtifact.exception.msg"), ex); + throw new BlackboardException("Error indexing artifact", ex); } } /** - * Adds a new artifact type based upon the parameters given + * Gets an artifact type, creating it if it does not already exist. Use this + * method to define custom artifact types. * - * @param typeName The name of the new artifact type - * @param displayName The name displayed for the new attribute type - * @return A type object representing the artifact type added - * @throws - * org.sleuthkit.autopsy.casemodule.services.Blackboard.BlackboardException + * @param typeName The type name of the artifact type. + * @param displayName The display name of the artifact type. + * + * @return A type object representing the artifact type. + * + * @throws BlackboardBlackboardException If there is a problem getting or + * adding the artifact type. */ - public BlackboardArtifact.Type addArtifactType(String typeName, String displayName) throws BlackboardException { + public BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName) throws BlackboardException { try { return Case.getCurrentCase().getSleuthkitCase().addBlackboardArtifactType(typeName, displayName); - } catch (TskCoreException | TskDataException ex) { - throw new BlackboardException("New artifact type could not be added", ex); + } catch (TskDataException typeExistsEx) { + try { + return Case.getCurrentCase().getSleuthkitCase().getArtifactType(typeName); + } catch (TskCoreException ex) { + throw new BlackboardException("Failed to get or add artifact type", ex); + } + } catch (TskCoreException ex) { + throw new BlackboardException("Failed to get or add artifact type", ex); } } /** - * Adds a new attribute type based upon the parameters given + * Gets an attribute type, creating it if it does not already exist. Use + * this method to define custom attribute types. * - * @param attrTypeString The type name of the attribute type - * @param valueType The type of any attribute of this type's value - * @param displayName The name displayed for the new attribute type - * @throws - * org.sleuthkit.autopsy.casemodule.services.Blackboard.BlackboardException + * @param typeName The type name of the attribute type. + * @param valueType The value type of the attribute type. + * @param displayName The display name of the attribute type. + * + * @return A type object representing the attribute type. + * + * @throws BlackboardBlackboardException If there is a problem getting or + * adding the attribute type. */ - public BlackboardAttribute.Type addAttributeType(String attrTypeString, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws BlackboardException { + public BlackboardAttribute.Type getOrAddAttributeType(String typeName, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws BlackboardException { try { - return Case.getCurrentCase().getSleuthkitCase().addArtifactAttributeType(attrTypeString, valueType, displayName); - } catch (TskDataException ex) { - throw new BlackboardException("New attribute type could not be added", ex); + return Case.getCurrentCase().getSleuthkitCase().addArtifactAttributeType(typeName, valueType, displayName); + } catch (TskDataException typeExistsEx) { + try { + return Case.getCurrentCase().getSleuthkitCase().getAttributeType(typeName); + } catch (TskCoreException ex) { + throw new BlackboardException("Failed to get or add attribute type", ex); + } } catch (TskCoreException ex) { - throw new BlackboardException("New attribute type could not be added", ex); + throw new BlackboardException("Failed to get or add attribute type", ex); } } + /** + * Cloese this blackboard and releases any resources associated with it. + * @throws IOException + */ @Override public void close() throws IOException { } /** - * Provides a system exception for the Keyword Search package. + * A blackboard exception. */ public static final class BlackboardException extends Exception { private static final long serialVersionUID = 1L; /** - * Constructs a new exception with null as its message. - */ - public BlackboardException() { - super(); - } - - /** - * Constructs a new exception with the specified message. + * Constructs a blackboard exception with the specified message. * * @param message The message. */ @@ -119,10 +133,11 @@ public final class Blackboard implements Closeable { } /** - * Constructs a new exception with the specified message and cause. + * Constructs a blackboard exception with the specified message and + * cause. * * @param message The message. - * @param cause The cause. + * @param cause The cause. */ public BlackboardException(String message, Throwable cause) { super(message, cause); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index 2d75572fd9..9353ca914b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -19,6 +19,4 @@ TagsManager.addContentTag.noCaseWarning=Failed to publish new content tag event. TagsManager.deleteContentTag.noCaseWarning=Failed to publish content tag deleted event. There is no case open. TagsManager.addBlackboardArtifactTag.noCaseWarning=Failed to publish new blackboard artifact tag event. There is no case open. TagsManager.deleteBlackboardArtifactTag.noCaseWarning=Failed to publish blackboard artifact tag deleted event. There is no case open. -Blackboard.keywordSearchNotFound.exception.msg=Keyword search service not found. -Blackboard.unableToIndexArtifact.exception.msg=Unable to index blackboard artifact Blackboard.unableToIndexArtifact.error.msg=Unable to index blackboard artifact {0} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties index 186fa5f8b4..956a5e6169 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties @@ -1,24 +1,22 @@ -FileManager.findFiles.exception.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -FileManager.findFiles2.exception.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -FileManager.findFiles3.exception.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -FileManager.openFiles.exception.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -FileManager.addDerivedFile.exception.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -FileManager.addCarvedFile.exception.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -FileManager.addLocalFilesDirs.exception.notReadable.msg=\u8FFD\u52A0\u3059\u308B\u30ED\u30FC\u30AB\u30EB\u30D5\u30A1\u30A4\u30EB\uFF0F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u4E2D\u306B\u8AAD\u307F\u53D6\u308C\u306A\u3044\u3082\u306E\u304C\uFF11\u500B\u3042\u308A\u307E\u3059\uFF1A{0}\u3001\u30D5\u30A1\u30A4\u30EB\u304C\u8FFD\u52A0\u3055\u308C\u308B\u524D\u306B\u51E6\u7406\u3092\u4E2D\u6B62\u3057\u307E\u3059 -FileManager.addLocalFilesDirs.exception.cantAdd.msg=\u30ED\u30FC\u30AB\u30EB\u30D5\u30A1\u30A4\u30EB\uFF0F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\uFF11\u500B\u306F\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\uFF1A{0} -FileManager.addLocalFileSetRootDir.exception.errCreateDir.msg=\u30ED\u30FC\u30AB\u30EB\u30D5\u30A1\u30A4\u30EB\u30BB\u30C3\u30C8\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3092\u4F5C\u6210\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u8D77\u3053\u308A\u307E\u3057\u305F\uFF1A {0} -FileManager.addLocalDirInt.exception.closed.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -FileManager.addLocalDirInt.exception.doesntExist.msg=\u5B58\u5728\u3057\u306A\u3044\u30ED\u30FC\u30AB\u30EB\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u8FFD\u52A0\u3092\u8A66\u307F\u307E\u3057\u305F\: {0} -FileManager.addLocalDirInt.exception.notReadable.msg=\u8AAD\u307F\u53D6\u308A\u3067\u304D\u306A\u3044\u30ED\u30FC\u30AB\u30EB\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u8FFD\u52A0\u3092\u8A66\u307F\u307E\u3057\u305F\: {0} -FileManager.addLocalDirInt2.exception.closed.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0} \u30B3\u30F3\u30C6\u30F3\u30C4\u30B5\u30A4\u30BA\u7BC4\u56F2(0 - {1})\u306E\u5916\u3067\u3059 -TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} \u30B3\u30F3\u30C6\u30F3\u30C4\u30B5\u30A4\u30BA\u7BC4\u56F2(0 - {1})\u306E\u5916\u3067\u3059 +FileManager.findFiles.exception.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +FileManager.findFiles2.exception.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +FileManager.findFiles3.exception.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +FileManager.openFiles.exception.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +FileManager.addDerivedFile.exception.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +FileManager.addCarvedFile.exception.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +FileManager.addLocalFilesDirs.exception.notReadable.msg=\u8ffd\u52a0\u3059\u308b\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\uff0f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u4e2d\u306b\u8aad\u307f\u53d6\u308c\u306a\u3044\u3082\u306e\u304c\uff11\u500b\u3042\u308a\u307e\u3059\uff1a{0}\u3001\u30d5\u30a1\u30a4\u30eb\u304c\u8ffd\u52a0\u3055\u308c\u308b\u524d\u306b\u51e6\u7406\u3092\u4e2d\u6b62\u3057\u307e\u3059 +FileManager.addLocalFilesDirs.exception.cantAdd.msg=\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\uff0f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\uff11\u500b\u306f\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\uff1a{0} +FileManager.addLocalFileSetRootDir.exception.errCreateDir.msg=\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\u30bb\u30c3\u30c8\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u4f5c\u6210\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u8d77\u3053\u308a\u307e\u3057\u305f\uff1a {0} +FileManager.addLocalDirInt.exception.closed.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +FileManager.addLocalDirInt.exception.doesntExist.msg=\u5b58\u5728\u3057\u306a\u3044\u30ed\u30fc\u30ab\u30eb\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u8ffd\u52a0\u3092\u8a66\u307f\u307e\u3057\u305f\: {0} +FileManager.addLocalDirInt.exception.notReadable.msg=\u8aad\u307f\u53d6\u308a\u3067\u304d\u306a\u3044\u30ed\u30fc\u30ab\u30eb\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u8ffd\u52a0\u3092\u8a66\u307f\u307e\u3057\u305f\: {0} +FileManager.addLocalDirInt2.exception.closed.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0} \u30b3\u30f3\u30c6\u30f3\u30c4\u30b5\u30a4\u30ba\u7bc4\u56f2(0 - {1})\u306e\u5916\u3067\u3059 +TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} \u30b3\u30f3\u30c6\u30f3\u30c4\u30b5\u30a4\u30ba\u7bc4\u56f2(0 - {1})\u306e\u5916\u3067\u3059 TagsManager.addContentTag.exception.endLTbegin.msg=endByteOffset < beginByteOffset -TagsManager.predefTagNames.bookmark.text=\u30D6\u30C3\u30AF\u30DE\u30FC\u30AF -TagsManager.addContentTag.noCaseWarning=\u65B0\u3057\u3044\u30BF\u30B0\u30A4\u30D9\u30F3\u30C8\u3092\u30D1\u30D6\u30EA\u30C3\u30B7\u30E5\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u958B\u3044\u3066\u3044\u308B\u30B1\u30FC\u30B9\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -TagsManager.deleteContentTag.noCaseWarning=\u524A\u9664\u3055\u308C\u305F\u30A4\u30D9\u30F3\u30C8\u306E\u30BF\u30B0\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u3092\u30D1\u30D6\u30EA\u30C3\u30B7\u30E5\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u958B\u3044\u3066\u3044\u308B\u30B1\u30FC\u30B9\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -TagsManager.addBlackboardArtifactTag.noCaseWarning=\u30A4\u30D9\u30F3\u30C8\u306E\u30BF\u30B0\u306E\u65B0\u3057\u3044blackboard\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u3092\u30D1\u30D6\u30EA\u30C3\u30B7\u30E5\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u958B\u3044\u3066\u3044\u308B\u30B1\u30FC\u30B9\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -TagsManager.deleteBlackboardArtifactTag.noCaseWarning=\u524A\u9664\u3055\u308C\u305F\u30A4\u30D9\u30F3\u30C8\u306E\u30BF\u30B0\u306E\u65B0\u3057\u3044blackboard\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u3092\u30D1\u30D6\u30EA\u30C3\u30B7\u30E5\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u958B\u3044\u3066\u3044\u308B\u30B1\u30FC\u30B9\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -Blackboard.keywordSearchNotFound.exception.msg=\u30AD\u30FC\u30EF\u30FC\u30C9\u691C\u7D22\u30B5\u30FC\u30D3\u30B9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -Blackboard.unableToIndexArtifact.exception.msg=blackboard\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u3092\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -Blackboard.unableToIndexArtifact.error.msg=blackboard\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8{0}\u3092\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 \ No newline at end of file +TagsManager.predefTagNames.bookmark.text=\u30d6\u30c3\u30af\u30de\u30fc\u30af +TagsManager.addContentTag.noCaseWarning=\u65b0\u3057\u3044\u30bf\u30b0\u30a4\u30d9\u30f3\u30c8\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002 +TagsManager.deleteContentTag.noCaseWarning=\u524a\u9664\u3055\u308c\u305f\u30a4\u30d9\u30f3\u30c8\u306e\u30bf\u30b0\u306e\u30b3\u30f3\u30c6\u30f3\u30c4\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002 +TagsManager.addBlackboardArtifactTag.noCaseWarning=\u30a4\u30d9\u30f3\u30c8\u306e\u30bf\u30b0\u306e\u65b0\u3057\u3044blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002 +TagsManager.deleteBlackboardArtifactTag.noCaseWarning=\u524a\u9664\u3055\u308c\u305f\u30a4\u30d9\u30f3\u30c8\u306e\u30bf\u30b0\u306e\u65b0\u3057\u3044blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002 +Blackboard.unableToIndexArtifact.error.msg=blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8{0}\u3092\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form b/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form index 8c0236cde0..6e0df8373e 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form @@ -3,9 +3,13 @@
+ + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index a0aeb51314..f05e555931 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -27,7 +27,7 @@ Format_OperatingSystem_Value={0} version {1} running on {2} LBL_Copyright=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2016.
URL_ON_IMG=http://www.sleuthkit.org/ -URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.0/ +URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.1/ FILE_FOR_LOCAL_HELP=file:/// INDEX_FOR_LOCAL_HELP=/docs/index.html diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java index 9121ad4d23..21e4cb1195 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java @@ -35,6 +35,7 @@ import org.openide.util.Lookup; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.CaseActionException; +import org.sleuthkit.autopsy.casemodule.CaseMetadata; import org.sleuthkit.autopsy.casemodule.OpenFromArguments; import org.sleuthkit.autopsy.coreutils.Logger; @@ -78,7 +79,7 @@ public class Installer extends ModuleInstall { if (processor instanceof OpenFromArguments) { OpenFromArguments argsProcessor = (OpenFromArguments) processor; final String caseFile = argsProcessor.getDefaultArg(); - if (caseFile != null && !caseFile.equals("") && caseFile.endsWith(".aut") && new File(caseFile).exists()) { //NON-NLS + if (caseFile != null && !caseFile.equals("") && caseFile.endsWith(CaseMetadata.getFileExtension()) && new File(caseFile).exists()) { //NON-NLS new Thread(() -> { try { Case.open(caseFile); diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java index 5ac5b95c67..1d58764315 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java @@ -26,10 +26,12 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.SwingWorker; import javax.swing.Timer; +import org.apache.commons.lang3.StringUtils; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.openide.nodes.FilterNode; import org.openide.nodes.Node; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Content; @@ -58,14 +60,12 @@ class ThumbnailViewNode extends FilterNode { @Override public String getDisplayName() { - if (super.getDisplayName().length() > 15) { - return super.getDisplayName().substring(0, 15).concat("..."); - } else { - return super.getDisplayName(); - } + return StringUtils.abbreviate(super.getDisplayName(), 18); } @Override + @NbBundle.Messages({"# {0} - file name", + "ThumbnailViewNode.progressHandle.text=Generating thumbnail for {0}"}) public Image getIcon(int type) { Image icon = null; @@ -82,7 +82,7 @@ class ThumbnailViewNode extends FilterNode { } if (swingWorker == null || swingWorker.isDone()) { swingWorker = new SwingWorker() { - final private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("generating thumbnail for video file " + content.getName()); + final private ProgressHandle progressHandle = ProgressHandleFactory.createHandle(Bundle.ThumbnailViewNode_progressHandle_text(content.getName())); @Override protected Image doInBackground() throws Exception { @@ -97,7 +97,7 @@ class ThumbnailViewNode extends FilterNode { iconCache = new SoftReference<>(super.get()); fireIconChange(); } catch (InterruptedException | ExecutionException ex) { - Logger.getLogger(ThumbnailViewNode.class.getName()).log(Level.SEVERE, "Error getting thumbnail icon", ex); //NON-NLS + Logger.getLogger(ThumbnailViewNode.class.getName()).log(Level.SEVERE, "Error getting thumbnail icon for " + content.getName(), ex); //NON-NLS } finally { progressHandle.finish(); if (timer != null) { diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java b/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java index dd2508a15d..16fde58e29 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java @@ -90,26 +90,21 @@ public final class Logger extends java.util.logging.Logger { fileHandler.setFormatter(new Formatter() { @Override public String format(LogRecord record) { - if (record.getThrown() != null) { - String stackTrace = ""; //NON-NLS + Throwable thrown = record.getThrown(); + String stackTrace = ""; //NON-NLS + while (thrown != null) { + stackTrace += thrown.toString() + "\n"; for (StackTraceElement traceElem : record.getThrown().getStackTrace()) { stackTrace += "\t" + traceElem.toString() + "\n"; //NON-NLS } - return (new Timestamp(record.getMillis())).toString() + " " //NON-NLS - + record.getSourceClassName() + " " //NON-NLS - + record.getSourceMethodName() + "\n" //NON-NLS - + record.getLevel() + ": " //NON-NLS - + this.formatMessage(record) + "\n" //NON-NLS - + record.getThrown().toString() + ":\n" //NON-NLS - + stackTrace - + "\n"; //NON-NLS - } else { - return (new Timestamp(record.getMillis())).toString() + " " //NON-NLS - + record.getSourceClassName() + " " //NON-NLS - + record.getSourceMethodName() + "\n" //NON-NLS - + record.getLevel() + ": " //NON-NLS - + this.formatMessage(record) + "\n"; //NON-NLS + thrown = thrown.getCause(); } + return (new Timestamp(record.getMillis())).toString() + " " //NON-NLS + + record.getSourceClassName() + " " //NON-NLS + + record.getSourceMethodName() + "\n" //NON-NLS + + record.getLevel() + ": " //NON-NLS + + this.formatMessage(record) + "\n" //NON-NLS + + stackTrace; } }); return fileHandler; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index ad71c7e523..dccedb0917 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -23,7 +23,7 @@ IngestJob.progress.fileIngest.displayName=Analyzing files from {0} IngestJob.progress.fileIngest.cancelMessage=Waiting for {0} on {1} IngestJob.progress.cancelling={0} (Cancelling...) IngestJob.cancellationDialog.title=Cancel Ingest -IngestDialog.title.text=Ingest Modules +IngestDialog.title.text=Run Ingest Modules IngestDialog.startButton.title=Start IngestDialog.closeButton.title=Close IngestManager.moduleErr=Module Error @@ -85,9 +85,6 @@ DataSourceIngestCancellationPanel.cancelCurrentModuleRadioButton.text=Cancel cur FileIngestCancellationPanel.cancelIngestJobRadioButton.text=Cancel data source ingest and file ingest FileIngestCancellationPanel.cancelFileIngestRadioButton.text=Cancel file ingest only DataSourceIngestCancellationPanel.cancelAllModulesRadioButton.text=Cancel all ingest modules -IngestJobSettingsPanel.advancedButton.actionCommand=Advanced -IngestJobSettingsPanel.advancedButton.text=Advanced -IngestJobSettingsPanel.descriptionLabel.text= IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.jobID=Job ID IngestJobTableModel.colName.jobID=Job ID IngestJobTableModel.colName.dataSource=Data Source @@ -117,3 +114,8 @@ IngestJob.cancelReason.ingestModStartFail.text=Ingest modules startup failed IngestJob.cancelReason.outOfDiskSpace.text=Out of disk space IngestJob.cancelReason.servicesDown.text=Services Down IngestJob.cancelReason.caseClosed.text=Case closed +IngestJobSettingsPanel.globalSettingsButton.text=Global Settings +gest +IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced +IngestJobSettingsPanel.globalSettingsButton.text=Global Settings +IngestJobSettingsPanel.descriptionLabel.text=dummmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy texxxxxxxxxxxxxxxttttttttttttttttttttttttttttttttttttttttttt diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties index 68034d6409..130c0c3171 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties @@ -68,8 +68,6 @@ IngestProgressSnapshotDialog.title.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30 IngestProgressSnapshotPanel.closeButton.text=\u9589\u3058\u308b IngestProgressSnapshotPanel.refreshButton.text=\u30ea\u30d5\u30ec\u30c3\u30b7\u30e5 IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.activity=\u30a2\u30af\u30c6\u30a3\u30d3\u30c6\u30a3 -IngestJobSettingsPanel.advancedButton.actionCommand=\u30a2\u30c9\u30d0\u30f3\u30b9 -IngestJobSettingsPanel.advancedButton.text=\u30a2\u30c9\u30d0\u30f3\u30b9 ModuleTableModel.colName.duration=\u6240\u8981\u6642\u9593 IngestJob.cancellationDialog.title=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u3092\u30ad\u30e3\u30f3\u30bb\u30eb IngestJobSettings.missingModule.warning=\u4ee5\u524d\u306b\u8aad\u307f\u8fbc\u3093\u3060{0}\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002 @@ -113,3 +111,5 @@ IngestJob.cancelReason.cancelledByUser.text=\u30e6\u30fc\u30b6\u30fc\u304c\u30ad IngestJob.cancelReason.ingestModStartFail.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u306e\u8d77\u52d5\u306b\u5931\u6557 IngestJob.cancelReason.outOfDiskSpace.text=\u30c7\u30a3\u30b9\u30af\u30b9\u30da\u30fc\u30b9\u304c\u8db3\u308a\u307e\u305b\u3093 IngestJob.cancelReason.caseClosed.text=\u30b1\u30fc\u30b9\u3092\u9589\u3058\u307e\u3057\u305f +IngestJobSettingsPanel.globalSettingsButton.actionCommand=\u30a2\u30c9\u30d0\u30f3\u30b9 +IngestJobSettingsPanel.globalSettingsButton.text=\u30a2\u30c9\u30d0\u30f3\u30b9 diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java index 2004674df7..3156314076 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -288,7 +288,7 @@ final class DataSourceIngestJob { String getExecutionContext() { return this.settings.getExecutionContext(); } - + /** * Gets the data source to be ingested by this job. * @@ -379,38 +379,45 @@ final class DataSourceIngestJob { private List startUpIngestPipelines() { List errors = new ArrayList<>(); - // Start up the first stage data source ingest pipeline. + /* + * Start the data-source-level ingest module pipelines. + */ errors.addAll(this.firstStageDataSourceIngestPipeline.startUp()); - - // Start up the second stage data source ingest pipeline. errors.addAll(this.secondStageDataSourceIngestPipeline.startUp()); - // Start up the file ingest pipelines (one per file ingest thread). - for (FileIngestPipeline pipeline : this.fileIngestPipelinesQueue) { - errors.addAll(pipeline.startUp()); - if (!errors.isEmpty()) { - // If there are start up errors, the ingest job will not proceed - // and the errors will ultimately be reported to the user for - // possible remedy so shut down the pipelines now that an - // attempt has been made to start up the data source ingest - // pipeline and at least one copy of the file ingest pipeline. - // pipeline. There is no need to complete starting up all of the - // file ingest pipeline copies since any additional start up - // errors are likely redundant. - while (!this.fileIngestPipelinesQueue.isEmpty()) { - pipeline = this.fileIngestPipelinesQueue.poll(); - if (pipeline.isRunning()) { - List shutDownErrors = pipeline.shutDown(); - if (!shutDownErrors.isEmpty()) { - logIngestModuleErrors(shutDownErrors); + /* + * If the data-source-level ingest pipelines were successfully started, + * start the Start the file-level ingest pipelines (one per file ingest + * thread). + */ + if (errors.isEmpty()) { + for (FileIngestPipeline pipeline : this.fileIngestPipelinesQueue) { + errors.addAll(pipeline.startUp()); + if (!errors.isEmpty()) { + /* + * If there are start up errors, the ingest job will not + * proceed, so shut down any file ingest pipelines that did + * start up. + */ + while (!this.fileIngestPipelinesQueue.isEmpty()) { + FileIngestPipeline startedPipeline = this.fileIngestPipelinesQueue.poll(); + if (startedPipeline.isRunning()) { + List shutDownErrors = startedPipeline.shutDown(); + if (!shutDownErrors.isEmpty()) { + /* + * The start up errors will ultimately be + * reported to the user for possible remedy, but + * the shut down errors are logged here. + */ + logIngestModuleErrors(shutDownErrors); + } } } + break; } - break; } } - logIngestModuleErrors(errors); return errors; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form index 2f769e6f8b..7298579aed 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form @@ -10,10 +10,10 @@ - + - + @@ -31,11 +31,11 @@ - - + + - - + + @@ -48,33 +48,33 @@ - + - - + + - - + + - - - - - + - + + + + + @@ -90,6 +90,9 @@ + + + @@ -129,50 +132,49 @@ - - - - - - - - + + + + + + + + - + - - - + + + + + - - - - - + + - + - + - + - + @@ -196,7 +198,12 @@ - + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index 78c1a214d8..f947c28359 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -25,6 +25,7 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.List; +import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; @@ -32,6 +33,7 @@ import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableColumn; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationDialog; /** @@ -78,6 +80,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { return this.settings; } + @Messages({"IngestJobSettingsPanel.noPerRunSettings=The selected module has no per-run settings."}) private void customizeComponents() { modulesTable.setModel(new IngestModulesTableModel()); modulesTable.setTableHeader(null); @@ -108,19 +111,21 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { if (!listSelectionModel.isSelectionEmpty()) { int index = listSelectionModel.getMinSelectionIndex(); selectedModule = modules.get(index); - simplePanel.removeAll(); + ingestSettingsPanel.removeAll(); if (null != selectedModule.getModuleSettingsPanel()) { - simplePanel.add(selectedModule.getModuleSettingsPanel()); + ingestSettingsPanel.add(selectedModule.getModuleSettingsPanel()); + } else { + ingestSettingsPanel.add(new JLabel(Bundle.IngestJobSettingsPanel_noPerRunSettings())); } - simplePanel.revalidate(); - simplePanel.repaint(); - advancedButton.setEnabled(null != selectedModule.getGlobalSettingsPanel()); + ingestSettingsPanel.revalidate(); + ingestSettingsPanel.repaint(); + globalSettingsButton.setEnabled(null != selectedModule.getGlobalSettingsPanel()); descriptionLabel.setText(selectedModule.getDescription()); descriptionLabel.setToolTipText(selectedModule.getDescription()); } } }); - + modulesTable.setRowSelectionInterval(0, 0); processUnallocCheckbox.setSelected(this.settings.getProcessUnallocatedSpace()); } @@ -137,20 +142,21 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { modulesScrollPane = new javax.swing.JScrollPane(); modulesTable = new javax.swing.JTable(); jPanel1 = new javax.swing.JPanel(); - advancedButton = new javax.swing.JButton(); + globalSettingsButton = new javax.swing.JButton(); jSeparator2 = new javax.swing.JSeparator(); descriptionLabel = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); - simplePanel = new javax.swing.JPanel(); + ingestSettingsPanel = new javax.swing.JPanel(); jButtonSelectAll = new javax.swing.JButton(); jButtonDeselectAll = new javax.swing.JButton(); processUnallocCheckbox = new javax.swing.JCheckBox(); setMaximumSize(new java.awt.Dimension(5750, 3000)); - setMinimumSize(new java.awt.Dimension(522, 257)); - setPreferredSize(new java.awt.Dimension(575, 300)); + setMinimumSize(new java.awt.Dimension(0, 0)); + setPreferredSize(new java.awt.Dimension(625, 450)); modulesScrollPane.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160))); + modulesScrollPane.setMinimumSize(new java.awt.Dimension(0, 0)); modulesScrollPane.setPreferredSize(new java.awt.Dimension(160, 160)); modulesTable.setBackground(new java.awt.Color(240, 240, 240)); @@ -169,12 +175,12 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { jPanel1.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160))); jPanel1.setPreferredSize(new java.awt.Dimension(338, 257)); - advancedButton.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.advancedButton.text")); // NOI18N - advancedButton.setActionCommand(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.advancedButton.actionCommand")); // NOI18N - advancedButton.setEnabled(false); - advancedButton.addActionListener(new java.awt.event.ActionListener() { + globalSettingsButton.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.globalSettingsButton.text")); // NOI18N + globalSettingsButton.setActionCommand(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.globalSettingsButton.actionCommand")); // NOI18N + globalSettingsButton.setEnabled(false); + globalSettingsButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - advancedButtonActionPerformed(evt); + globalSettingsButtonActionPerformed(evt); } }); @@ -183,36 +189,37 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { jScrollPane1.setBorder(null); jScrollPane1.setPreferredSize(new java.awt.Dimension(250, 180)); - simplePanel.setLayout(new javax.swing.BoxLayout(simplePanel, javax.swing.BoxLayout.PAGE_AXIS)); - jScrollPane1.setViewportView(simplePanel); + ingestSettingsPanel.setMinimumSize(new java.awt.Dimension(0, 300)); + ingestSettingsPanel.setLayout(new javax.swing.BoxLayout(ingestSettingsPanel, javax.swing.BoxLayout.PAGE_AXIS)); + jScrollPane1.setViewportView(ingestSettingsPanel); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jSeparator2, javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 203, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(advancedButton))) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 302, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(globalSettingsButton))) .addContainerGap()) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 211, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 330, Short.MAX_VALUE) + .addGap(18, 18, 18) .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(8, 8, 8) + .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(advancedButton)) - .addContainerGap()) + .addComponent(globalSettingsButton) + .addGap(8, 8, 8)) ); jButtonSelectAll.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.jButtonSelectAll.text")); // NOI18N @@ -244,8 +251,8 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 271, Short.MAX_VALUE) .addGap(10, 10, 10)) .addGroup(layout.createSequentialGroup() .addGap(24, 24, 24) @@ -255,8 +262,8 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addComponent(jButtonSelectAll, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(18, 18, 18) .addComponent(jButtonDeselectAll))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 30, Short.MAX_VALUE))) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 310, Short.MAX_VALUE) + .addGap(32, 32, 32))) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 324, Short.MAX_VALUE) .addContainerGap()) ); layout.setVerticalGroup( @@ -264,9 +271,6 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 278, Short.MAX_VALUE) - .addContainerGap()) .addGroup(layout.createSequentialGroup() .addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -274,11 +278,14 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addComponent(jButtonDeselectAll) .addComponent(jButtonSelectAll)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(processUnallocCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addComponent(processUnallocCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 428, Short.MAX_VALUE) + .addContainerGap()))) ); }// //GEN-END:initComponents - private void advancedButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_advancedButtonActionPerformed + private void globalSettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_globalSettingsButtonActionPerformed final AdvancedConfigurationDialog dialog = new AdvancedConfigurationDialog(); dialog.addApplyButtonListener(new ActionListener() { @@ -299,7 +306,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { }); dialog.display(selectedModule.getGlobalSettingsPanel()); - }//GEN-LAST:event_advancedButtonActionPerformed + }//GEN-LAST:event_globalSettingsButtonActionPerformed private void jButtonSelectAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonSelectAllActionPerformed SelectAllModules(true); @@ -321,8 +328,9 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { } // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton advancedButton; private javax.swing.JLabel descriptionLabel; + private javax.swing.JButton globalSettingsButton; + private javax.swing.JPanel ingestSettingsPanel; private javax.swing.JButton jButtonDeselectAll; private javax.swing.JButton jButtonSelectAll; private javax.swing.JPanel jPanel1; @@ -331,7 +339,6 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { private javax.swing.JScrollPane modulesScrollPane; private javax.swing.JTable modulesTable; private javax.swing.JCheckBox processUnallocCheckbox; - private javax.swing.JPanel simplePanel; private javax.swing.ButtonGroup timeGroup; // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index c196caba8a..0e82461c28 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -556,9 +556,9 @@ public class IngestManager { this.jobsById.remove(job.getId()); } for (IngestModuleError error : errors) { - logger.log(Level.SEVERE, String.format("Error starting %s ingest module", error.getModuleDisplayName()), error.getModuleError()); //NON-NLS + logger.log(Level.SEVERE, String.format("Error starting %s ingest module for job %d", error.getModuleDisplayName(), job.getId()), error.getModuleError()); //NON-NLS } - IngestManager.logger.log(Level.INFO, "Ingest job {0} could not be started", job.getId()); //NON-NLS + IngestManager.logger.log(Level.SEVERE, "Ingest job {0} could not be started", job.getId()); //NON-NLS if (RuntimeProperties.coreComponentsAreActive()) { EventQueue.invokeLater(new Runnable() { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java index 26f4fd6a11..0cf8aac221 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java @@ -20,20 +20,25 @@ package org.sleuthkit.autopsy.ingest; import java.awt.BorderLayout; import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; +import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; import org.openide.util.NbBundle; +import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.ingest.IngestJobSettings.IngestType; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Directory; @@ -49,7 +54,6 @@ public final class RunIngestModulesDialog extends JDialog { private static final long serialVersionUID = 1L; private static final String TITLE = NbBundle.getMessage(RunIngestModulesDialog.class, "IngestDialog.title.text"); private final IngestType ingestType; - private static Dimension DIMENSIONS = new Dimension(500, 300); private final List dataSources = new ArrayList<>(); private IngestJobSettingsPanel ingestJobSettingsPanel; @@ -75,7 +79,7 @@ public final class RunIngestModulesDialog extends JDialog { * @param dataSources The data sources to be processed. */ public RunIngestModulesDialog(List dataSources) { - this(new JFrame(TITLE), TITLE, true, dataSources); + this((JFrame) WindowManager.getDefault().getMainWindow(), TITLE, true, dataSources); } /** @@ -98,11 +102,7 @@ public final class RunIngestModulesDialog extends JDialog { /** * Center the dialog. */ - Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); - setSize(DIMENSIONS); - int width = this.getSize().width; - int height = this.getSize().height; - setLocation((screenDimension.width - width) / 2, (screenDimension.height - height) / 2); + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();; /** * Get the default or saved ingest job settings for this context and use @@ -111,7 +111,8 @@ public final class RunIngestModulesDialog extends JDialog { IngestJobSettings ingestJobSettings = new IngestJobSettings(RunIngestModulesDialog.class.getCanonicalName(), this.ingestType); RunIngestModulesDialog.showWarnings(ingestJobSettings); this.ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings); - add(this.ingestJobSettingsPanel, BorderLayout.PAGE_START); + setPreferredSize(this.ingestJobSettingsPanel.getPreferredSize()); + add(this.ingestJobSettingsPanel, BorderLayout.CENTER); // Add a start ingest button. JButton startButton = new JButton(NbBundle.getMessage(this.getClass(), "IngestDialog.startButton.title")); @@ -133,12 +134,13 @@ public final class RunIngestModulesDialog extends JDialog { // Put the buttons in their own panel, under the settings panel. JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS)); - buttonPanel.add(new javax.swing.Box.Filler(new Dimension(10, 10), new Dimension(10, 10), new Dimension(10, 10))); + buttonPanel.setLayout(new FlowLayout(FlowLayout.TRAILING)); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); buttonPanel.add(startButton); - buttonPanel.add(new javax.swing.Box.Filler(new Dimension(10, 10), new Dimension(10, 10), new Dimension(10, 10))); + buttonPanel.add(new javax.swing.Box.Filler(new Dimension(5, 10), new Dimension(5, 10), new Dimension(5, 10))); buttonPanel.add(closeButton); - add(buttonPanel, BorderLayout.LINE_START); + + add(buttonPanel, BorderLayout.SOUTH); /** * Add a handler for when the dialog window is closed directly, @@ -154,8 +156,10 @@ public final class RunIngestModulesDialog extends JDialog { /** * Show the dialog. */ + int width = this.getPreferredSize().width; + int height = this.getPreferredSize().height; + setLocation((screenDimension.width - width) / 2, (screenDimension.height - height) / 2); pack(); - setResizable(false); setVisible(true); } @@ -196,7 +200,7 @@ public final class RunIngestModulesDialog extends JDialog { JOptionPane.showMessageDialog(null, warningMessage.toString()); } } - + /** * Constructs a dialog box that allows a user to configure and execute * analysis of one or more data sources with ingest modules. @@ -236,5 +240,5 @@ public final class RunIngestModulesDialog extends JDialog { this.dataSources.clear(); this.dataSources.addAll(dataSources); } - + } diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.form index 4974e318bd..878f2ca87b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.form @@ -23,7 +23,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.java index 4ecde417ce..a59f445387 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.java @@ -93,7 +93,7 @@ final class FileExtMismatchModuleSettingsPanel extends IngestModuleIngestJobSett .addComponent(skipTextPlain) .addComponent(skipNoExtCheckBox) .addComponent(skipKnownFiles)) - .addGap(0, 138, Short.MAX_VALUE)) + .addGap(0, 10, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java new file mode 100644 index 0000000000..d8cf3a51bd --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java @@ -0,0 +1,58 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2016 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.modules.filetypeid; + +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; + +/** + * Ingest job options for the file type identifier ingest module instances. + * + * @deprecated This class is obsolete (files are no longer skipped for any + * reason by file typing) but it is retained for backwards compatibility because + * it was erroneously made part of the public API and so that old settings files + * can be deserialized successfully (and ignored). + */ +@Deprecated +public class FileTypeIdModuleSettings implements IngestModuleIngestJobSettings { + + private static final long serialVersionUID = 1L; + private boolean skipKnownFiles = true; + private final boolean skipSmallFiles = false; // No longer used. + + FileTypeIdModuleSettings() { + } + + FileTypeIdModuleSettings(boolean skipKnownFiles) { + this.skipKnownFiles = skipKnownFiles; + } + + @Override + public long getVersionNumber() { + return serialVersionUID; + } + + void setSkipKnownFiles(boolean enabled) { + skipKnownFiles = enabled; + } + + boolean skipKnownFiles() { + return skipKnownFiles; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form index 0a88eb5dc8..5fd29f9482 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form @@ -26,7 +26,7 @@ - + @@ -47,15 +47,15 @@ - - - + + + + + - - - - + + @@ -120,9 +120,6 @@ - - - diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java index 32de8e6bf5..00eb729aad 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java @@ -321,7 +321,7 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(knownHashDbsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 272, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)) + .addGap(0, 18, Short.MAX_VALUE)) .addComponent(knownBadHashDbsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addGap(10, 10, 10) @@ -337,14 +337,14 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe .addGap(2, 2, 2) .addComponent(knownHashDbsLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 54, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(knownBadHashDbsLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(alwaysCalcHashesCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 53, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(alwaysCalcHashesCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0)) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java index 14a0d878f8..bf161241b1 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java @@ -23,7 +23,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.logging.Level; import javafx.beans.Observable; @@ -150,11 +149,7 @@ public final class FilteredEventsModel { final ZoomParams zoomParams = requestedZoomParamters.get(); if (zoomParams != null) { - if (zoomParams.getTypeZoomLevel().equals(requestedTypeZoom.get()) == false - || zoomParams.getDescriptionLOD().equals(requestedLOD.get()) == false - || zoomParams.getFilter().equals(requestedFilter.get()) == false - || Objects.equals(zoomParams.getTimeRange(), requestedTimeRange.get()) == false) { - + synchronized (FilteredEventsModel.this) { requestedTypeZoom.set(zoomParams.getTypeZoomLevel()); requestedFilter.set(zoomParams.getFilter()); requestedTimeRange.set(zoomParams.getTimeRange()); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java index dff26b1e61..bd88a6d90b 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014-15 Basis Technology Corp. + * Copyright 2014-16 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,10 +33,7 @@ import javafx.collections.ObservableList; * a {@link CompoundFilter} uses listeners to enforce the following * relationships between it and its sub-filters: *
    - * if a filter becomes active, and all its sub-filters were inactive, make - * them all active - * if a filter becomes inactive and all its sub-filters were active, make - * them all inactive + * if a filter becomes inactive disable all of its subfilters * if a sub-filter changes active state set the parent filter active if any * of its sub-filters are active. *
@@ -93,9 +90,7 @@ public abstract class CompoundFilter extends Abstr for (int i = 0; i < oneFilter.getSubFilters().size(); i++) { final SubFilterType subFilter = oneFilter.getSubFilters().get(i); final SubFilterType otherSubFilter = otherFilter.getSubFilters().get(i); - if (subFilter.equals(otherSubFilter) == false - || subFilter.isDisabled() != otherSubFilter.isDisabled() - || subFilter.isSelected() != otherSubFilter.isSelected()) { + if (subFilter.equals(otherSubFilter) == false) { return false; } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java index 02318310f1..0da318e80d 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-16 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,6 +37,7 @@ public class DataSourcesFilter extends UnionFilter { public DataSourcesFilter copyOf() { final DataSourcesFilter filterCopy = new DataSourcesFilter(); filterCopy.setSelected(isSelected()); + filterCopy.setDisabled(isDisabled()); //add a copy of each subfilter this.getSubFilters().forEach((DataSourceFilter t) -> { filterCopy.addSubFilter(t.copyOf()); @@ -87,7 +88,7 @@ public class DataSourcesFilter extends UnionFilter { } final DataSourcesFilter other = (DataSourcesFilter) obj; - if (isSelected() != other.isSelected()) { + if (isActive() != other.isActive()) { return false; } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java index b7a13184f7..371f32dcdc 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2015-16 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.timeline.filters; @@ -30,6 +43,7 @@ public class HashHitsFilter extends UnionFilter { public HashHitsFilter copyOf() { HashHitsFilter filterCopy = new HashHitsFilter(); filterCopy.setSelected(isSelected()); + filterCopy.setDisabled(isDisabled()); //add a copy of each subfilter this.getSubFilters().forEach((HashSetFilter t) -> { filterCopy.addSubFilter(t.copyOf()); @@ -65,7 +79,7 @@ public class HashHitsFilter extends UnionFilter { } final HashHitsFilter other = (HashHitsFilter) obj; - if (isSelected() != other.isSelected()) { + if (isActive() != other.isActive()) { return false; } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java index 1ab69a3909..4c92a3b02a 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2015-16 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.timeline.filters; @@ -31,6 +44,7 @@ public class TagsFilter extends UnionFilter { public TagsFilter copyOf() { TagsFilter filterCopy = new TagsFilter(); filterCopy.setSelected(isSelected()); + filterCopy.setDisabled(isDisabled()); //add a copy of each subfilter this.getSubFilters().forEach((TagNameFilter t) -> { filterCopy.addSubFilter(t.copyOf()); @@ -66,7 +80,7 @@ public class TagsFilter extends UnionFilter { } final TagsFilter other = (TagsFilter) obj; - if (isSelected() != other.isSelected()) { + if (isActive() != other.isActive()) { return false; } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java index 85a299e5fc..4968e92e80 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-15 Basis Technology Corp. + * Copyright 2013-16 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -126,7 +126,7 @@ public class TypeFilter extends UnionFilter { } final TypeFilter other = (TypeFilter) obj; - if (isSelected() != other.isSelected()) { + if (isActive() != other.isActive()) { return false; } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/UnionFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/UnionFilter.java index 07ef904e75..27bec42c72 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/UnionFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/UnionFilter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014-15 Basis Technology Corp. + * Copyright 2014-16 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java index 0433f99e7e..cdd027472f 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,12 +22,14 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.IOException; +import java.nio.file.Paths; import java.util.logging.FileHandler; import java.util.logging.Level; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.BlackboardResultWriter; @@ -110,33 +112,60 @@ public class KeywordSearch { } /** - * Listener to swap cores when the case changes + * Listener to create/open and close Solr cores when cases are + * created/opened and closed. */ static class CaseChangeListener implements PropertyChangeListener { @Override public void propertyChange(PropertyChangeEvent evt) { + /* + * TODO (AUT-2081): There is a Solr core unloading bug, fixed in + * Solr 5.4, that results in the co-existence of a core.properties + * file and a core.properties.unloaded file in the core instance + * directory when a core is closed/unloaded. When this happens, + * subsequent core open/load attempts will fail. The workaround for + * single-user cases is to close and reopen Autopsy so that a new + * server instance gets spun up. + */ if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) { if (null != evt.getOldValue()) { + /* + * A case is being closed. + */ Case closedCase = (Case) evt.getOldValue(); try { BlackboardResultWriter.stopAllWriters(); - Thread.sleep(2000); // TODO (RC): This is a fragile way to wait here. + /* + * TODO (AUT-2084): The following code + * KeywordSearch.CaseChangeListener gambles that any + * BlackboardResultWriters (SwingWorkers) will complete + * in less than roughly two seconds + */ + Thread.sleep(2000); server.closeCore(); } catch (Exception ex) { - String caseName = closedCase.getName(); - logger.log(Level.SEVERE, String.format("Failed to close core for %s", caseName), ex); //NON-NLS - MessageNotifyUtil.Notify.error(NbBundle.getMessage(KeywordSearch.class, "KeywordSearch.closeCore.notification.msg"), ex.getMessage()); + String caseId = Paths.get(closedCase.getCaseDirectory(), closedCase.getName()).toString(); + logger.log(Level.SEVERE, String.format("Failed to close core for %s", caseId), ex); //NON-NLS + if (RuntimeProperties.coreComponentsAreActive()) { + MessageNotifyUtil.Notify.error(NbBundle.getMessage(KeywordSearch.class, "KeywordSearch.closeCore.notification.msg"), ex.getMessage()); + } } } + if (null != evt.getNewValue()) { + /* + * A case is being created/opened. + */ Case openedCase = (Case) evt.getNewValue(); try { server.openCoreForCase(openedCase); } catch (Exception ex) { - String caseName = openedCase.getName(); - logger.log(Level.SEVERE, String.format("Failed to open or create core for %s", caseName), ex); //NON-NLS - MessageNotifyUtil.Notify.error(NbBundle.getMessage(KeywordSearch.class, "KeywordSearch.openCore.notification.msg"), ex.getMessage()); + String caseId = Paths.get(openedCase.getCaseDirectory(), openedCase.getName()).toString(); + logger.log(Level.SEVERE, String.format("Failed to open or create core for %s", caseId), ex); //NON-NLS + if (RuntimeProperties.coreComponentsAreActive()) { + MessageNotifyUtil.Notify.error(NbBundle.getMessage(KeywordSearch.class, "KeywordSearch.openCore.notification.msg"), ex.getMessage()); + } } } } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java index 312c600d7a..ef7e3ed76b 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -66,14 +66,16 @@ import org.apache.solr.common.SolrException; import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.coreutils.UNCPathUtilities; import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; /** - * Handles for keeping track of a Solr server and its cores + * Handles management of a either a local or centralized Solr server and its + * cores. */ public class Server { - // field names that are used in SOLR schema + /** + * Solr document field names. + */ public static enum Schema { ID { @@ -148,6 +150,7 @@ public class Server { } }, }; + public static final String HL_ANALYZE_CHARS_UNLIMITED = "500000"; //max 1MB in a chunk. use -1 for unlimited, but -1 option may not be supported (not documented) //max content size we can send to Solr public static final long MAX_CONTENT_SIZE = 1L * 1024 * 1024 * 1024; @@ -196,7 +199,7 @@ public class Server { */ Server() { initSettings(); - + this.localSolrServer = new HttpSolrServer("http://localhost:" + currentSolrServerPort + "/solr"); //NON-NLS serverAction = new ServerAction(); solrFolder = InstalledFileLocator.getDefault().locate("solr", Server.class.getPackage().getName(), false); //NON-NLS @@ -204,7 +207,7 @@ public class Server { currentCoreLock = new ReentrantReadWriteLock(true); uncPathUtilities = new UNCPathUtilities(); - + logger.log(Level.INFO, "Created Server instance"); //NON-NLS } @@ -596,11 +599,13 @@ public class Server { * ** Convenience methods for use while we only open one case at a time *** */ /** - * Opens or creates a core (index) for a case. + * Creates/opens a Solr core (index) for a case. * - * @param theCase the case for which the core is to be opened or created. + * @param theCase The case for which the core is to be created/opened. * - * @throws KeywordSearchModuleException + * + * @throws KeywordSearchModuleException If an error occurs while + * creating/opening the core. */ void openCoreForCase(Case theCase) throws KeywordSearchModuleException { currentCoreLock.writeLock().lock(); @@ -630,6 +635,15 @@ public class Server { currentCoreLock.writeLock().lock(); try { if (null != currentCore) { + /* + * TODO (AUT-2081): There is a Solr core unloading bug, fixed in + * Solr 5.4, that will result in the co-existence of a + * core.properties file and a core.properties.unloaded file in + * the core instance directory when the following code executes. + * When this happens, subsequent open/load attempts will fail. + * The workaround for single-user cases is to close and reopen + * Autopsy so that a new server instance gets spun up. + */ currentCore.close(); currentCore = null; serverAction.putValue(CORE_EVT, CORE_EVT_STATES.STOPPED); @@ -655,7 +669,7 @@ public class Server { * * @return absolute path to index dir */ - String getIndexDirPath(Case theCase) { + String geCoreDataDirPath(Case theCase) { String indexDir = theCase.getModuleDirectory() + File.separator + "keywordsearch" + File.separator + "data"; //NON-NLS if (uncPathUtilities != null) { // if we can check for UNC paths, do so, otherwise just return the indexDir @@ -676,11 +690,14 @@ public class Server { * ** end single-case specific methods *** */ /** - * Open a core for the given case + * Creates/opens a Solr core (index) for a case. * - * @param theCase the case to open core for + * @param theCase The case for which the core is to be created/opened. * - * @return + * @return An object representing the created/opened core. + * + * @throws KeywordSearchModuleException If an error occurs while + * creating/opening the core. */ private Core openCore(Case theCase) throws KeywordSearchModuleException { try { @@ -692,11 +709,12 @@ public class Server { currentSolrServer = new HttpSolrServer("http://" + host + ":" + port + "/solr"); //NON-NLS } connectToSolrServer(currentSolrServer); + } catch (SolrServerException | IOException ex) { throw new KeywordSearchModuleException(NbBundle.getMessage(Server.class, "Server.connect.exception.msg"), ex); } - String dataDir = getIndexDirPath(theCase); + String dataDir = geCoreDataDirPath(theCase); String coreName = theCase.getTextIndexName(); return this.openCore(coreName.isEmpty() ? DEFAULT_CORE_NAME : coreName, new File(dataDir), theCase.getCaseType()); } @@ -1050,12 +1068,17 @@ public class Server { } /** - * Open a new core + * Creates/opens a Solr core (index) for a case. * - * @param coreName name to refer to the core by in Solr - * @param dataDir directory to load/store the core data from/to + * @param coreName The core name. + * @param dataDir The data directory for the core. + * @param caseType The type of the case (single-user or multi-user) for + * which the core is being created/opened. * - * @return new core + * @return An object representing the created/opened core. + * + * @throws KeywordSearchModuleException If an error occurs while + * creating/opening the core. */ private Core openCore(String coreName, File dataDir, CaseType caseType) throws KeywordSearchModuleException { @@ -1064,14 +1087,25 @@ public class Server { dataDir.mkdirs(); } - //handle a possible scenario when server process might not be fully started if (!this.isRunning()) { - logger.log(Level.WARNING, "Core open requested, but server not yet running"); //NON-NLS - throw new KeywordSearchModuleException( - NbBundle.getMessage(this.getClass(), "Server.openCore.exception.msg")); + logger.log(Level.SEVERE, "Core create/open requested, but server not yet running"); //NON-NLS + throw new KeywordSearchModuleException(NbBundle.getMessage(this.getClass(), "Server.openCore.exception.msg")); } - if (!coreExistsOnServer(coreName)) { + if (!coreIsLoaded(coreName)) { + /* + * The core either does not exist or it is not loaded. Make a + * request that will cause the core to be created if it does not + * exist or loaded if it already exists. + * + * TODO (AUT-2081): There is a Solr core unloading bug, fixed in + * Solr 5.4, that results in the co-existence of a + * core.properties file and a core.properties.unloaded file in + * the core instance directory when a core is unloaded. When + * this happens, this code will fail. The workaround for + * single-user cases is to close and reopen Autopsy so that a + * new server instance gets spun up. + */ CoreAdminRequest.Create createCoreRequest = new CoreAdminRequest.Create(); createCoreRequest.setDataDir(dataDir.getAbsolutePath()); createCoreRequest.setCoreName(coreName); @@ -1088,8 +1122,7 @@ public class Server { return new Core(coreName, caseType); } catch (SolrServerException | SolrException | IOException ex) { - throw new KeywordSearchModuleException( - NbBundle.getMessage(this.getClass(), "Server.openCore.exception.cantOpen.msg"), ex); + throw new KeywordSearchModuleException(NbBundle.getMessage(this.getClass(), "Server.openCore.exception.cantOpen.msg"), ex); } } @@ -1106,17 +1139,19 @@ public class Server { } /** - * Determines whether or not a Solr core instance exists on the current Solr - * server. + * Determines whether or not a particular Solr core exists and is loaded. * - * @param coreName the name of the core. + * @param coreName The name of the core. * - * @return true or false. + * @return True if the core exists and is loaded, false if the core does not + * exist or is not loaded * - * @throws SolrServerException - * @throws IOException + * @throws SolrServerException If there is a problem communicating with the + * Solr server. + * @throws IOException If there is a problem communicating with the + * Solr server. */ - private boolean coreExistsOnServer(String coreName) throws SolrServerException, IOException { + private boolean coreIsLoaded(String coreName) throws SolrServerException, IOException { CoreAdminResponse response = CoreAdminRequest.getStatus(coreName, currentSolrServer); return response.getCoreStatus(coreName).get("instanceDir") != null; //NON-NLS } diff --git a/NEWS.txt b/NEWS.txt index 2922552cf5..a4aece14bd 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -2,6 +2,7 @@ Improvements: - VMWare virtual machine files (vmdk) and Microsoft Virtual Hard Drives (vhd) can be added as data sources. - New core ingest module detects vmdk and vhd files embedded in other data sources and adds them as data sources. +- Text associated with artifacts posted to the blackboard is indexed and searched for keywords. - Custom (user-defined) blackboard artifact and attribute types displayed in UI and included reports. - File size and MIME type conditions can be specified for interesting files rules. - File size and MIME type conditions can be specified for file search by attributes. diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/SearchEngineURLQueryAnalyzer.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/SearchEngineURLQueryAnalyzer.java index fdd1a018cd..ff45f2efb8 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/SearchEngineURLQueryAnalyzer.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/SearchEngineURLQueryAnalyzer.java @@ -277,8 +277,8 @@ class SearchEngineURLQueryAnalyzer extends Extract { int totalQueries = 0; try { //from blackboard_artifacts - Collection listArtifacts = currentCase.getSleuthkitCase().getMatchingArtifacts("WHERE (artifact_type_id = '" + ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() //NON-NLS - + "' OR artifact_type_id = '" + ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() + "') "); //List of every 'web_history' and 'bookmark' artifact NON-NLS + Collection listArtifacts = currentCase.getSleuthkitCase().getMatchingArtifacts("WHERE (blackboard_artifacts.artifact_type_id = '" + ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() //NON-NLS + + "' OR blackboard_artifacts.artifact_type_id = '" + ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() + "') "); //List of every 'web_history' and 'bookmark' artifact NON-NLS logger.log(Level.INFO, "Processing {0} blackboard artifacts.", listArtifacts.size()); //NON-NLS for (BlackboardArtifact artifact : listArtifacts) { diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index 387cfb83e3..ffe39d6b4b 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Mon, 22 Feb 2016 16:37:47 -0500 +#Wed, 06 Apr 2016 23:58:02 -0400 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index eac00c4b67..aaaa4f0909 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Mon, 22 Feb 2016 16:37:47 -0500 +#Wed, 06 Apr 2016 23:58:02 -0400 CTL_MainWindow_Title=Autopsy 4.1.0 CTL_MainWindow_Title_No_Project=Autopsy 4.1.0 diff --git a/docs/doxygen-user/Doxyfile b/docs/doxygen-user/Doxyfile index 6a2a3f14e8..d86bbf0ac2 100755 --- a/docs/doxygen-user/Doxyfile +++ b/docs/doxygen-user/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy User Documentation" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.0 +PROJECT_NUMBER = 4.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -1025,7 +1025,7 @@ GENERATE_HTML = YES # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_OUTPUT = 4.0 +HTML_OUTPUT = 4.1 # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). diff --git a/docs/doxygen-user/images/extension-mismatch-detected-ingest-settings.PNG b/docs/doxygen-user/images/extension-mismatch-detected-ingest-settings.PNG index 3a40a5c340..fba9b2f45f 100755 Binary files a/docs/doxygen-user/images/extension-mismatch-detected-ingest-settings.PNG and b/docs/doxygen-user/images/extension-mismatch-detected-ingest-settings.PNG differ diff --git a/docs/doxygen-user/images/hash-lookup.PNG b/docs/doxygen-user/images/hash-lookup.PNG index 5f70223b5e..c760ce71cd 100755 Binary files a/docs/doxygen-user/images/hash-lookup.PNG and b/docs/doxygen-user/images/hash-lookup.PNG differ diff --git a/docs/doxygen-user/images/interesting_files_ingest_settings.PNG b/docs/doxygen-user/images/interesting_files_ingest_settings.PNG index 61f78c7e26..b6277a684b 100755 Binary files a/docs/doxygen-user/images/interesting_files_ingest_settings.PNG and b/docs/doxygen-user/images/interesting_files_ingest_settings.PNG differ diff --git a/docs/doxygen-user/images/keyword-search-ingest-settings.PNG b/docs/doxygen-user/images/keyword-search-ingest-settings.PNG index a393e24c8d..dcc7cf6028 100755 Binary files a/docs/doxygen-user/images/keyword-search-ingest-settings.PNG and b/docs/doxygen-user/images/keyword-search-ingest-settings.PNG differ diff --git a/docs/doxygen-user/images/select-ingest-modules.PNG b/docs/doxygen-user/images/select-ingest-modules.PNG index 1f227102b8..1238b14675 100755 Binary files a/docs/doxygen-user/images/select-ingest-modules.PNG and b/docs/doxygen-user/images/select-ingest-modules.PNG differ diff --git a/docs/doxygen-user/main.dox b/docs/doxygen-user/main.dox index a95705d20e..067b672d64 100644 --- a/docs/doxygen-user/main.dox +++ b/docs/doxygen-user/main.dox @@ -4,7 +4,7 @@ Overview ----- -This is the User's Guide for the open source Autopsy platform. Autopsy allows you to examine a hard drive or mobile device and recover evidence from it. This guide should help you with using Autopsy. The developer's guide will help you develop your own Autopsy modules. +This is the User's Guide for the open source Autopsy platform. Autopsy allows you to examine a hard drive or mobile device and recover evidence from it. This guide should help you with using Autopsy. The developer's guide will help you develop your own Autopsy modules. Autopsy 4 (and 3) are a complete rewrite from Autopsy 2, and none of this document is relevant to Autopsy 2. diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 8874eff27f..f6fb7a7038 100755 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.0 +PROJECT_NUMBER = 4.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -1063,7 +1063,7 @@ GENERATE_HTML = YES # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_OUTPUT = api-docs/4.0/ +HTML_OUTPUT = api-docs/4.1/ # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp).